> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stableyard.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> The error shape, every error code and its HTTP status, and which ones are safe to retry.

Errors return a stable machine-readable `code`. Branch on the code, never on the message or on the HTTP status alone, because several codes share a status.

```json theme={null}
{
  "error": {
    "code": "payment_method_not_supported",
    "message": "This payment method is not available for the requested destination."
  }
}
```

Every error response echoes the `Stableyard-Version` header, so a report can be tied to the contract that produced it.

<Warning>
  Some errors return `conflict` at the top level while the specific cause appears in a nested `details.code`. Read the nested code when it is present.
</Warning>

## Request and authentication

| Code | HTTP | Meaning |
| - | - | - |
| `bad_request` | 400 | The request failed validation |
| `unauthorized` | 401 | Missing or invalid credentials |
| `client_token_expired` | 401 | A client session expired. Mint a new one |
| `portal_reauthentication_required` | 401 | The dashboard session needs a fresh sign-in |
| `forbidden` | 403 | The credential is authenticated but not permitted |
| `not_found` | 404 | No such resource in this app environment |
| `rate_limited` | 429 | Too many requests. Back off and retry |

## Accounts and compliance

| Code | HTTP | Meaning |
| - | - | - |
| `account_already_exists` | 409 | That `externalUserId` already has an account |
| `account_subject_unclassified` | 422 | The account predates explicit classification and cannot use this rail |
| `compliance_action_required` | 422 | The customer must complete an identity step first |
| `compliance_action_expired` | 410 | The compliance action link is no longer valid |

## Idempotency and concurrency

| Code | HTTP | Meaning |
| - | - | - |
| `idempotency_conflict` | 409 | The same key was reused with a different body |
| `request_in_progress` | 409 | An identical request is still being processed |
| `invalid_state_transition` | 409 | The resource cannot move to that state from where it is |
| `conflict` | 409 | A generic conflict. Check `details.code` |

## Payments

| Code | HTTP | Meaning |
| - | - | - |
| `payment_not_open` | 409 | The payment is no longer accepting options or funds |
| `payment_method_not_supported` | 422 | Not available for this destination, chain or asset |
| `payment_amount_below_minimum` | 422 | Under the minimum for the selected route |
| `payment_quote_expired` | 409 | The quote timed out. Refresh the option |
| `payment_option_limit_reached` | 429 | Too many options created for one payment |
| `payment_already_detected` | 409 | Funds for this payment were already observed |
| `payment_provider_unavailable` | 503 | The provider for this route is down |
| `payment_provider_error` | 502 | The provider rejected or failed the request |

## Escrow and settlement

| Code | HTTP | Meaning |
| - | - | - |
| `escrow_provisioning_unavailable` | 503 | An escrow could not be provisioned right now |
| `escrow_not_ready` | 409 | The escrow is not yet usable for this operation |
| `escrow_receipt_unverified` | 409 | Funds are not confirmed as received |
| `insufficient_escrow_balance` | 409 | Not enough collected value for this operation |
| `escrow_balance_reserved` | 409 | The balance is reserved by another operation |
| `settlement_profile_required` | 422 | The account has no settlement destination set |
| `settlement_not_ready` | 409 | Settlement has not reached the required state |
| `settlement_already_exists` | 409 | Settlement was already created |

## Refunds

| Code | HTTP | Meaning |
| - | - | - |
| `refund_amount_exceeds_option` | 422 | More than the funded option can return |
| `refund_route_not_supported` | 422 | No return path exists for how this was funded |
| `refund_retry_not_allowed` | 409 | This refund cannot be retried in its current state |

## Infrastructure

| Code | HTTP | Meaning |
| - | - | - |
| `chain_config_missing` | 424 | The chain is not configured in this environment |
| `provider_unavailable` | 503 | A dependency is not operational |
| `provider_failure` | 502 | A dependency returned an error |
| `deposit_webhook_registration_failed` | 502 | A deposit address could not be registered for monitoring |
| `custody_signer_unavailable` | 503 | The signer required for this operation is unavailable |

## Retrying safely

| Situation | Do |
| - | - |
| 429, 502, 503, 504 | Retry with backoff, reusing the **same** `Idempotency-Key` |
| 400, 403, 404, 422 | Do not retry. Fix the request |
| 409 `request_in_progress` | Wait, then read the resource before retrying |
| 409 `idempotency_conflict` | Do not retry. Your key was reused with different input |
| Timeout, no response | Retry with the same key. That is what the key is for |

**Never create a replacement payment to work around a stuck one.** Reuse the original payment and its key. A new payment for the same order is how duplicate payouts happen.

## Next

<CardGroup cols={2}>
  <Card title="Idempotency" icon="fingerprint" href="/idempotency">
    How keys make retries safe.
  </Card>

  <Card title="Status codes" icon="list-check" href="/status-codes">
    Payment, deposit and refund states.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.