> ## 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.

# Ingesting Events

> Send customer events to RevBridge AI using the Events API endpoint.

## Endpoint

```
POST https://api.revbridge.ai/ingest/events
```

Send one or more users, each with their identifiers and a list of events, in a single request. The API validates each user independently and accepts valid users even if others in the batch fail validation.

<Info>
  **Base URL:** `https://api.revbridge.ai` (production) or `https://api-dev.revbridge.ai` (development).
</Info>

## Request format

### Headers

| Header          | Required | Description        |
| --------------- | -------- | ------------------ |
| `Authorization` | Yes      | `Bearer <API_KEY>` |
| `Content-Type`  | Yes      | `application/json` |

### Body

```json theme={null}
{
  "users": [
    {
      "identifiers": {
        "email": "jane@example.com",
        "user_id": "usr_12345"
      },
      "user_properties": {
        "loyalty_tier": "gold",
        "preferred_category": "electronics"
      },
      "events": [
        {
          "event_name": "purchase",
          "timestamp": "2026-01-15T14:30:00Z",
          "revenue": 89.99,
          "currency": "USD",
          "order_id": "ORD-9876"
        }
      ]
    }
  ]
}
```

### Fields

| Field                          | Type   | Required | Description                                                                                                                                                            |
| ------------------------------ | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `users`                        | array  | Yes      | Array of user objects (1–1,000 per request)                                                                                                                            |
| `users[].identifiers`          | object | Yes      | At least one identifier: `user_id`, `email`, `phone_number`, or `anon_id`. Can also include profile fields. See [User Identification](/developer/user-identification). |
| `users[].user_properties`      | object | No       | Key-value pairs that are accumulated on the user profile over time. The latest value for each key wins. See [User Properties](#user-properties).                       |
| `users[].events`               | array  | Yes      | At least one event per user                                                                                                                                            |
| `users[].events[].event_name`  | string | Yes      | Name of the event (e.g., `purchase`, `page_view`)                                                                                                                      |
| `users[].events[].timestamp`   | string | No       | ISO 8601 timestamp. Defaults to the current time if omitted.                                                                                                           |
| `users[].events[].revenue`     | number | No       | Revenue amount associated with the event                                                                                                                               |
| `users[].events[].event_value` | number | No       | Numeric value for the event                                                                                                                                            |
| `users[].events[].{custom}`    | any    | No       | Any additional key-value pairs are stored as event properties                                                                                                          |

## Response format

### 202 — Accepted

Returned when at least one user passes validation. The response includes counts and any per-user errors.

```json theme={null}
{
  "trace_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "users_accepted": 2,
  "users_rejected": 1,
  "errors": [
    {
      "userIndex": 2,
      "message": "at least one identifier is required (user_id, email, phone_number, or anon_id)"
    }
  ]
}
```

### 400 — Bad Request

Returned when the payload is invalid or **all** users fail validation.

```json theme={null}
{
  "error": "validation failed",
  "trace_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "errors": [
    {
      "userIndex": 0,
      "message": "events array is required and must not be empty"
    }
  ]
}
```

### 401 — Unauthorized

Returned when the API key is missing or invalid.

```json theme={null}
{
  "error": "unauthorized"
}
```

### 413 — Payload Too Large

Returned when the request body exceeds 10 MB.

### 503 — Service Unavailable

Returned when the service is temporarily unable to process requests. Retry with exponential backoff.

```json theme={null}
{
  "error": "service temporarily unavailable",
  "trace_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
```

## Partial acceptance

The Events API uses **partial acceptance**: valid users are processed even if other users in the same request fail validation. This means a single request can return `202 Accepted` with both `users_accepted > 0` and `users_rejected > 0`.

<Info>
  Always check the `users_rejected` field in the response. If it is greater than zero, inspect the `errors` array to understand which users failed and why.
</Info>

## Trace ID

Every response includes a `trace_id`. This unique identifier can be used to:

* Correlate requests with RevBridge support for debugging
* Log and track requests in your own systems
* Match accepted events to their downstream effects

<Tip>
  Store the `trace_id` from every API response in your logs. It significantly speeds up troubleshooting.
</Tip>

## Examples

### Simple event

Send a single purchase event for one user.

<Accordion title="cURL">
  ```bash theme={null}
  curl -X POST https://api.revbridge.ai/ingest/events \
    -H "Authorization: Bearer rbk_a1b2c3d4e5f6g7h8" \
    -H "Content-Type: application/json" \
    -d '{
      "users": [
        {
          "identifiers": {
            "email": "jane@example.com"
          },
          "events": [
            {
              "event_name": "purchase",
              "timestamp": "2026-01-15T14:30:00Z",
              "revenue": 89.99,
              "currency": "USD",
              "order_id": "ORD-9876"
            }
          ]
        }
      ]
    }'
  ```
</Accordion>

<Accordion title="JavaScript (fetch)">
  ```javascript theme={null}
  const response = await fetch("https://api.revbridge.ai/ingest/events", {
    method: "POST",
    headers: {
      "Authorization": "Bearer rbk_a1b2c3d4e5f6g7h8",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      users: [
        {
          identifiers: { email: "jane@example.com" },
          events: [
            {
              event_name: "purchase",
              timestamp: "2026-01-15T14:30:00Z",
              revenue: 89.99,
              currency: "USD",
              order_id: "ORD-9876",
            },
          ],
        },
      ],
    }),
  });

  const data = await response.json();
  console.log(`Accepted: ${data.users_accepted}, Rejected: ${data.users_rejected}`);
  ```
</Accordion>

<Accordion title="Python (requests)">
  ```python theme={null}
  import requests

  response = requests.post(
      "https://api.revbridge.ai/ingest/events",
      headers={
          "Authorization": "Bearer rbk_a1b2c3d4e5f6g7h8",
          "Content-Type": "application/json",
      },
      json={
          "users": [
              {
                  "identifiers": {"email": "jane@example.com"},
                  "events": [
                      {
                          "event_name": "purchase",
                          "timestamp": "2026-01-15T14:30:00Z",
                          "revenue": 89.99,
                          "currency": "USD",
                          "order_id": "ORD-9876",
                      }
                  ],
              }
          ]
      },
  )

  data = response.json()
  print(f"Accepted: {data['users_accepted']}, Rejected: {data.get('users_rejected', 0)}")
  ```
</Accordion>

### Batch request — multiple users

Send events for multiple users in a single request for better performance.

```json theme={null}
{
  "users": [
    {
      "identifiers": { "email": "jane@example.com", "user_id": "usr_001" },
      "events": [
        { "event_name": "purchase", "revenue": 49.99, "currency": "USD" }
      ]
    },
    {
      "identifiers": { "email": "john@example.com", "user_id": "usr_002" },
      "events": [
        { "event_name": "add_to_cart", "product_id": "SKU-123", "product_name": "Blue T-Shirt" }
      ]
    },
    {
      "identifiers": { "phone_number": "+5511999887766" },
      "events": [
        { "event_name": "page_view", "page": "/summer-sale" },
        { "event_name": "product_view", "product_id": "SKU-456" }
      ]
    }
  ]
}
```

### Multiple events per user

A single user can have multiple events in one request. This is useful for sending a batch of historical events.

```json theme={null}
{
  "users": [
    {
      "identifiers": {
        "user_id": "usr_001",
        "email": "jane@example.com",
        "first_name": "Jane",
        "city": "São Paulo",
        "country": "BR"
      },
      "events": [
        {
          "event_name": "product_view",
          "timestamp": "2026-01-15T14:00:00Z",
          "product_id": "SKU-789",
          "category": "shoes"
        },
        {
          "event_name": "add_to_cart",
          "timestamp": "2026-01-15T14:05:00Z",
          "product_id": "SKU-789",
          "quantity": 1
        },
        {
          "event_name": "purchase",
          "timestamp": "2026-01-15T14:10:00Z",
          "revenue": 129.90,
          "currency": "BRL",
          "order_id": "ORD-5432"
        }
      ]
    }
  ]
}
```

### Custom event properties

Any key-value pairs beyond the standard fields are stored as custom event properties.

```json theme={null}
{
  "users": [
    {
      "identifiers": { "user_id": "usr_001" },
      "events": [
        {
          "event_name": "subscription_changed",
          "plan": "pro",
          "billing_cycle": "annual",
          "previous_plan": "free",
          "mrr": 99.00
        }
      ]
    }
  ]
}
```

### User properties

Use `user_properties` to accumulate profile attributes over time. Unlike `identifiers` (which are set once), user properties are **merged across events** — the latest value for each key always wins.

This is useful for tracking attributes that change over time and can arrive sparsely across different events.

```json theme={null}
{
  "users": [
    {
      "identifiers": {
        "email": "jane@example.com",
        "user_id": "usr_001"
      },
      "user_properties": {
        "loyalty_tier": "gold",
        "lifetime_value": "1250.00",
        "preferred_category": "electronics",
        "last_store_visited": "SP-Paulista"
      },
      "events": [
        { "event_name": "purchase", "revenue": 299.90 }
      ]
    }
  ]
}
```

<Info>
  User properties are accumulated over time using a **last-write-wins** strategy. If you send `loyalty_tier: "gold"` in one event and `loyalty_tier: "platinum"` in a later event, the profile will show `"platinum"`. Properties not included in a request are left unchanged.
</Info>

Key differences between `identifiers`, `user_properties`, and event properties:

|                 | `identifiers`                         | `user_properties`                | Event `{custom}`           |
| --------------- | ------------------------------------- | -------------------------------- | -------------------------- |
| **Scope**       | User profile (identity)               | User profile (attributes)        | Single event               |
| **Used for**    | Matching and merging profiles         | Segmentation and personalization | Event-level analytics      |
| **Persistence** | Permanent (linked to identity graph)  | Last-write-wins across events    | Stored per event           |
| **Example**     | `email`, `phone_number`, `first_name` | `loyalty_tier`, `lifetime_value` | `product_id`, `cart_total` |
