> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# Event Envelope

Every server source answers one question the same way: given a POST body, how many events did the caller send, and which ones. The same request body produces the same event count on Express, Cloud Functions, Lambda and Fetch.

## Accepted body forms[​](#accepted-body-forms "Direct link to Accepted body forms")

| Body                                          | Meaning                                                                                                            |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `{ "name": "page view", ... }`                | One event.                                                                                                         |
| `{ "batch": [ ... ] }`                        | N events. The canonical envelope.                                                                                  |
| `[ ... ]`                                     | N events. Accepted alias.                                                                                          |
| A string, number, `null`, or unparseable body | Raw input: one empty event, with the value available as `ingest.body` for a `source.before` transformer to decode. |

An object that is not a valid event is forwarded as one event rather than being replaced by an empty one, so a `source.before` chain can rewrite a vendor payload into a walkerOS event. Validity is decided once, by the collector, which answers 400 with a reason when an event never becomes one.

An explicit `{ "batch": [] }` is a well formed request carrying zero events. It answers 200, with `processed: 0` in the body wherever the response reflects the delivery outcome (see the synchronous-mode note below).

## Batch size[​](#batch-size "Direct link to Batch size")

`settings.maxBatchSize` caps how many events one request may carry. The default is 100 on every source. A batch over the cap answers **400** and nothing is pushed.

## Responses[​](#responses "Direct link to Responses")

A batch answers with the batch shape whether it carries one event or fifty:

| Outcome              | Status | Body                                                                |
| -------------------- | ------ | ------------------------------------------------------------------- |
| All events delivered | 200    | `{ success: true, processed, ids }`                                 |
| Some events failed   | 207    | `{ success: false, processed, failed, errors: [{ index, error }] }` |
| Over the cap         | 400    | `{ success: false, error }`                                         |

Single event requests keep their existing per source response bodies.

### 207 requires synchronous mode[​](#207-requires-synchronous-mode "Direct link to 207 requires synchronous mode")

The Express source acknowledges POST requests before delivery by default (`async` resolves to `true` for POST), so it cannot report per-index outcomes: an accepted batch answers 200 meaning "accepted", not "delivered", and failures surface through `collector.status` and the logs. Set `config.async: false` or `config.async: { "POST": false }` to have the response reflect the delivery outcome.

## GET is one event, deliberately[​](#get-is-one-event-deliberately "Direct link to GET is one event, deliberately")

All four sources serve a tracking pixel on GET. Query parameters carry exactly one event, parsed with the same rules everywhere, and the response is a transparent GIF. There is no batch form on GET: URLs have length limits, and the pixel exists for the no-JS path where one event is the whole point.

On the AWS Lambda and Cloud Functions sources, `settings.enablePixelTracking: false` answers 405 instead. The Express and Fetch sources control this through their route configuration rather than a setting.

## Current limit: per-request ingest with batches[​](#current-limit-per-request-ingest-with-batches "Direct link to Current limit: per-request ingest with batches")

`ingest` is **request scoped**, not event scoped. Every event in one batch shares one `Ingest`.

Transformers that write per event annotations into `ingest` therefore record only the last event's values for a batch. This affects `@walkeros/transformer-bot` (which writes `ingest.bot.*`) and `@walkeros/transformer-validate`.

**While either transformer is in the chain, prefer single event requests.** Batch delivery is correct for the events themselves; only the `ingest` annotations collapse. A per event annotation channel is planned.

This applies to every batch producer, not just browser clients. A walkerOS runtime forwarding to another walkerOS runtime is one too: with `config.batch` set, `@walkeros/server-destination-api` sends one request carrying many events, so a receiving flow that runs either transformer collapses its annotations the same way.
