Submit a batch of events

Submits many events in one request. Use this instead of many single calls when you have high volume. One request amortizes the cost of auth, parsing, and queueing across all the events, so throughput goes up and overhead goes down.

Each item in events is a full event object. It follows the same schema as Submit an event, so every per event field works here too, including agent_key, properties, and idempotency_key.

You can send 1 to 500 events per request.

Validation is atomic

The whole batch is validated before anything is enqueued. If any event is malformed, the request is rejected with 400 VALIDATION_ERROR and nothing is sent. The error details point to the failing event by position, for example events[12].action. Fix that event and resend the batch.

Response

A 202 Accepted returns a small body:

{
  "accepted": 48,
  "failed": [
    { "index": 12, "reason": "rejected" },
    { "index": 37, "reason": "unconfirmed" }
  ]
}

accepted is how many events were confirmed enqueued. failed lists any events the queue rejected or could not confirm, by their zero based position in your events array. An empty failed array means every event was confirmed enqueued. The response is always 202, even when some events fail, so you get a per event retry boundary instead of retrying the whole request.

Each failure has a reason:

reasonMeaningSafe to retry?
rejectedThe queue did not accept the event. It is not enqueued.Yes. Retrying it cannot duplicate.
unconfirmedThe enqueue call timed out or errored. The event may or may not be enqueued.Only with idempotency_key. Without one, a retry can create a duplicate.

Retry only the events in failed. For unconfirmed failures, set an idempotency_key on the event so the retry is deduplicated instead of billed twice.

Ordering

Events keep their order per outcome. Two events with the same key are processed in the order you sent them, even when they land in different internal batches. Events for different outcomes process in parallel.

Order holds across failures too. If an event is rejected or unconfirmed, any later event for the same outcome in the same request is also reported in failed and is not enqueued. So retrying the events in failed resends that outcome's tail in order. Failures never cascade between different outcomes.

Idempotency

Set idempotency_key on any event in the batch to make a retry of that event safe. The same key on the same outcome always maps to the same event, so resending it does not create a second billable event. Keys are scoped to your account and outcome key. See Submit an event for the full idempotency rules.

Size limit

The batch request body is capped at 5 MiB. Larger bodies are rejected with 413 PAYLOAD_TOO_LARGE. Keep properties small and store large metadata in your own storage, sending only a reference.

Example

curl -X POST https://api.thewitn.com/v1/events/batch \
  -H "Authorization: Bearer $WITN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "key": "support:ticket:1001",
        "action": "csat_received",
        "customer_key": "acme",
        "properties": { "value": 4 }
      },
      {
        "key": "support:ticket:1002",
        "action": "csat_received",
        "customer_key": "acme",
        "properties": { "value": 5 }
      }
    ]
  }'

Errors

CodeStatusWhen
VALIDATION_ERROR400Any event in the batch is missing a required field or is invalid, or the array is empty or over 500 events.
TOKEN_INVALID401The token is missing or not recognised.
PAYLOAD_TOO_LARGE413The batch body exceeded the 5 MiB limit.

Per event processing errors (such as AGENT_NOT_FOUND or CUSTOMER_NOT_FOUND) surface later in the background consumer DLQ, the same as the single event endpoint. A 202 only reports queue acceptance; processing still happens asynchronously.

On this page