---
title: "Track Event"
method: POST
path: "/v1/events"
tags: ["Events"]
---

# Track Event

`POST /v1/events`

Record a customer event for a project. Requires the audience:write permission. Contact resolution is consent safe: profile fields may update, subscription status never changes. Send an Idempotency-Key header (or a body dedupeKey) for replay safety; without either, every call stores a distinct event. Events carrying identifiers.externalOrderId and a numeric properties.value are recorded as conversions attributed to the last email the contact clicked within five days.

## Headers

- `Idempotency-Key` string

## Request body

- IngestEventRequest
  - `projectId` string, required
  - `name` string, required — Event name, e.g. purchase.completed. Names containing refund or cancelled record negative conversion amounts.
  - `origin` string
  - `eventVersion` string
  - `identifiers` EventIdentifiers, required — Contact identity for the event. At least one of email or subscriberId is required. Provider ids (externalCustomerId, externalCheckoutId, externalOrderId) support integrations and conversion attribution.
    - `email` string, email
    - `subscriberId` string
    - `externalCustomerId` string
    - `externalCheckoutId` string
    - `externalOrderId` string — The provider's order or charge id. Required for the event to record a conversion.
  - `profile` EventProfile — Contact metadata to update. Profile updates never change subscription status, tags, or consent. Events never opt a contact in.
    - `firstName` string
    - `lastName` string
    - `phone` string
    - `country` string
    - `language` string
    - `customFields` object
  - `properties` object — Event facts. Up to 16KB, 50 top-level keys, 4 levels deep. A numeric value (major units, e.g. 49.99) together with identifiers.externalOrderId records a conversion; currency is an ISO code, default USD.
  - `occurredAt` string, date-time — When the event happened. Defaults to receipt time.
  - `dedupeKey` string — Event-identity dedupe key. Replaying the same key stores nothing and returns the original eventId.

## Response `201`

Event stored (or replayed)

- ApiResponseTrackEventResult
  - `success` boolean, required
  - `data` object, nullable
    - `stored` boolean — false when the dedupeKey was seen before; eventId then refers to the original event.
    - `eventId` string
    - `dedupeKey` string
  - `error` string, nullable

## Other responses

- `400` — Validation failed or no contact identifier
- `401` — Missing or invalid API key
- `403` — Missing audience:write permission or no access to the project
- `404` — Subscriber not found in this project

---

[API](https://skmtc.net/migma/apis/migma-ai-api-v1.md) · [All operations](https://skmtc.net/migma/apis/migma-ai-api-v1/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/migma/migma-ai-api-v1/revisions/2d06ad0e0bc3/schema)
