Errors
Every failure the SDK reports answers one question first: did the request reach the platform? The answer decides whether you may mark the order failed or must query before deciding. Payouts move money, so getting this wrong creates duplicate payouts or orders stuck forever.
Error types
| Meaning | Go | JavaScript | Python | PHP | Java |
|---|---|---|---|---|---|
| Client configuration invalid | error from NewClient | ConfigError | ConfigError | ConfigException | DeepaymentException.Config |
| Rejected before sending | errors.Is(err, ErrInvalidRequest) | RequestError | RequestError | RequestException | DeepaymentException.Request |
| No usable response | errors.Is(err, ErrTransport) | TransportError | TransportError | TransportException | DeepaymentException.Transport |
| Business error in envelope | *APIError | APIError | APIError | ApiException | DeepaymentException.Api |
| Non-envelope response | *ResponseError | ResponseError | ResponseError | ResponseException | DeepaymentException.Response |
| Response over size limit | errors.Is(err, ErrResponseTooLarge) | ResponseTooLargeError | ResponseTooLargeError | ResponseTooLargeException | DeepaymentException.ResponseTooLarge |
| Webhook verification failed | error from VerifyWebhook / Parse* | WebhookError | WebhookError | WebhookException | DeepaymentException.Webhook |
All non-Go types derive from one base (SDKError, SdkException, DeepaymentException), so a single catch covers everything the SDK raises.
Triage
| Error | What happened | Do |
|---|---|---|
| Rejected before sending | Local validation failed, a parameter was bad, or the request could not be encoded or signed. Nothing was sent. | Safe to mark failed. Fix the request and retry under the same merchantOrderNo. |
| No usable response | Connection failure, timeout, interrupted read. The request may have arrived. | Outcome unknown. Never mark a payout failed. Query by merchantOrderNo, or resend the identical request under the same number. |
| Business error | The platform answered with a well-formed error envelope. | Branch on msg, see below. |
| Non-envelope response | Gateway or CDN returned HTML or plain text (a 502 page, for example). | Outcome unknown. Query before deciding. |
| Response over size limit | A response arrived but was discarded. | Outcome unknown; the order was most likely created. Query before deciding. |
| Anything else | Unexpected. | Assume the request may have arrived. Query before deciding. |
Business error fields
| Field | Go | JS | Python | PHP | Java |
|---|---|---|---|---|---|
| HTTP status | HTTPStatus | httpStatus | http_status | $e->httpStatus | httpStatus |
| Numeric code | Code | code | code | $e->getCode() | code |
Machine-readable msg | Msg | msg | msg | $e->msg | msg |
| Human-readable message | Message | apiMessage | message | $e->apiMessage | apiMessage |
| Trace id | TraceID | traceId | trace_id | $e->traceId | traceId |
| Raw body | RawBody | rawBody | raw_body | $e->rawBody | rawBody |
Log the trace id with every failure; support uses it to find the request. Constants for msg are exported in every language (Go MsgOrderNotFound, JS MSG.ORDER_NOT_FOUND, Python MSG_ORDER_NOT_FOUND); PHP and Java compare against the string.
Acting on msg
The full code table with HTTP statuses is in Error Codes. The cases that need a specific reaction:
msg | Do |
|---|---|
INVALID_FIELD | A format the SDK does not check failed at the gateway. Fix the field; the same merchantOrderNo can be reused. |
UNAUTHORIZED | Check the server clock, the access key, and that the registered public key matches your private key. |
IDEMPOTENCY_CONFLICT | The number is taken but the platform could not return its order. Query that number and keep querying; do not switch numbers. |
CHANNEL_ERROR | The order may already exist. Query by merchantOrderNo first; reuse the number only once the query returns ORDER_NOT_FOUND. |
CHANNEL_BUSY | Refused before the order was created. Resend the same number after a back-off; the only channel error that needs no query first. |
ORDER_REJECTED | Risk control or a business rule. Do not retry the same request. |
INSUFFICIENT_BALANCE | Top up, then create a new payout. |
RATE_LIMITED | Back off and retry the same request. |
SERVICE_UNAVAILABLE, INTERNAL_ERROR | Treat as outcome unknown for writes: query before resending. |
Merchant order number is the safety net
Everything above rests on one property: a second create with the same merchantOrderNo never creates a second order. Generate the number before the first attempt, persist it, and reuse it for every query and resend until the order reaches a final state. Only allocate a new number for a genuinely new order.