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

# Error reference

> RFC 7807 problem detail format, status-code catalog, and troubleshooting recipes.

All Integration API errors follow **RFC 7807 Problem Details**
(`application/problem+json`). A single schema covers every failure mode —
auth, validation, concurrency, rate-limiting, server errors.

## Problem shape

```json theme={null}
{
  "type": "https://api.novatrade24.com/problems/validation-error",
  "title": "Validation Error",
  "status": 422,
  "detail": "Field 'vatNumber' must match pattern ^[A-Z]{2}[0-9A-Z]+$",
  "instance": "/v1/partners/xxx/buyers",
  "traceId": "req_a1b2c3d4",
  "errors": [
    {
      "field": "vatNumber",
      "message": "must match pattern ^[A-Z]{2}[0-9A-Z]+$",
      "rejectedValue": "invalid"
    }
  ]
}
```

| Field      | Type       | Notes                                                                                |
| ---------- | ---------- | ------------------------------------------------------------------------------------ |
| `type`     | URI string | Stable identifier for the error category. Keyed on this, not on `status` or `title`. |
| `title`    | string     | Human-readable summary. Safe to display.                                             |
| `status`   | integer    | HTTP status code, duplicated for convenience.                                        |
| `detail`   | string     | Human-readable specifics of this particular occurrence.                              |
| `instance` | string     | Request path.                                                                        |
| `traceId`  | string     | Correlation id. Include in support requests.                                         |
| `errors[]` | array      | **Validation-error only** — per-field breakdown.                                     |

**Always key on `type`**, not on `status` or `title`. We may add new
problem types over time; we will not change existing ones without a version
bump.

## Status-code catalog

| Status | Meaning                                                                          | Typical `type` URIs                                                                                            |
| ------ | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `400`  | Malformed request                                                                | `…/problems/malformed-request`                                                                                 |
| `401`  | Missing or invalid token                                                         | `…/problems/unauthorized`                                                                                      |
| `403`  | Authenticated but not authorized (partner scope, capability, DPA)                | `…/problems/forbidden`, `…/problems/capability-required`, `…/problems/dpa-not-accepted`                        |
| `404`  | Resource not found                                                               | `…/problems/not-found`                                                                                         |
| `409`  | State conflict (If-Match mismatch, natural-key collision, milestone already set) | `…/problems/version-mismatch`, `…/problems/resource-exists-different-body`, `…/problems/milestone-already-set` |
| `422`  | Validation failed or idempotency key reused with different body                  | `…/problems/validation-error`, `…/problems/idempotency-key-reused`                                             |
| `429`  | Rate limit exceeded                                                              | `…/problems/rate-limited`                                                                                      |
| `500`  | Unexpected server error                                                          | `…/problems/internal-error`                                                                                    |

## Handling examples

<CodeGroup>
  ```typescript TypeScript theme={null}
  async function call(url: string, init: RequestInit) {
    const res = await fetch(url, init);
    if (res.ok) return res.json();

    const problem = await res.json();
    switch (problem.type) {
      case 'https://api.novatrade24.com/problems/version-mismatch':
        // Refetch and retry with new ETag.
        throw new VersionMismatch(problem);

      case 'https://api.novatrade24.com/problems/rate-limited':
        const retryAfter = parseInt(res.headers.get('Retry-After') ?? '1', 10);
        await new Promise((r) => setTimeout(r, retryAfter * 1000));
        return call(url, init);

      case 'https://api.novatrade24.com/problems/dpa-not-accepted':
        alertOps('Novatrade24 DPA needs re-acceptance', problem);
        throw new DpaStale(problem);

      default:
        throw new ApiError(res.status, problem);
    }
  }
  ```

  ```python Python theme={null}
  def call(session, method, url, **kw):
      r = session.request(method, url, **kw)
      if r.ok:
          return r.json()
      problem = r.json()
      t = problem.get("type", "")
      if t.endswith("/rate-limited"):
          time.sleep(int(r.headers.get("Retry-After", "1")))
          return call(session, method, url, **kw)
      if t.endswith("/version-mismatch"):
          raise VersionMismatch(problem)
      if t.endswith("/dpa-not-accepted"):
          raise DpaStale(problem)
      raise ApiError(r.status_code, problem)
  ```
