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

# Send events

> POST a batch of storefront events to the Layers Tracking API. Up to 100 events per request, validated individually, dispatched to your configured pipelines.

`POST /beacon` is the single ingestion endpoint for the Tracking API. It accepts a batch of up to 100 events per request and routes each event to the store pipelines configured to receive that event type.

## Authorization

The token can be passed as a header or as a `?token=` query parameter — see [Authentication](/tracking-api/authentication) for the full discussion.

<ParamField header="X-Storefront-Access-Token" type="string">
  Your Layers storefront access token. Required if `?token=` is not used.
</ParamField>

<ParamField query="token" type="string">
  Same token, passed via query string. Use this form when calling from `navigator.sendBeacon`, which can't set custom headers.
</ParamField>

## Headers

<ParamField header="Content-Type" type="string" default="application/json" required />

<ParamField header="Accept" type="string" default="application/json" required />

<ParamField header="X-Requested-With" type="string">
  Optional. If the value contains `tapcart` or `fuego` (case-insensitive), the request is tagged as `shopping_channel: "app"`. Otherwise the channel is inferred from User-Agent and defaults to `"web"`.
</ParamField>

## Body

<ParamField body="events" type="array" required>
  Array of 1–100 event objects. Each event is validated independently against the schema for its `event_type`. Events that fail validation are dropped without failing the batch.

  See [Event types](/tracking-api/event-types) for the per-event schema and the [Payload examples](/tracking-api/payload-examples) page for full request bodies.
</ParamField>

## Behavior

* Returns **`201 Created`** with a JSON `null` body on success.
* Returns **`401`** if no valid token is provided.
* Returns **`422`** with a `{ errors: [...] }` body if the top-level request shape is wrong (missing `events`, empty array, more than 100 entries).
* Per-event validation errors **do not fail the batch.** Invalid events are silently dropped. Valid events continue to dispatch.
* Each accepted event is enriched server-side with:
  * `geo_country`, `geo_state`, `geo_city` (from Cloudflare edge geo).
  * `device_type`, `browser`, `os` (parsed from `User-Agent`).
  * `shopping_channel` (`web` or `app`, inferred unless the event already specifies it).
* Events are routed to your store's configured pipelines based on `event_type`. Routing is fire-and-forget — pipeline delivery failures are logged but do not affect the HTTP response.

## Limits

| Limit                        | Value                                  |
| ---------------------------- | -------------------------------------- |
| Max events per request       | 100                                    |
| Min events per request       | 1                                      |
| Recommended max request body | 64 KB (the `sendBeacon` browser limit) |

For higher throughput, batch events on the client (e.g., flush every 2 seconds or every 20 events) and send multiple requests rather than one giant one.

## Request

```json Example request theme={null}
POST https://cl.uselayers.com/beacon
Content-Type: application/json
Accept: application/json
X-Storefront-Access-Token: shpat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

{
  "events": [
    {
      "event_id": "01HZY8E2K3M4N5P6Q7R8S9T0V1",
      "event_type": "product_click",
      "timestamp": "2026-06-01T14:30:00Z",
      "session_id": "sess_abc123",
      "attribution_token": "2y10smI2dB7XZXXFJsLUELltgueq8NRd",
      "product_id": 7003338965178,
      "position": 3
    },
    {
      "event_id": "01HZY8E2K3M4N5P6Q7R8S9T0V2",
      "event_type": "add_to_cart",
      "timestamp": "2026-06-01T14:30:12Z",
      "session_id": "sess_abc123",
      "product_id": 7003338965178,
      "variant_id": 41234567890123
    }
  ]
}
```

## Responses

<ResponseExample>
  ```text 201 Created theme={null}
  HTTP/1.1 201 Created
  Content-Type: application/json

  null
  ```

  ```json 401 Unauthenticated theme={null}
  {
    "error": "Unauthenticated"
  }
  ```

  ```json 422 Validation error theme={null}
  {
    "errors": [
      "Validation error: Required at \"events\""
    ]
  }
  ```
</ResponseExample>

## Next steps

* [Event types](/tracking-api/event-types) — the schema for every supported `event_type`.
* [Payload examples](/tracking-api/payload-examples) — copy-pasteable bodies for the most common scenarios.
* [Sending events with `navigator.sendBeacon`](/tracking-api/guides/send-beacon) — the recommended browser pattern.
