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

# Errors

> HTTP error codes returned by the DecimalAI API and how to handle them.

The DecimalAI API uses standard HTTP status codes and returns structured JSON error bodies.

## Error response shape

```json theme={null}
{
  "detail": "Skill 'search-flights' not found"
}
```

For validation errors raised by Pydantic, `detail` stays a string and the per-field errors are attached under `details.errors`:

```json theme={null}
{
  "detail": "Request validation failed",
  "code": "validation_error",
  "request_id": "2a47c3a3-724",
  "details": {
    "errors": [
      {
        "field": "body.agent_name",
        "message": "Field required"
      }
    ]
  }
}
```

## Status codes

| Code    | Meaning               | Common causes                                                                                                                                      | What to do                                                                                                                                                       |
| ------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **200** | OK                    | Request succeeded.                                                                                                                                 | Use the response body.                                                                                                                                           |
| **201** | Created               | Resource created (skill, dataset, API key).                                                                                                        | Persist the returned ID.                                                                                                                                         |
| **400** | Bad Request           | Missing field, malformed JSON, invalid enum value, or webhook signature mismatch.                                                                  | Check the `detail` for the failing field; fix the request body and retry.                                                                                        |
| **401** | Unauthorized          | Missing or invalid API key, expired Clerk session, or webhook signature header missing.                                                            | Re-issue the API key from [Settings → API keys](https://app.decimal.ai/settings/api-keys). Confirm the header is `Authorization: Bearer dai_sk_...`.             |
| **402** | Payment Required      | Plan quota exhausted (traces ingested, SFT rows, or other metered resource).                                                                       | Upgrade the plan in [Settings → Billing](https://app.decimal.ai/settings/billing), or wait for the next billing period. The `detail` names the exhausted metric. |
| **403** | Forbidden             | Your role lacks permission for this action, or you're attempting to access a workspace you don't belong to.                                        | Ask a workspace admin to grant the required role, or scope the action to a workspace you have access to.                                                         |
| **404** | Not Found             | The named resource (trace ID, skill name, manifest ID, dataset version) doesn't exist or has been deleted.                                         | Check the resource ID; verify it exists with a `list` call.                                                                                                      |
| **409** | Conflict              | Idempotency conflict — e.g., installing a registry skill that's already installed, or syncing a skill whose body hash matches an existing version. | This is usually safe to ignore. The conflicting resource is returned in `detail`.                                                                                |
| **422** | Unprocessable Entity  | Request validation failed (Pydantic).                                                                                                              | The `details.errors` array lists each invalid field.                                                                                                             |
| **429** | Too Many Requests     | Rate limit exceeded for your plan tier.                                                                                                            | Honor the `Retry-After` response header and back off. See the [Tracing guide](/guides/tracing) for batch ingest patterns that reduce request count.              |
| **500** | Internal Server Error | Unhandled exception on the backend.                                                                                                                | Retry with backoff; if persistent, file a support request with the response `X-Request-ID` header.                                                               |
| **501** | Not Implemented       | Feature is gated, deprecated, or not enabled on your plan.                                                                                         | Check the [Pricing page](/pricing) for plan availability.                                                                                                        |
| **503** | Service Unavailable   | Backend overloaded or in maintenance.                                                                                                              | Retry with backoff; if persistent, email [hello@decimal.ai](mailto:hello@decimal.ai) with your `X-Request-ID`.                                                   |

## Idempotency

Several endpoints are idempotent by design:

* `POST /api/v1/manifests` — same `manifest_hash` returns the existing `manifest_id` with `"is_new": false` and `"action": "deduped"`.
* `POST /api/v1/skills/sync` — returns per-batch counts, `{"status": "ok", "created": 2, "updated": 1, "unchanged": 5}`; unchanged skills fall into `unchanged`, changes auto-create a new version.
* `POST /api/v1/traces` — duplicate `trace_id` returns the existing trace.

Re-running these is safe and will not double-count toward your quota.

## Rate limits

Rate limits are applied per API key, using one token bucket that covers the whole API surface — there is no separate ingest budget. The bucket is sized from the key's organization plan:

| Plan       | RPM    | Burst |
| ---------- | ------ | ----- |
| Free       | 60     | 10    |
| Core       | 120    | 20    |
| Pro        | 300    | 50    |
| Enterprise | 1,000+ | 200+  |

When you hit a limit, responses include:

```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 12
```

The SDK respects `Retry-After` automatically. If you're calling the API directly, sleep for the indicated number of seconds before retrying.

## Reporting an issue

For 5xx errors or unexpected behavior, include the `X-Request-ID` response header when filing a support ticket — it lets us look up the failing request in logs.
