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.

JSON
{
  "error": {
    "code": "FORBIDDEN",
    "message": "Access denied"
  },
  "meta": { "requestId": "req_..." }
}
  • code is stable: branch on it, not on message, which is for people and can change.
  • details, when present, says more, such as which field failed validation.
  • meta.requestId identifies the request. Quote it when you report a problem.

Statuses

StatusMeansCommon codes
400The request is malformed or fails validation.BAD_REQUEST, IDEMPOTENCY_KEY_REQUIRED
401The API key is missing, invalid, expired, or revoked.UNAUTHORIZED, INVALID_API_KEY, EXPIRED_API_KEY, REVOKED_API_KEY
403The 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
404Nothing with that ID exists in the project.NOT_FOUND
409The 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
413The request body is larger than 1 MB.PAYLOAD_TOO_LARGE
422The 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
429Too many requests. See Rate limits.RATE_LIMITED
500Something failed inside SDP.INTERNAL_ERROR
502Solana 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
503SDP, 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, and 422: 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.
  • 409 answering a stale expectedUpdatedAt (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 new updatedAt and a new key.
  • 409 IDEMPOTENCY_KEY_IN_FLIGHT and 429: wait for Retry-After, then retry with the same Idempotency-Key.
  • 409 IDEMPOTENCY_KEY_OUTCOME_UNKNOWN: final for that key. Read the resource with GET to see whether the request ran, then send it again with a new key.
  • 503 RPC_UNAVAILABLE: details.reason says why Solana RPC was unavailable. upstream_unavailable is temporary: wait for Retry-After, then retry as the 5xx rule below says. not_configured and cluster_mismatch are SDP configuration problems that a retry won't fix. Quote meta.requestId when 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 quote meta.requestId when you report it.
  • 5xx: most routes store the error and return it again to a same-key retry. Read the resource with GET to 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.