Errors
A failed request returns an HTTP error status and one error envelope, with a code to branch on.
A failed request returns an error status and this body. The health checks are the exception: each answers with its own body, as its page shows.
codeis stable: branch on it, not onmessage, which is for people and can change.details, when present, says more, such as which field failed validation.meta.requestIdidentifies the request. Quote it when you report a problem.
Statuses
| Status | Means | Common codes |
|---|---|---|
400 | The request is malformed or fails validation. | BAD_REQUEST, IDEMPOTENCY_KEY_REQUIRED |
401 | The API key is missing, invalid, expired, or revoked. | UNAUTHORIZED, INVALID_API_KEY, EXPIRED_API_KEY, REVOKED_API_KEY |
403 | The key lacks the grant or wallet access the request needs, or the call comes from an IP address the key or its organization doesn't allow (details.reason is ip_not_allowed). | FORBIDDEN, INSUFFICIENT_PERMISSIONS |
404 | Nothing with that ID exists in the project. | NOT_FOUND |
409 | The request conflicts with the resource's state, or an earlier request with the same idempotency key is still running or never recorded its outcome. | CONFLICT, IDEMPOTENCY_KEY_IN_FLIGHT, IDEMPOTENCY_KEY_OUTCOME_UNKNOWN |
413 | The request body is larger than 1 MB. | PAYLOAD_TOO_LARGE |
422 | The request is well formed but can't go ahead: its idempotency key was used for a different request, the transaction fee sponsor rejected the transaction, or the wallet's policy at its custody provider refused to sign it. | IDEMPOTENCY_KEY_REUSED, SIGNING_REJECTED, CUSTODY_POLICY_REFUSED |
429 | Too many requests. See Rate limits. | RATE_LIMITED |
500 | Something failed inside SDP. | INTERNAL_ERROR |
502 | Solana RPC or a provider answered, but with something SDP couldn't use, or the custody provider failed or timed out while signing. | SOLANA_RPC_ERROR, PROVIDER_RESPONSE_INVALID, CUSTODY_ERROR |
503 | SDP, or a provider it depends on, is unavailable for now, or a provider isn't configured for the project's environment. | SERVICE_UNAVAILABLE, PROVIDER_UNAVAILABLE, PROVIDER_NOT_CONFIGURED, RPC_UNAVAILABLE |
Each operation's page lists its statuses and shows a success example. The OpenAPI spec carries every response schema.
Preconditions
A write that should apply only to the version you last read takes an optional expectedUpdatedAt field in its request body: the updatedAt from your last read of the resource. When the resource has changed since, the write changes nothing and returns 409, carrying the current updatedAt in error.details. The operation's page says whether it takes the field, and names the code it returns. Omit it to write whatever the current version is.
The field is part of the body, so it is part of what an Idempotency-Key identifies: a retry under the same key must send the same value.
Retrying
400,401,403,404,413, and422: fix the request before you send it again.422 CUSTODY_POLICY_REFUSED: the wallet's policy at its custody provider refused to sign. The message names the provider. Review the policy there, or change the request, before you send it again.409 CONFLICT: read the resource's current state, then decide.409answering a staleexpectedUpdatedAt(the code its operation's page names): the resource changed since the version you sent. Read it again, review what changed, then send the write with the newupdatedAtand a new key.409 IDEMPOTENCY_KEY_IN_FLIGHTand429: wait forRetry-After, then retry with the sameIdempotency-Key.409 IDEMPOTENCY_KEY_OUTCOME_UNKNOWN: final for that key. Read the resource withGETto see whether the request ran, then send it again with a new key.503 RPC_UNAVAILABLE:details.reasonsays why Solana RPC was unavailable.upstream_unavailableis temporary: wait forRetry-After, then retry as the5xxrule below says.not_configuredandcluster_mismatchare SDP configuration problems that a retry won't fix. Quotemeta.requestIdwhen you report one.503 PROVIDER_NOT_CONFIGURED: a provider the request needs, such as the custody provider that signs for the wallet, isn't configured for the project's environment. A retry won't fix it until that changes. Check the provider's configuration, or quotemeta.requestIdwhen you report it.5xx: most routes store the error and return it again to a same-key retry. Read the resource withGETto see whether the request took effect, then retry with a new key. On the routes that move money, a same-key retry runs again and never acts twice.
Idempotency covers what each retry returns.