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

# Errors

> Every status code and message the Events API returns, and what to do about each one.

Errors come from two places, and they look different:

* **The gateway** checks the key, the size and the rate before your request reaches the API. It answers with a plain **HTML page**, not JSON.
* **The Events API** validates the payload and answers with **JSON** that includes a `trace_id`.

Check the status code first, and parse JSON only for `202`, `400`, `500` and `503` responses whose `Content-Type` is `application/json`.

## Status codes

| Status | Body | Meaning | What to do |
| - | - | - | - |
| `202` | JSON | At least one user accepted | Read `errors` and `warnings`. See [Response](https://docs.revbridge.ai/developer/ingesting-events.md#response). |
| `400` | JSON | The payload is invalid, or every user was rejected | Fix it using the messages below. Don't retry unchanged. |
| `401` | HTML | Missing `Authorization` header, or a wrong, deleted or malformed key | Send `Authorization: Bearer rbak_…` with an active key. |
| `403` | HTML | A publishable `rbpk_` key used outside `/ingest` | Use a secret key for that API. |
| `405` | Text | Wrong HTTP method | Use `POST`. |
| `413` | HTML | Body over 50 MB | Split the batch. Requests over 10 MB already fail with `400`. |
| `500` | JSON or HTML | Key validation was temporarily unavailable | Retry with backoff. |
| `503` | HTML | Rate limit exceeded | Retry with backoff, and batch more users per request. |
| `503` | JSON | `service temporarily unavailable`: the API couldn't take the events | Retry the same request with backoff. |

See [Limits & Retries](https://docs.revbridge.ai/developer/limits.md) for the limits and a retry loop.

## Request errors (400)

These reject the whole request. The body is `{ "error": "<message>", "trace_id": "…" }`.

| `error` | Cause | Fix |
| - | - | - |
| `invalid JSON body` | Malformed JSON, an empty body, or a body between 10 and 50 MB | Validate the JSON. Keep each request under 10 MB. |
| `users array is required and must not be empty` | `users` is missing or `[]` | Send at least one user. |
| `users array exceeds maximum of 1000` | More than 1,000 users | Split the batch. |
| `validation failed` | Every user was rejected | Read the `errors` list; the messages are below. |

## User errors

Each entry in `errors` has a `userIndex` (the zero-based position in `users`) and a `message`. A rejected user can have several entries. `events[N]` is the zero-based position of the event inside that user.

| `message` | Fix |
| - | - |
| `identifiers is required` | Add an `identifiers` object. |
| `at least one identifier is required (user_id, email, phone_number, or anon_id)` | Add one of those four. |
| `all provided identifiers have invalid values (see warnings)` | Every identifier was dropped. The `warnings` for the same `userIndex` say why. |
| `age must be a number` | Send `age` as a number, or leave it out. |
| `events array is required and must not be empty` | Add at least one event. |
| `events[N]: event_name is required` | Add `event_name`. |
| `events[N]: event_name must be a non-empty string` | `event_name` is empty or not a string. |
| `events[N]: timestamp must be a string` | Send the timestamp as text, not as a number. |
| `events[N]: timestamp must be valid ISO 8601` | Use `2026-01-15T14:30:00Z`. A date without a time is rejected. |
| `events[N]: revenue must be a number` | Send a number such as `49.99`. |
| `events[N]: event_value must be a number` | Send a number. |

## Warnings

A warning means the user was **accepted**, but one identifier was dropped. The message names the field and ends with `— field ignored`:

| `message` | Cause |
| - | - |
| `email: empty value — field ignored` | An identifier sent as `""` (also for `user_id`, `phone_number`, `anon_id`) |
| `user_id: placeholder value "null" is not an identifier — field ignored` | A placeholder such as `null`, `test`, `unknown` or `0` |
| `email: "jane@" is not a valid email address — field ignored` | The email doesn't look like `name@domain.tld` |
| `phone_number: "+55" is not a valid phone number (expected E.164, e.g. +5511999887766) — field ignored` | Fewer than 8 or more than 15 digits, letters, or one digit repeated |

Fix warnings at the source. Each one is a contact you can't reach or a person who won't match. The rules are in [Validation](https://docs.revbridge.ai/developer/user-identification.md#validation).

## Accepted but wrong

Some mistakes pass validation, return `202`, and still damage your data. The API can't flag them:

* **No `timestamp` on imported history**: every event is dated at import time. See [Send history with real timestamps](https://docs.revbridge.ai/developer/ingesting-events.md#send-history-with-real-timestamps).
* **The same order sent twice**: both are stored. See [Send each order once](https://docs.revbridge.ai/developer/best-practices.md#send-each-order-once).
* **`product_ids` as objects or a plain string**: product data is lost. See [Standard fields](https://docs.revbridge.ai/developer/event-types.md#standard-fields).
* **No email or phone**: the person can't receive a message.
* **No `first_name`**: messages go out without the name.

When you contact [support@revbridge.ai](mailto:support@revbridge.ai) about a request, include its `trace_id`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.