</CodeGroup>

## Validation errors (`422`)

Body includes an `errors[]` array with per-field detail:

```json theme={null}
{
  "type": "https://api.novatrade24.com/problems/validation-error",
  "title": "Validation Error",
  "status": 422,
  "detail": "Request body failed validation. See errors[].",
  "instance": "/v1/partners/.../buyers",
  "traceId": "req_a1b2c3d4",
  "errors": [
    {
      "field": "vatNumber",
      "message": "must match pattern ^[A-Z]{2}[0-9A-Z]+$",
      "rejectedValue": "invalid"
    },
    {
      "field": "address.country",
      "message": "must be a 2-letter ISO-3166-1 alpha-2 code",
      "rejectedValue": "ger"
    }
  ]
}
```

Show the per-field messages in your UI; root-level `detail` is a summary.

## Concurrency conflicts (`409` with version mismatch)

When a `PATCH` carries an `If-Match` header that doesn't match the current
entity version, NT24 returns `409` with the **full current resource body**
— you don't need a separate GET to reconcile.

```json theme={null}
{
  "type": "https://api.novatrade24.com/problems/version-mismatch",
  "title": "Version Mismatch",
  "status": 409,
  "detail": "If-Match version 3 does not match current version 5.",
  "instance": "/v1/partners/.../orders/...",
  "traceId": "req_...",
  "currentResource": {
    "uuid": "...",
    "version": 5,
    "...": "..."
  }
}
```

Merge locally and retry with the new `ETag`.

## Idempotency key reuse (`422`)

If you reuse an `Idempotency-Key` within the 24-hour window with a
**different body**, NT24 rejects with `422`:

```json theme={null}
{
  "type": "https://api.novatrade24.com/problems/idempotency-key-reused",
  "title": "Idempotency Key Reused With Different Body",
  "status": 422,
  "detail": "Key 'abc-123' was first used for a different request. Use a new key.",
  "instance": "/v1/partners/.../buyers",
  "traceId": "req_..."
}
```

Generate fresh UUIDs for each logically-distinct request.

## Rate limiting (`429`)

```json theme={null}
{
  "type": "https://api.novatrade24.com/problems/rate-limited",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "60 requests per minute for write category exceeded.",
  "instance": "/v1/partners/.../orders",
  "traceId": "req_..."
}
```

Response headers carry the budget state — honor `Retry-After`:

```
Retry-After: 37
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1729684260
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="403 but `/me` succeeds">
    Your token is valid, but the specific partner in the URL path isn't in
    your authorized partners list — OR a capability required for the
    endpoint (e.g. `allowMarketplaceLedKyc`) is `false` on your org. Check
    `GET /v1/me`.
  </Accordion>

  <Accordion title="409 on POST that was supposed to be idempotent">
    The resource exists already with a **different body** than what you're
    sending. Either re-send the exact original body, or switch to `PATCH` to
    update fields explicitly. Safe retries require both the same
    `Idempotency-Key` AND the same body.
  </Accordion>

  <Accordion title="422 with no errors[] array">
    Non-validation 422 — most commonly idempotency-key reuse with different
    body. Check `type`.
  </Accordion>

  <Accordion title="Intermittent 500 errors">
    Capture `traceId` from the response body and include it when reaching
    [our contact page](https://www.novatrade24.com/contact).
    We correlate logs by trace id.
  </Accordion>
</AccordionGroup>

## Next

<CardGroup cols={2}>
  <Card title="Rate limits" icon="gauge-high" href="/concepts/rate-limits">
    Tier breakdowns and burst behavior.
  </Card>

  <Card title="Idempotency" icon="arrows-rotate" href="/concepts/idempotency">
    Key format, TTL, replay semantics.
  </Card>
</CardGroup>
