Skip to content

Error codes ​

Failed requests return an HTTP status between 400 and 599 and a JSON body with a code and a human-readable error and/or message:

json
{
  "error": "amount should at least be 10.00",
  "code": "unknown_error",
  "message": "amount should at least be 10.00"
}

Branch on the HTTP status first, then on code. Many request errors share the generic code unknown_error and are distinguished by HTTP status. The error / message text is for logs and humans and may change.

By HTTP status ​

HTTPMeaning
400Malformed request, amount outside limits, or a signature field is malformed
401Authentication failed — bad credentials, access token or signature (see below)
403IP address not allowlisted, bank not supported, or refresh token already used
404Refresh token not recognised
409Duplicate invoice_no (deposits)
422A payload field failed validation
500Server error; for withdrawals also insufficient balance or duplicate invoice_no
503Deposits or withdrawals are temporarily unavailable — retry later

Codes ​

CodeHTTPDescription
unknown_error400, 409, 422, 500, 503Generic request error — see the HTTP status and message
server_error500Server error
FAILED401Access token missing, invalid, expired or superseded — get a new token
credential.invalid_username_or_password401Wrong email or password
credential.invalid_token404Refresh token not recognised
credential.token_blocked403Refresh token already used or revoked

Signature errors ​

Returned by signed endpoints when the request signature can't be verified. Body: {"error": "…", "code": "signature.…"}.

HTTPCodeWhat to check
400signature.body.emptyRequest body is empty
400signature.body.invalid_jsonBody must be JSON: {"data": "…"}
400signature.data.missingThe data field is missing or empty
400signature.data.invalid_base64data must be standard base64 (with padding)
400signature.timestamp.missingSend the X-Timestamp header
400signature.timestamp.invalidX-Timestamp must be Unix seconds as an integer
401signature.timestamp.expiredTimestamp is > 60 s old — check your clock (NTP)
401signature.timestamp.futureTimestamp is > 5 s in the future — check your clock (NTP)
400signature.nonce.missingSend the X-Nonce header
400signature.nonce.invalidNonce must be 16–64 chars of [A-Za-z0-9_-]
401signature.nonce.replayedNonce already used — generate a fresh one per request, including retries
401signature.header.missingSend the X-Signature header
401signature.header.invalid_base64X-Signature must be standard base64
401signature.vendor.unresolvedCouldn't identify your account from the access token
401signature.public_key.missingWe don't have your public key yet — contact your account manager
401signature.verify.failedSigning string mismatch or wrong key — see the checklist below
500signature.nonce.store_failedTemporary server error — retry with a new nonce

Debugging signature.verify.failed ​

  1. URL — are you signing the exact URL you POST to, for the right environment? (rules)
  2. Data — is the signed data byte-for-byte the same string you put in the body? Don't re-serialise between signing and sending.
  3. Separators — five parts joined by single . characters, no spaces or newlines.
  4. Algorithm — RSA PKCS#1 v1.5 with SHA-256 (not PSS), signature standard-base64 encoded.
  5. Key — is the private key the pair of the public key you sent us, for this environment?

Need help? Contact your DMC Pay account manager.