---
title: "Create an event"
method: POST
path: "/events"
tags: ["events"]
---

# Create an event

`POST /events`

`external_id` and `shopify_customer_id` also create a profile when none matches.

## Headers

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

## Request body

- EventCreate — Pass exactly one of `profile_id` or `identifier`.
  - `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 `201`

The created event.

- EventEnvelope
  - `data` Event, required
    - `currency` string, nullable, required — Non-null exactly when `value` is.
    - `dedupe_id` string, nullable, required — Property-scoped, first-write-wins for 48 hours.
    - `id` string, required
    - `metric` Metric — The registered meaning and observed schema of an event type.
      - `description` string, nullable, required — Writable on custom metrics only.
      - `first_seen_at` string, date-time, required
      - `id` string, required — Metric ID (`mtr_*`).
      - `name` string, required — The event type this metric aggregates, e.g. `order.completed`.
      - `object` 'metric', required
      - `schema` object, required — Discovered property types, `{property path: type}`. Fills in as events arrive; a path observed with conflicting types reads `mixed`.
      - `source` string, nullable, required — Originating integration (`shopify`, `api`, `sdk`).
      - `system` boolean, required — True for platform-owned standard metrics.
    - `object` 'event', required
    - `occurred_at` string, date-time, required
    - `profile` Profile
      - `attributes` object, required
      - `created_at` string, date-time, required
      - `id` string, required
      - `identifier_ids` IdentifierId[], required
      - `identifiers` Identifier[]
        - `created_at` string, date-time, required
        - `display_value` string, required
        - `id` string, required
        - `is_primary` boolean, required
        - `object` 'identifier', required
        - `profile_id` string, required
        - `source` string, required
        - `type` string, required
        - `updated_at` string, date-time, required
        - `value` string — Requires the `identifiers:read_value` scope.
        - `verified_at` string, date-time, required
      - `location` Location, required
        - `city` string, nullable
        - `country` string, nullable — ISO 3166-1 alpha-2.
        - `region` string, nullable
        - `timezone` string, nullable — IANA time zone name.
        - `zip` string, nullable
      - `merged_into` string, required
      - `object` 'profile', required
      - `profile_ref` string — Property-scoped compact reference, present for properties enabled for the rollout. It is not authorization or merge evidence.
      - `status` 'active' | 'merged' | 'redacted', required
      - `tags` string[], required — Managed in the Postscript app and by the Shopify customer sync.
      - `updated_at` string, date-time, required
    - `profile_id` string, nullable, required — Null only for anonymous events not yet linked to a profile.
    - `properties` object, required
    - `received_at` string, date-time, required
    - `source` string, 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, nullable, required — Decimal string.
  - `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.
- `404` — No such resource in the authenticated property.
- `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).
- `422` — Semantically invalid, e.g. an impossible lifecycle transition.
- `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)
