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

# Batch calls

> Decide several elements or report several events in one request: envelopes, caps, per-item results and errors, and per-item idempotency.

Two endpoints have a batch form: `decide` takes `elements`, `events` takes `events`. Both return per-item results inside a `200`, so one bad item never fails its siblings, and both count as one request against the [rate limit](https://docs.trycurious.ai/api-reference/rate-limits.md).

## Decide several elements

```json theme={null}
{
  "user_id": "user_123",
  "attributes": { "plan": "pro" },
  "context": { "page": "/pricing" },
  "elements": [
    { "element": "pricing_hero" },
    { "element": "pricing_cta", "idempotency_key": "0b3c1f0a-9d8e-4b7c-a6f5-e4d3c2b1a0f9" },
    { "element": "upgrade_prompt", "user_id": "user_456" }
  ]
}
```

```json theme={null}
{
  "results": [
    { "index": 0, "element": "pricing_hero", "status": "ok", "content": "Ship better experiments", "arm_id": "…", "arm_type": "variant", "decision_id": "…", "experiment_id": "…", "experiment_status": "exploring" },
    { "index": 1, "element": "pricing_cta", "status": "ok", "content": "Start free", "arm_id": "…", "arm_type": "control", "decision_id": "…", "experiment_id": "…", "experiment_status": "initializing", "replayed": true },
    { "index": 2, "element": "upgrade_prompt", "status": "error", "error": "conflict", "message": "No live experiment for element \"upgrade_prompt\" — publishable keys are serve-only; declare the element first with a secret-key decide call or POST /declare" }
  ],
  "replayed": 1
}
```

* Up to 50 items. The envelope's `user_id`, `identifiers`, `attributes`, `context` and `options` are defaults that items may override.
* Each item is a complete singular request, so a secret-key item may carry a declaration, and a publishable-key item may carry only the serving fields.
* `idempotency_key` is per item. The envelope-level `replayed` counts how many items were replays.
* A repeated (user, element) pair in one envelope is an item-level error, since the second decision would only end the first's window.
* Items may name different users, for cross-user jobs such as rendering a digest for many recipients.

The browser SDK uses this form to decide every tagged element near the viewport in one request per frame; the server SDK exposes it as `decideMany()`.

## Report several events

```json theme={null}
{
  "user_id": "user_123",
  "timestamp": "2026-04-30T22:33:42Z",
  "events": [
    { "name": "viewed", "properties": { "page": "/pricing" }, "id": "v-1" },
    { "name": "clicked", "id": "c-1" },
    { "name": "purchased", "value": 49.99, "user_id": "user_456", "id": "p-9" },
    { "value": 3 }
  ]
}
```

```json theme={null}
{
  "results": [
    { "index": 0, "id": "v-1", "status": "ok" },
    { "index": 1, "id": "c-1", "status": "ok", "duplicate": true },
    { "index": 2, "id": "p-9", "status": "ok" },
    { "index": 3, "status": "error", "error": "invalid_request", "message": "user_id and name are required" }
  ],
  "duplicates": 1
}
```

* Up to 200 items. The envelope's `user_id`, `context` and `timestamp` apply to items that omit them.
* `id` is per item and echoed back. `duplicates` counts items whose `id` was already known, including an earlier item in the same batch.
* Unknown fields are ignored on the envelope and on items; `created_at` and `as_of` are rejected per item.

## Envelope errors versus item errors

An envelope error fails the whole request with a non-2xx status: a bad key, an unparseable body, an empty list (`elements must be a non-empty array`), more items than the cap. An item error is reported inside the `200` at the item's `index` and uses the same `{ "error", "message" }` shape as a standalone error. Handle both: check the status, then walk `results`.

## When to batch

Batch when the items are known together: a page with several optimized elements, a flush of queued events, a nightly sync. Do not hold a decision back to fill a batch; the deadline on `decide` matters more than the request count. Events can wait: the server SDK queues them and flushes every five seconds or every hundred events, whichever comes first.


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