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

# Errors & retries

> Every response code, and which ones to retry.

## Status codes

| Status | Meaning                                        | Retry?                        |
| ------ | ---------------------------------------------- | ----------------------------- |
| `202`  | Accepted — `{ accepted, duplicates }`          | —                             |
| `400`  | Invalid envelope or batch. Nothing was stored. | **No** — fix the request      |
| `401`  | Missing or invalid bearer token                | **No** — fix the token        |
| `429`  | Rate limit exceeded                            | **Yes** — back off and retry  |
| `503`  | Temporarily unavailable (e.g. a database blip) | **Yes** — honor `Retry-After` |
| `500`  | Unexpected server error                        | **Yes** — retry with backoff  |

<Note>
  **Retryable vs. permanent.** `400` and `401` won't change on retry — fix the envelope or
  the token. `429`, `503`, and `500` are transient — retry with exponential backoff. On a
  `503`, Pulse sends a `Retry-After` header (in seconds) and never leaks an internal error.
</Note>

## Validation errors (`400`)

A single invalid event returns the failing fields:

```json theme={null}
{
  "error": "invalid event envelope",
  "details": [
    { "path": "confidence", "message": "Number must be less than or equal to 1" }
  ]
}
```

### Batches are all-or-nothing

If any event in an array is invalid, the **entire batch is rejected and nothing is
stored** — the response points at the offending elements by index:

```json theme={null}
{
  "error": "invalid batch — rejected atomically, nothing was stored",
  "invalid": [
    {
      "index": 1,
      "issues": [
        { "path": "eot", "message": "Required" },
        { "path": "confidence", "message": "Number must be less than or equal to 1" }
      ]
    }
  ]
}
```

Fix the flagged events and resend the whole batch. The already-valid events were not
stored, so there is no risk of duplication.

## Rate limiting (`429`)

Requests are rate-limited per venue. If you exceed the limit, back off and retry.
High-frequency sources should **batch events** (up to 500 per request) rather than send one
request each.

## Temporary outages (`503`)

A `503` means Pulse hit a transient infrastructure problem (such as a brief database
disconnect). The request was not stored. Retry after the interval in the `Retry-After`
header; because resends are [idempotent](/delivery-semantics), retrying is always safe.
