---
title: "Bulk create events"
method: POST
path: "/events/batch"
tags: ["events"]
---

# Bulk create events

`POST /events/batch`

Accepts up to 1,000 events. `external_id` and `shopify_customer_id` must already match a profile. See [Bulk requests](/docs/bulk-requests) for per-item results and retry behaviour.

## Headers

- `Idempotency-Key` string
- `Postscript-Version` string, date

## Request body

- EventBatchRequest — Up to 1,000 items and 2 MB per request.
  - `backfill` boolean — Marks the whole batch as historical: stored and counted in aggregates, but never triggers flows or webhooks. Debits a separate rate window.
  - `events` EventBatchItem[], required
    - `currency` string
    - `dedupe_id` string — Deduplicates the event for 48 hours. See [Idempotency](/docs/idempotency).
    - `identifier` object — `email` and `phone` create a profile when none matches.
      - `type` string, required
      - `value` string, required
    - `occurred_at` string, date-time — Defaults to `received_at`.
    - `profile_id` string
    - `properties` object, required
    - `type` string, required — Lowercase dot notation, e.g. `order.completed`. Underscores are rewritten as dots. Platform namespaces such as `sms.*` and `profile.*` are reserved.
    - `value` string — Decimal string, sent with `currency`.

## Response `200`

Per-item results in request order. Failed items carry a per-item `error`; successes carry the event reference.

- BatchEnvelope
  - `data` BatchResult, required — Per-item results, ordered as the request. A batch takes up to 1,000 items for event ingestion and 100 elsewhere.
    - `counts` object, required
      - `failed` integer, required
      - `succeeded` integer, required
    - `object` 'batch_result', required
    - `results` BatchItemResult[], required
      - `client_reference` string, nullable
      - `data` object, nullable — On success, the affected resource reference; null on failure.
        - `id` string, required — Type-prefixed ID, parsed case-insensitively. IDs of a type sort by creation time.
        - `object` string, required
      - `error` object, nullable — On failure, the per-item error; null on success.
        - `code` string, required
        - `message` string, required
        - `param` string, nullable
        - `type` 'invalid_request' | 'authorization_error' | 'idempotency_error' | 'conflict' | 'not_found' | 'rate_limit_error' | 'provider_error' | 'internal_error', required
      - `status` integer, required
  - `meta` Meta, required
    - `as_of` string, date-time — The response reflects data through this instant.
    - `livemode` boolean, required
    - `page` PageMeta
      - `has_more` boolean, required
      - `limit` integer, required — Granted page size.
      - `next_cursor` string, nullable — Cursor for `page[after]`, valid 7 days.
    - `request_id` string, required
    - `resolved_from` string — The merged-away profile ID the request addressed; `data` holds the survivor.
    - `revision` string, date, required

## Other responses

- `400` — Malformed input, an unknown parameter, an unsupported filter, sort, or expand, or a mistyped ID.
- `401` — Missing or invalid API key.
- `403` — The key lacks the required scope.
- `409` — State conflict: an identifier collision (`identity_conflict`), an idempotency key reused with a different body, or a duplicate request still in flight (`Retry-After` present).
- `429` — Rate limit exceeded.
- `500` — Internal error.
- `502` — Upstream provider failure.
- `503` — Temporarily unavailable.

---

[API](https://skmtc.dev/pscrpt/apis/postscript-native-api-beta.md) · [All operations](https://skmtc.dev/pscrpt/apis/postscript-native-api-beta/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/pscrpt/postscript-native-api-beta/revisions/a9a161774352/schema)
