Skip to main content

Why requests are signed

  • Your secret never leaves your servers. A leaked request or log line cannot be used to make other requests.
  • Requests cannot be altered in transit. Changing the amount, the investment or the path invalidates the signature.
  • Captured requests expire. The timestamp must be within 5 minutes of server time, and Idempotency-Key makes a replayed POST harmless.
A signature is valid for one request only, so sign each request just before sending it. The API playground on this site cannot sign requests; test with your own code.

Headers

Building the signature

Sign the exact bytes you send. Serialise the JSON once, hash those bytes, send those bytes. Do not let your HTTP client re-serialise the body after you signed it.
Rules that trip people up:
  • The path includes the query string and excludes the host: /partner/v1/orders?status=completed&limit=20.
  • METHOD is upper-case.
  • The signature is lower-case hex, 128 characters.
  • Keep your clock on NTP; a drift over 5 minutes fails every request.

Worked example

Check your implementation byte for byte against these fixed inputs:
The canonical string is the four parts joined with real newlines. The resulting header values are printed on the live reference page at https://api.myladder.africa/partner/docs/ under “Worked example”, computed by the same code the server verifies with.

Code

Document uploads

POST /kyb/documents is multipart/form-data. Build the multipart body first, sign those exact bytes, and send them unchanged with the matching Content-Type boundary. Most HTTP clients generate the multipart body as they send, which breaks the signature, so build it yourself (for example requests_toolbelt.MultipartEncoder(...).to_string() in Python).

Troubleshooting

The response message says which of these it was; branch on code, read message when debugging.