URL: /api/errors

---
title: Errors
description: HTTP status codes and error body shape.
---

Errors carry an HTTP status code and a JSON body.

```json
{
  "detail": "Domain is locked at the registry",
  "code": "DOMAIN_LOCKED"
}
```

`detail` is human-readable. `code` is a stable machine token; new codes can appear, existing ones don't change meaning.

## Status codes

| Code | When |
| --- | --- |
| 200 | OK |
| 201 | Resource created |
| 202 | Action accepted, work happens async (registration, transfer) |
| 204 | No content (delete) |
| 400 | Invalid input. Body has field-level detail under `detail` (FastAPI shape). |
| 401 | Missing or bad token |
| 402 | Payment required — balance too low for the action |
| 403 | Token valid but lacks scope or org access |
| 404 | Resource not found, or you don't have access (we don't leak existence) |
| 409 | Conflict — duplicate, version mismatch, or domain in incompatible state |
| 422 | Schema validation failed (FastAPI default) |
| 429 | Rate-limited — back off |
| 500 | Server bug. Always reportable. |
| 502 / 503 | Upstream registrar or DNS provider unavailable. Safe to retry with backoff. |

## Validation errors

FastAPI returns 422 with a list of field errors:

```json
{
  "detail": [
    {
      "loc": ["body", "tld"],
      "msg": "TLD must be lowercase",
      "type": "value_error"
    }
  ]
}
```

## Idempotency

State-changing endpoints accept an `Idempotency-Key` header. Sending the same key with the same body within 24 hours returns the cached response — safe to retry network failures without double-charging.

```bash
curl -X POST .../v1/orgs/org_x/domains/example.com/renew \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Authorization: Bearer dg_live_..."
```

A duplicate key with a different body returns HTTP 409.
