---
title: "Errors"
description: "The body of every failed request, the status codes, the error codes you can branch on, and what to do about each."
canonical_url: "https://docs.stablegate.com/docs/guide/getting-started/errors"
---
# Errors

> The body of every failed request, the status codes, the error codes you can branch on, and what to do about each.

Every failed request returns the same JSON body.

```json
{
  "trace_id": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
  "error_code": "devapi_not_found_error",
  "message": "Not Found",
  "details": "The customer does not belong to this partner"
}
```

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      What it is
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        trace_id
      </code>
    </td>
    
    <td>
      Identifier of this request. Keep it: support asks for it first
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        error_code
      </code>
    </td>
    
    <td>
      Machine-readable code, stable across releases. Branch on it
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        message
      </code>
    </td>
    
    <td>
      Short explanation for a human. The wording changes without notice, do not match on it
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        details
      </code>
    </td>
    
    <td>
      Extra context: a string, a list of field errors, or no key at all when there is nothing to add
    </td>
  </tr>
</tbody>
</table>

## Status codes

<table>
<thead>
  <tr>
    <th>
      Status
    </th>
    
    <th>
      Meaning
    </th>
    
    <th>
      What to do
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        400
      </code>
    </td>
    
    <td>
      The request is well-formed, but these values cannot be used
    </td>
    
    <td>
      Read <code>
        message
      </code>
      
       and fix the request
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        401
      </code>
    </td>
    
    <td>
      The API key is missing or unknown
    </td>
    
    <td>
      Send a valid <code>
        X-Api-Key
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        403
      </code>
    </td>
    
    <td>
      The key is valid, the action is not allowed for it
    </td>
    
    <td>
      Do not retry; the action needs a different account
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        404
      </code>
    </td>
    
    <td>
      The object does not exist or belongs to another partner
    </td>
    
    <td>
      Check the UUID against your own customers
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        405
      </code>
    </td>
    
    <td>
      The method is not allowed on this path
    </td>
    
    <td>
      Fix the request
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        409
      </code>
    </td>
    
    <td>
      The object is in a state that does not allow the action
    </td>
    
    <td>
      Read the object, act on its current state
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        422
      </code>
    </td>
    
    <td>
      The body or a header failed validation
    </td>
    
    <td>
      Read <code>
        details
      </code>
      
      ; the list names every invalid field
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        500
      </code>
    </td>
    
    <td>
      A failure on our side
    </td>
    
    <td>
      Retry with backoff; if it repeats, send support the <code>
        trace_id
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        503
      </code>
    </td>
    
    <td>
      The service is temporarily unavailable
    </td>
    
    <td>
      Retry with backoff
    </td>
  </tr>
</tbody>
</table>

## Codes

<table>
<thead>
  <tr>
    <th>
      <code>
        error_code
      </code>
    </th>
    
    <th>
      HTTP
    </th>
    
    <th>
      When
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        devapi_internal_error
      </code>
    </td>
    
    <td>
      <code>
        500
      </code>
    </td>
    
    <td>
      Unexpected failure inside Stablegate
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_request_validation_error
      </code>
    </td>
    
    <td>
      <code>
        422
      </code>
    </td>
    
    <td>
      The body or a header failed validation
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_iban_parse_error
      </code>
    </td>
    
    <td>
      <code>
        400
      </code>
    </td>
    
    <td>
      The IBAN cannot be parsed
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_bank_code_required_error
      </code>
    </td>
    
    <td>
      <code>
        400
      </code>
    </td>
    
    <td>
      The IBAN does not carry a BIC; pass <code>
        bank_code
      </code>
      
       explicitly
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_bad_request_error
      </code>
    </td>
    
    <td>
      <code>
        400
      </code>
    </td>
    
    <td>
      The values contradict each other, for example both <code>
        client_account
      </code>
      
       and <code>
        client_account_uuid
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_email_occupied_error
      </code>
    </td>
    
    <td>
      <code>
        400
      </code>
    </td>
    
    <td>
      The email or username belongs to an existing customer
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_not_found_error
      </code>
    </td>
    
    <td>
      <code>
        404
      </code>
    </td>
    
    <td>
      The object does not exist or is not yours
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_unauthorized_error
      </code>
    </td>
    
    <td>
      <code>
        401
      </code>
    </td>
    
    <td>
      The API key is missing or unknown
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_forbidden_error
      </code>
    </td>
    
    <td>
      <code>
        403
      </code>
    </td>
    
    <td>
      The action is not allowed for this key
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_method_not_allowed_error
      </code>
    </td>
    
    <td>
      <code>
        405
      </code>
    </td>
    
    <td>
      The method is not allowed on this path
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_customer_close_error
      </code>
    </td>
    
    <td>
      <code>
        409
      </code>
    </td>
    
    <td>
      A customer can be closed only in the <code>
        new
      </code>
      
       state with no verification submitted
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_download_aol_error
      </code>
    </td>
    
    <td>
      <code>
        409
      </code>
    </td>
    
    <td>
      The account opening letter is not available in the current state
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_kyc_application_link_error
      </code>
    </td>
    
    <td>
      <code>
        400
      </code>
      
      , <code>
        409
      </code>
    </td>
    
    <td>
      Verification by link is not configured, or the application is in a state that does not allow the action
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_instant_verification_error
      </code>
    </td>
    
    <td>
      <code>
        400
      </code>
      
      , <code>
        409
      </code>
    </td>
    
    <td>
      Instant verification is not configured, not available for this customer type, or the application is in a state that does not allow the action
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_idempotency_invalid_key
      </code>
    </td>
    
    <td>
      <code>
        422
      </code>
    </td>
    
    <td>
      <code>
        Idempotency-Key
      </code>
      
       has non-printable characters or is longer than 255
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_idempotency_key_misuse
      </code>
    </td>
    
    <td>
      <code>
        422
      </code>
    </td>
    
    <td>
      The key was already used with a different body or path
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_idempotency_request_in_progress
      </code>
    </td>
    
    <td>
      <code>
        409
      </code>
    </td>
    
    <td>
      A request with this key is still running; retry when it finishes
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        devapi_service_unavailable_error
      </code>
    </td>
    
    <td>
      <code>
        503
      </code>
    </td>
    
    <td>
      A service Stablegate depends on is down
    </td>
  </tr>
</tbody>
</table>

## Validation errors

A `422` lists every invalid field in `details`:

```json
{
  "trace_id": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
  "error_code": "devapi_request_validation_error",
  "message": "Unprocessable Entity",
  "details": [
    {
      "loc": ["body", "source", "amount"],
      "msg": "Input should be a valid decimal",
      "type": "decimal_parsing"
    },
    {
      "loc": ["body", "destination", "client_account_uuid"],
      "msg": "Field required",
      "type": "missing"
    }
  ]
}
```

`loc` is the path to the field: the first item is where the value came from (`body`, `query`, `header`), the rest is the path inside it.

## Codes raised by other services

Requests that touch orders, limits, accounts, customers or verification go through internal services, and their codes reach you through the Partner API: `oa_` for operations, `ca_` for customers. An example is `oa_limit_exceeded_error`, which `check-limits` and order creation return when a rule is broken, with the reason in `details`.

Treat these codes as opaque. Log the code and the `trace_id`, show the customer `message`, and send both to support when the problem needs us.

## Retries

- Retry `500`, `503` and timeouts with exponential backoff. Three attempts is enough for an interactive flow; a background job can keep going longer.
- Send the same `Idempotency-Key` on every retry of the same request: a repeated create returns the first result instead of a second order. A retry with a different body answers `422` with `devapi_idempotency_key_misuse`.
- Do not retry `400`, `401`, `403`, `404` and `422` unchanged: the same request fails the same way.
- `409` may go away when the object changes state, so re-read the object before you decide.
- There is no rate limit today. If one appears, it will answer `429` with `Retry-After`.

## The request id header

Every response carries `X-Request-Id`. Send your own value in the request header and Stablegate returns it unchanged; without it the platform generates one. The `trace_id` of an error body is the same value, so the header alone identifies the call even when the body never reaches you — for example a gateway timeout.

```bash
curl https://api.stablegate.com/v1/customers/ \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Request-Id: order-c1d2e3f4-42"
```

## Before you contact support

Send the `trace_id`, the method and path of the request, and the time with the time zone. The `trace_id` finds the request in our logs, everything else narrows the search.


## Sitemap

See the full [sitemap](https://docs.stablegate.com/sitemap.md) for all pages.
