frequentix
Developer docs

Build on the same API the product runs on.

The storefront, console and scanner are all clients of the frequentix API. These pages document the surface you can use too — OAuth clients, REST reads and signed webhooks — with worked examples our test suite verifies.

Documentation menu

API reference

Reads over your events, ticket types, orders, tickets and contacts, plus the narrow set of writes an integration actually needs: upserting contacts, checking tickets in, and managing webhook subscriptions. Field lists here mirror the API’s serializers exactly, and every example is schema-true.

Conventions

Base URL and versioning

Every endpoint lives under https://api.frequentix.com/v1. Requests carry Authorization: Bearer <token> — see Authentication.

Stability

Within /v1, documented fields are never removed or renamed, and their meaning doesn’t change. Evolution is additive: new fields, new endpoints and new webhook event names may appear at any time, so build clients that tolerate unknown keys. The webhook envelope and signature scheme are stable, and every delivery declares the api_version its payload was rendered under. If a breaking change is ever genuinely needed, it would ship opt-in, pinned per integration client — never as a surprise to existing integrations.

Responses and pagination

Responses wrap their result in a top-level data key. List endpoints return a paginator — 25 per page by default, ?per_page=N up to 100 — so page through with ?page=N and follow next_page_url until it is null:

dataarray

The page of results.

current_pageinteger

This page's number.

per_pageinteger

Page size — 25 by default; request more with ?per_page= up to 100.

totalinteger

Total results across all pages.

next_page_urlstring | null

Absolute URL of the next page — null on the last. Follow it until null to read everything.

prev_page_urlstring | null

Absolute URL of the previous page — null on the first.

frominteger | null

1-based index of the first result on this page.

tointeger | null

1-based index of the last result on this page.

last_pageinteger

Number of the final page.

first_page_urlstring

Absolute URL of the first page.

last_page_urlstring

Absolute URL of the final page.

pathstring

The endpoint URL without paging.

linksarray

Prev/number/next link objects, for building a pager UI.

Writes and idempotency

The two writes that create or change records — POST /integration/contacts and POST /integration/scans — require an Idempotency-Key header (any unique string up to 200 characters; a UUID is ideal). Retrying with the same key replays the stored response instead of running the request again, so a timeout can be retried safely. Reusing a key with a different body answers 409.

Object references

Every object is identified by a prefixed reference — a lowercase ULID like evt_01k0zqj4d8v6snb2x9e7g3m5cr. Treat references as opaque strings: match on the prefix if you must, never parse the tail.

evt_Event
tt_Ticket type
adn_Add-on
ord_Order
tkt_Ticket
ref_Refund
ses_Event session
loc_Scanner location
wle_Waitlist entry
whk_Webhook subscription
whd_Webhook delivery
scn_Entry scan
qst_Registration question
fld_Registration field

Money and dates

  • Monetary amounts are integers in minor units (pence, cents) with an uppercase ISO 4217 currency alongside — 8250 is £82.50.
  • REST timestamps are UTC in the form 2026-10-02T18:30:00.000000Z. Webhook payloads use offset ISO 8601 (2026-08-14T19:04:11+01:00) instead.

Fetching what changed

Every list endpoint takes ?updated_since=<ISO 8601> and switches into incremental mode: only rows updated on or after your pointer, oldest change first, and the response gains a top-level watermark beside data. The sync loop is three habits:

  1. Request the list with updated_since= your stored pointer (use 1970-01-01T00:00:00Z for the first full import).
  2. Walk next_page_url until it is null, upserting rows into your copy keyed by reference.
  3. Store the response’s watermark as your next updated_since.
The pointer loop
curl "https://api.frequentix.com/v1/integration/orders?updated_since=2026-08-21T10%3A02%3A31Z" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"

{
  "data": { "data": [  ], "next_page_url": null, },
  "watermark": "2026-08-21T10:09:44.000000Z"
}

The comparison is inclusive and the watermark sits a moment behind the clock, so nothing committing mid-poll can slip between two sweeps — the trade is that rows near the boundary can arrive twice. Upserting by reference makes re-delivery harmless; never treat the feed as append-only. In incremental mode pages are cursor-driven rather than numbered (a row changing mid-walk re-delivers later instead of shifting an unseen row out of a page), but the habit is unchanged — follow next_page_url:

dataarray

The page of results, oldest change first.

per_pageinteger

Page size — 25 by default; request more with ?per_page= up to 100.

next_page_urlstring | null

Absolute URL of the next page — null once you have everything. Follow it until null.

prev_page_urlstring | null

Absolute URL of the previous page — null on the first.

next_cursorstring | null

Opaque cursor the next-page URL carries; you never build one yourself.

prev_cursorstring | null

Opaque cursor for the previous page.

pathstring

The endpoint URL without paging.

Deletions and erasures

Removed rows disappear from default responses, which a sync cannot see. Add ?include_deleted=1 to receive tombstones: removed tickets and archived events carry deleted_at, and a contact erased under a data-protection request appears once as an identity-free stub (is_erased: true, every personal field null) — the signal to erase your copy as well. Every removal bumps updated_at, so tombstones flow through the same pointer loop.

What the pointer cannot see

Check-ins never touch the ticket row — a ticket’s updated_at (and its status) stay put when someone walks through the door. Arrivals live on the entry-scans list, which takes the same updated_since pointer, and on the ticket.scanned webhook. Registration answers likewise keep their own clock: editing an answer moves the answer’s answered_at, not the ticket’s updated_at.

List events

GET/v1/integration/eventsevents:read

Your organiser's events, newest first. An event-scoped client sees only the events it was granted.

Query parameters

pageinteger

Page number, starting at 1. Ignored when updated_since is present (cursor pages).

updated_sincestring (ISO 8601)

Incremental mode: only rows updated on or after this instant, oldest change first, cursor-paged, with a top-level watermark to use as your next pointer. Inclusive — expect re-delivery around the boundary and dedupe by reference. See “Fetching what changed”.

include_deletedboolean

Also return removed rows as tombstones (deleted_at set; erased contacts as identity-free stubs), so a sync can drop its copies. Off by default.

Event object

referencestring

Event reference (evt_…).

slugstring

URL slug — accepted interchangeably with the reference in paths.

namestring

Event name.

statusstring

draft or published.

starts_atstring | null

Event start, UTC.

ends_atstring | null

Event end, UTC.

timezonestring

IANA timezone the event runs in, e.g. Europe/London.

currencystring

Uppercase ISO 4217 currency code.

updated_atstring

When the event last changed, UTC — what ?updated_since= compares against.

deleted_atstring | null

Set when the event has been archived. Archived events only appear under ?include_deleted=1.

Example

Request
curl "https://api.frequentix.com/v1/integration/events" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "current_page": 1,
    "data": [
      {
        "reference": "evt_01k2h6vcwj1ya3z8r1k7g5f0nd",
        "slug": "northlight-sessions-winter-special",
        "name": "Northlight Sessions — Winter Special",
        "status": "draft",
        "starts_at": "2027-01-22T19:00:00.000000Z",
        "ends_at": "2027-01-22T23:00:00.000000Z",
        "timezone": "Europe/London",
        "currency": "GBP",
        "updated_at": "2026-08-19T16:47:03.000000Z",
        "deleted_at": null
      },
      {
        "reference": "evt_01k0zqj4d8v6snb2x9e7g3m5cr",
        "slug": "northlight-sessions-autumn-run",
        "name": "Northlight Sessions — Autumn Run",
        "status": "published",
        "starts_at": "2026-10-02T18:30:00.000000Z",
        "ends_at": "2026-12-19T22:30:00.000000Z",
        "timezone": "Europe/London",
        "currency": "GBP",
        "updated_at": "2026-08-18T09:12:40.000000Z",
        "deleted_at": null
      }
    ],
    "first_page_url": "https://api.frequentix.com/v1/integration/events?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "https://api.frequentix.com/v1/integration/events?page=1",
    "links": [
      {
        "url": null,
        "label": "&laquo; Previous",
        "active": false
      },
      {
        "url": "https://api.frequentix.com/v1/integration/events?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": null,
        "label": "Next &raquo;",
        "active": false
      }
    ],
    "next_page_url": null,
    "path": "https://api.frequentix.com/v1/integration/events",
    "per_page": 25,
    "prev_page_url": null,
    "to": 2,
    "total": 2
  }
}

Draft events are included — check status before treating an event as live.

With ?updated_since=, only events changed since your pointer, plus a watermark for the next poll.

Retrieve an event

GET/v1/integration/events/{eventKey}events:read

One event with its ticket types, including live availability counters.

Path parameters

eventKeystring

The event's reference (evt_…) or its slug — both are accepted.

Event object

referencestring

Event reference (evt_…).

slugstring

URL slug — accepted interchangeably with the reference in paths.

namestring

Event name.

statusstring

draft or published.

starts_atstring | null

Event start, UTC.

ends_atstring | null

Event end, UTC.

timezonestring

IANA timezone the event runs in, e.g. Europe/London.

currencystring

Uppercase ISO 4217 currency code.

updated_atstring

When the event last changed, UTC — what ?updated_since= compares against.

deleted_atstring | null

Set when the event has been archived. Archived events only appear under ?include_deleted=1.

ticket_types[] — Ticket type object

referencestring

Ticket type reference (tt_…).

namestring

Ticket type name.

priceinteger

Price in minor units (pence, cents).

currencystring

Uppercase ISO 4217 currency code.

is_activeboolean

Whether it is on sale.

totalinteger | null

Capacity — null when inventory is unlimited.

soldinteger | null

Tickets sold so far.

Example

Request
curl "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "reference": "evt_01k0zqj4d8v6snb2x9e7g3m5cr",
    "slug": "northlight-sessions-autumn-run",
    "name": "Northlight Sessions — Autumn Run",
    "status": "published",
    "starts_at": "2026-10-02T18:30:00.000000Z",
    "ends_at": "2026-12-19T22:30:00.000000Z",
    "timezone": "Europe/London",
    "currency": "GBP",
    "updated_at": "2026-08-18T09:12:40.000000Z",
    "deleted_at": null,
    "ticket_types": [
      {
        "reference": "tt_01k0zqj5ae8txcv3m7d9e2b4hs",
        "name": "General admission",
        "price": 2750,
        "currency": "GBP",
        "is_active": true,
        "total": 350,
        "sold": 214
      },
      {
        "reference": "tt_01k0zqj5famz3w8p6t2v0c9d4e",
        "name": "Front row",
        "price": 4500,
        "currency": "GBP",
        "is_active": true,
        "total": 40,
        "sold": 40
      }
    ]
  }
}

An unknown key, another organiser's event, or an event outside your client's scope all return the same 404 — existence is never revealed.

List an event's orders

GET/v1/integration/events/{eventKey}/ordersorders:read

The event's orders, newest first, with buyer contact details.

Path parameters

eventKeystring

The event's reference (evt_…) or its slug — both are accepted.

Query parameters

pageinteger

Page number, starting at 1. Ignored when updated_since is present (cursor pages).

updated_sincestring (ISO 8601)

Incremental mode: only rows updated on or after this instant, oldest change first, cursor-paged, with a top-level watermark to use as your next pointer. Inclusive — expect re-delivery around the boundary and dedupe by reference. See “Fetching what changed”.

Order object

referencestring

Order reference (ord_…).

statusstring

draft, pending_payment, awaiting_approval, paid, free_confirmed, cancelled or refunded.

currencystring

Uppercase ISO 4217 currency code.

subtotalinteger

Line-item total before discounts and tax, in minor units.

discount_totalinteger

Discounts applied, in minor units.

tax_totalinteger

Tax charged, in minor units.

totalinteger

Amount paid, in minor units.

contactobject | null

Buyer contact — {email, first_name, last_name} — or null when none is attached.

confirmed_atstring | null

When the order confirmed, UTC.

created_atstring

When the order was created, UTC.

updated_atstring

When the order last changed (status moves, refunds, …), UTC — what ?updated_since= compares against.

Example

Request
curl "https://api.frequentix.com/v1/integration/events/northlight-sessions-autumn-run/orders?page=1" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "current_page": 1,
    "data": [
      {
        "reference": "ord_01k2f1rdth8wz1y6p9h5f0d3ka",
        "status": "paid",
        "currency": "GBP",
        "subtotal": 9000,
        "discount_total": 0,
        "tax_total": 0,
        "total": 9000,
        "contact": {
          "email": "theo.marsh@example.com",
          "first_name": "Theo",
          "last_name": "Marsh"
        },
        "confirmed_at": "2026-08-21T10:02:33.000000Z",
        "created_at": "2026-08-21T09:58:12.000000Z",
        "updated_at": "2026-08-21T10:02:33.000000Z"
      },
      {
        "reference": "ord_01k1p3v9qe6rwyx0m5h8t2c4nf",
        "status": "paid",
        "currency": "GBP",
        "subtotal": 8250,
        "discount_total": 0,
        "tax_total": 0,
        "total": 8250,
        "contact": {
          "email": "amelia.hart@example.com",
          "first_name": "Amelia",
          "last_name": "Hart"
        },
        "confirmed_at": "2026-08-14T18:04:11.000000Z",
        "created_at": "2026-08-14T18:01:47.000000Z",
        "updated_at": "2026-08-14T18:04:11.000000Z"
      }
    ],
    "first_page_url": "https://api.frequentix.com/v1/integration/events/northlight-sessions-autumn-run/orders?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "https://api.frequentix.com/v1/integration/events/northlight-sessions-autumn-run/orders?page=1",
    "links": [
      {
        "url": null,
        "label": "&laquo; Previous",
        "active": false
      },
      {
        "url": "https://api.frequentix.com/v1/integration/events/northlight-sessions-autumn-run/orders?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": null,
        "label": "Next &raquo;",
        "active": false
      }
    ],
    "next_page_url": null,
    "path": "https://api.frequentix.com/v1/integration/events/northlight-sessions-autumn-run/orders",
    "per_page": 25,
    "prev_page_url": null,
    "to": 2,
    "total": 2
  }
}

Orders of every status are returned — filter on status (paid, free_confirmed, refunded, …) for settled revenue.

With ?updated_since=, refunds and cancellations surface too: any status move bumps updated_at.

Who am I

GET/v1/integration/meany scope

The organiser this token acts for and what the client may do. Automation platforms use it as the connection test and label.

Identity object

organiserobject

{reference, display_name} — whose data this token reads.

clientobject

{id, name, scopes, all_events} — the client behind the token.

api_versionstring

The contract version this client is pinned to (date-stamped).

Example

Request
curl "https://api.frequentix.com/v1/integration/me" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "organiser": {
      "reference": "org_01k0zq2v7m4xerb8t5w9c3n6dh",
      "display_name": "Northlight Live"
    },
    "client": {
      "id": "9d3f2b1a-4c5e-6f70-8192-a3b4c5d6e7f8",
      "name": "Zapier",
      "scopes": [
        "orders:read",
        "tickets:read",
        "webhooks:write"
      ],
      "all_events": true
    },
    "api_version": "2026-08-01"
  }
}

List orders (organiser-wide)

GET/v1/integration/ordersorders:read

Every event's orders in one feed, newest first — the polling shape for automations not pinned to one event. Each order carries its event reference.

Query parameters

pageinteger

Page number, starting at 1. Ignored when updated_since is present (cursor pages).

updated_sincestring (ISO 8601)

Incremental mode: only rows updated on or after this instant, oldest change first, cursor-paged, with a top-level watermark to use as your next pointer. Inclusive — expect re-delivery around the boundary and dedupe by reference. See “Fetching what changed”.

Order object

referencestring

Order reference (ord_…).

statusstring

draft, pending_payment, awaiting_approval, paid, free_confirmed, cancelled or refunded.

currencystring

Uppercase ISO 4217 currency code.

subtotalinteger

Line-item total before discounts and tax, in minor units.

discount_totalinteger

Discounts applied, in minor units.

tax_totalinteger

Tax charged, in minor units.

totalinteger

Amount paid, in minor units.

contactobject | null

Buyer contact — {email, first_name, last_name} — or null when none is attached.

confirmed_atstring | null

When the order confirmed, UTC.

created_atstring

When the order was created, UTC.

updated_atstring

When the order last changed (status moves, refunds, …), UTC — what ?updated_since= compares against.

eventstring | null

Reference of the event the order belongs to (evt_…).

Example

Request
curl "https://api.frequentix.com/v1/integration/orders?updated_since=2026-08-21T10%3A00%3A00Z" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "current_page": 1,
    "data": [
      {
        "reference": "ord_01k2f1rdth8wz1y6p9h5f0d3ka",
        "status": "paid",
        "currency": "GBP",
        "subtotal": 9000,
        "discount_total": 0,
        "tax_total": 0,
        "total": 9000,
        "contact": {
          "email": "theo.marsh@example.com",
          "first_name": "Theo",
          "last_name": "Marsh"
        },
        "confirmed_at": "2026-08-21T10:02:33.000000Z",
        "created_at": "2026-08-21T09:58:12.000000Z",
        "updated_at": "2026-08-21T10:02:33.000000Z",
        "event": "evt_01k0zqj4d8v6snb2x9e7g3m5cr"
      }
    ],
    "first_page_url": "https://api.frequentix.com/v1/integration/orders?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "https://api.frequentix.com/v1/integration/orders?page=1",
    "links": [
      {
        "url": null,
        "label": "&laquo; Previous",
        "active": false
      },
      {
        "url": "https://api.frequentix.com/v1/integration/orders?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": null,
        "label": "Next &raquo;",
        "active": false
      }
    ],
    "next_page_url": null,
    "path": "https://api.frequentix.com/v1/integration/orders",
    "per_page": 25,
    "prev_page_url": null,
    "to": 1,
    "total": 1
  }
}

An event-scoped client sees only its events' orders here, exactly as on the per-event endpoint.

One organiser-wide updated_since pointer here syncs every event's orders in a single loop.

Retrieve an order

GET/v1/integration/orders/{reference}orders:read

One order by its reference, with its event.

Path parameters

referencestring

The order's reference (ord_…).

Order object

referencestring

Order reference (ord_…).

statusstring

draft, pending_payment, awaiting_approval, paid, free_confirmed, cancelled or refunded.

currencystring

Uppercase ISO 4217 currency code.

subtotalinteger

Line-item total before discounts and tax, in minor units.

discount_totalinteger

Discounts applied, in minor units.

tax_totalinteger

Tax charged, in minor units.

totalinteger

Amount paid, in minor units.

contactobject | null

Buyer contact — {email, first_name, last_name} — or null when none is attached.

confirmed_atstring | null

When the order confirmed, UTC.

created_atstring

When the order was created, UTC.

updated_atstring

When the order last changed (status moves, refunds, …), UTC — what ?updated_since= compares against.

eventstring | null

Reference of the event the order belongs to (evt_…).

Example

Request
curl "https://api.frequentix.com/v1/integration/orders/ord_01k2f1rdth8wz1y6p9h5f0d3ka" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "reference": "ord_01k2f1rdth8wz1y6p9h5f0d3ka",
    "status": "paid",
    "currency": "GBP",
    "subtotal": 9000,
    "discount_total": 0,
    "tax_total": 0,
    "total": 9000,
    "contact": {
      "email": "theo.marsh@example.com",
      "first_name": "Theo",
      "last_name": "Marsh"
    },
    "confirmed_at": "2026-08-21T10:02:33.000000Z",
    "created_at": "2026-08-21T09:58:12.000000Z",
    "updated_at": "2026-08-21T10:02:33.000000Z",
    "event": "evt_01k0zqj4d8v6snb2x9e7g3m5cr"
  }
}

List an event's tickets

GET/v1/integration/events/{eventKey}/ticketstickets:read

Issued tickets with their holders, newest first. Filter by order to turn an order into its attendees — one item per person.

Path parameters

eventKeystring

The event's reference (evt_…) or its slug — both are accepted.

Query parameters

pageinteger

Page number, starting at 1. Ignored when updated_since is present (cursor pages).

orderstring

Only this order's tickets (ord_…). Unknown orders 404.

statusstring

valid, checked_in, cancelled or refunded. Arrivals are not reported through this field — read the entry-scans list or ticket.scanned webhooks.

updated_sincestring (ISO 8601)

Incremental mode: only rows updated on or after this instant, oldest change first, cursor-paged, with a top-level watermark to use as your next pointer. Inclusive — expect re-delivery around the boundary and dedupe by reference. See “Fetching what changed”.

include_deletedboolean

Also return removed rows as tombstones (deleted_at set; erased contacts as identity-free stubs), so a sync can drop its copies. Off by default.

includestring

answers adds each ticket's registration answers to the list items (always present on the single-ticket read).

Ticket object

referencestring

Ticket reference (tkt_…).

statusstring

valid, checked_in, cancelled or refunded. Check-ins never appear here (or move updated_at): arrivals live on the scan record — consume ticket.scanned webhooks or the entry-scans list.

ticket_typeobject | null

The type — {reference, name}.

contactobject | null

The holder — {reference, email, first_name, last_name}. Reassignment repoints this, so it is the person at the door, not necessarily the buyer.

orderstring | null

Order reference (ord_…).

sessionobject | null

For multi-date runs: the occurrence this ticket admits to — {reference, name, starts_at}; null on a single-date event.

seat_labelstring | null

Reserved seating: the seat ("Stalls · Row A · Seat 4"); null for GA.

created_atstring

When the ticket was issued, UTC.

updated_atstring

When the ticket last changed (reassignment, cancellation, …), UTC — what ?updated_since= compares against.

deleted_atstring | null

Set when the ticket was removed (superseded by a transfer or resale, or erased). Removed tickets only appear under ?include_deleted=1.

answers[] — Answer object (with `?include=answers`)

questionstring

The question's reference (qst_…) — an answer's identity is (ticket, question); there is no separate answer id.

fieldstring

The underlying field definition (fld_…), shared across events.

keystring

The field's machine key, stable per organiser — e.g. dietary.

labelstring | null

The question as it was asked.

typestring

Field type — text, select, multiselect, date, country, ….

valuestring | number | boolean | array | null

The answer as stored. Null when the question was asked but not answered — a different fact from the question being absent (not asked for this ticket's type).

value_labelsarray | null

For choice types: the chosen options resolved to their labels, always as a list (one element on a single select). Choice options have no ids — value is the stable key, this is the wording.

answered_atstring | null

When the answer row last changed, UTC. This is the only change signal: editing answers moves nothing on the ticket, and a data-protection erasure nulls value while moving this.

Example

Request
curl "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/tickets?order=ord_01k2f1rdth8wz1y6p9h5f0d3ka" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "current_page": 1,
    "data": [
      {
        "reference": "tkt_01k2f1rf2p9xz4w7b1m6d8e0hs",
        "status": "valid",
        "ticket_type": {
          "reference": "tt_01k0zqj5ae8txcv3m7d9e2b4hs",
          "name": "General admission"
        },
        "contact": {
          "reference": "con_01k2f1rdz44qh8n2v5x9b7c1mf",
          "email": "theo.marsh@example.com",
          "first_name": "Theo",
          "last_name": "Marsh"
        },
        "order": "ord_01k2f1rdth8wz1y6p9h5f0d3ka",
        "session": null,
        "seat_label": null,
        "created_at": "2026-08-21T10:02:34.000000Z",
        "updated_at": "2026-08-21T10:02:34.000000Z",
        "deleted_at": null
      }
    ],
    "first_page_url": "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/tickets?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/tickets?page=1",
    "links": [
      {
        "url": null,
        "label": "&laquo; Previous",
        "active": false
      },
      {
        "url": "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/tickets?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": null,
        "label": "Next &raquo;",
        "active": false
      }
    ],
    "next_page_url": null,
    "path": "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/tickets",
    "per_page": 25,
    "prev_page_url": null,
    "to": 1,
    "total": 1
  }
}

Cancelled-and-superseded tickets (transfers, resale) are excluded, exactly as in the console — unless you ask for tombstones with ?include_deleted=1, which serves them with deleted_at set so a sync can drop its copies.

With ?updated_since=, reassignments, cancellations and removals surface incrementally.

Retrieve a ticket

GET/v1/integration/tickets/{reference}tickets:read

One ticket by reference, with its holder, its event and the registration answers provided when it was bought.

Path parameters

referencestring

The ticket's reference (tkt_…).

Ticket object (plus `event`)

referencestring

Ticket reference (tkt_…).

statusstring

valid, checked_in, cancelled or refunded. Check-ins never appear here (or move updated_at): arrivals live on the scan record — consume ticket.scanned webhooks or the entry-scans list.

ticket_typeobject | null

The type — {reference, name}.

contactobject | null

The holder — {reference, email, first_name, last_name}. Reassignment repoints this, so it is the person at the door, not necessarily the buyer.

orderstring | null

Order reference (ord_…).

sessionobject | null

For multi-date runs: the occurrence this ticket admits to — {reference, name, starts_at}; null on a single-date event.

seat_labelstring | null

Reserved seating: the seat ("Stalls · Row A · Seat 4"); null for GA.

created_atstring

When the ticket was issued, UTC.

updated_atstring

When the ticket last changed (reassignment, cancellation, …), UTC — what ?updated_since= compares against.

deleted_atstring | null

Set when the ticket was removed (superseded by a transfer or resale, or erased). Removed tickets only appear under ?include_deleted=1.

eventstring | null

Reference of the ticket's event (evt_…).

answers[] — Answer object

questionstring

The question's reference (qst_…) — an answer's identity is (ticket, question); there is no separate answer id.

fieldstring

The underlying field definition (fld_…), shared across events.

keystring

The field's machine key, stable per organiser — e.g. dietary.

labelstring | null

The question as it was asked.

typestring

Field type — text, select, multiselect, date, country, ….

valuestring | number | boolean | array | null

The answer as stored. Null when the question was asked but not answered — a different fact from the question being absent (not asked for this ticket's type).

value_labelsarray | null

For choice types: the chosen options resolved to their labels, always as a list (one element on a single select). Choice options have no ids — value is the stable key, this is the wording.

answered_atstring | null

When the answer row last changed, UTC. This is the only change signal: editing answers moves nothing on the ticket, and a data-protection erasure nulls value while moving this.

Example

Request
curl "https://api.frequentix.com/v1/integration/tickets/tkt_01k2f1rf2p9xz4w7b1m6d8e0hs" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "reference": "tkt_01k2f1rf2p9xz4w7b1m6d8e0hs",
    "status": "valid",
    "ticket_type": {
      "reference": "tt_01k0zqj5ae8txcv3m7d9e2b4hs",
      "name": "General admission"
    },
    "contact": {
      "reference": "con_01k2f1rdz44qh8n2v5x9b7c1mf",
      "email": "theo.marsh@example.com",
      "first_name": "Theo",
      "last_name": "Marsh"
    },
    "order": "ord_01k2f1rdth8wz1y6p9h5f0d3ka",
    "session": null,
    "seat_label": null,
    "created_at": "2026-08-21T10:02:34.000000Z",
    "updated_at": "2026-08-21T10:02:34.000000Z",
    "deleted_at": null,
    "event": "evt_01k0zqj4d8v6snb2x9e7g3m5cr",
    "answers": [
      {
        "question": "qst_01k1c8mw2e5rv7x0b3d6f9g2hj",
        "field": "fld_01k1c8kt9q3nw6y8z1a4c7e0gm",
        "key": "dietary",
        "label": "Dietary requirements",
        "type": "select",
        "value": "vegan",
        "value_labels": [
          "Vegan"
        ],
        "answered_at": "2026-08-21T10:01:58.000000Z"
      },
      {
        "question": "qst_01k1c8p04u7tx9z2b5d8f1h4jn",
        "field": "fld_01k1c8n52s5pw8y0a3c6e9g2im",
        "key": "accessibility",
        "label": "Access requirements we should know about",
        "type": "text",
        "value": null,
        "value_labels": null,
        "answered_at": null
      }
    ]
  }
}

The answers are the buyer's registration — one submission per order — so every ticket on an order carries the same set. A question asked but left blank appears with value: null; a question not applicable to this ticket's type is absent.

List contacts

GET/v1/integration/contactscontacts:read

Your organiser's contacts, newest first. ?email= is an exact, case-insensitive lookup — the "find contact" step.

Query parameters

pageinteger

Page number, starting at 1. Ignored when updated_since is present (cursor pages).

emailstring

Exact email to look up (case-insensitive).

updated_sincestring (ISO 8601)

Incremental mode: only rows updated on or after this instant, oldest change first, cursor-paged, with a top-level watermark to use as your next pointer. Inclusive — expect re-delivery around the boundary and dedupe by reference. See “Fetching what changed”.

include_deletedboolean

Also return removed rows as tombstones (deleted_at set; erased contacts as identity-free stubs), so a sync can drop its copies. Off by default.

Contact object

referencestring

Contact reference (con_…).

emailstring | null

Email address — the identity key. Null on an erased contact's stub.

first_namestring | null

First name.

last_namestring | null

Last name.

mobilestring | null

Mobile number.

unsubscribed_atstring | null

When they unsubscribed from marketing email. If you email this list from your own tools, exclude anyone with a value here.

is_erasedboolean

True on the stub of a contact erased under a data-protection request: the reference survives so you can find your copy, every identity field is null, and your copy should be erased too.

erased_atstring | null

When the erasure happened, UTC.

created_atstring

When the contact was created, UTC.

updated_atstring

When the contact last changed, UTC — what ?updated_since= compares against. Erasure moves it, so a sweep picks the stub up.

Example

Request
curl "https://api.frequentix.com/v1/integration/contacts?email=theo.marsh%40example.com" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "current_page": 1,
    "data": [
      {
        "reference": "con_01k2f1rdz44qh8n2v5x9b7c1mf",
        "email": "theo.marsh@example.com",
        "first_name": "Theo",
        "last_name": "Marsh",
        "mobile": null,
        "unsubscribed_at": null,
        "is_erased": false,
        "erased_at": null,
        "created_at": "2026-08-21T09:58:12.000000Z",
        "updated_at": "2026-08-21T09:58:12.000000Z"
      }
    ],
    "first_page_url": "https://api.frequentix.com/v1/integration/contacts?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "https://api.frequentix.com/v1/integration/contacts?page=1",
    "links": [
      {
        "url": null,
        "label": "&laquo; Previous",
        "active": false
      },
      {
        "url": "https://api.frequentix.com/v1/integration/contacts?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": null,
        "label": "Next &raquo;",
        "active": false
      }
    ],
    "next_page_url": null,
    "path": "https://api.frequentix.com/v1/integration/contacts",
    "per_page": 25,
    "prev_page_url": null,
    "to": 1,
    "total": 1
  }
}

Contacts erased under a data-protection request are absent by default. With ?include_deleted=1 they appear as identity-free stubs (is_erased: true, every personal field null) — the signal to erase your copy too. Erasure bumps updated_at, so an incremental sweep picks the stub up.

Retrieve a contact

GET/v1/integration/contacts/{reference}contacts:read

One contact by reference.

Path parameters

referencestring

The contact's reference (con_…).

Contact object

referencestring

Contact reference (con_…).

emailstring | null

Email address — the identity key. Null on an erased contact's stub.

first_namestring | null

First name.

last_namestring | null

Last name.

mobilestring | null

Mobile number.

unsubscribed_atstring | null

When they unsubscribed from marketing email. If you email this list from your own tools, exclude anyone with a value here.

is_erasedboolean

True on the stub of a contact erased under a data-protection request: the reference survives so you can find your copy, every identity field is null, and your copy should be erased too.

erased_atstring | null

When the erasure happened, UTC.

created_atstring

When the contact was created, UTC.

updated_atstring

When the contact last changed, UTC — what ?updated_since= compares against. Erasure moves it, so a sweep picks the stub up.

Example

Request
curl "https://api.frequentix.com/v1/integration/contacts/con_01k2f1rdz44qh8n2v5x9b7c1mf" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "reference": "con_01k2f1rdz44qh8n2v5x9b7c1mf",
    "email": "theo.marsh@example.com",
    "first_name": "Theo",
    "last_name": "Marsh",
    "mobile": null,
    "unsubscribed_at": null,
    "is_erased": false,
    "erased_at": null,
    "created_at": "2026-08-21T09:58:12.000000Z",
    "updated_at": "2026-08-21T09:58:12.000000Z"
  }
}

Create or update a contact

POST/v1/integration/contactscontacts:write

Upsert by email: creates the contact (201) or updates the fields you provide on the existing one (200). Fields you omit are never touched, and the email is only ever the match key.

Query parameters

emailstring (body, required)

The identity key — matched case-insensitively.

first_name / last_name / mobilestring (body, optional)

Set only the fields you send.

Contact object

referencestring

Contact reference (con_…).

emailstring | null

Email address — the identity key. Null on an erased contact's stub.

first_namestring | null

First name.

last_namestring | null

Last name.

mobilestring | null

Mobile number.

unsubscribed_atstring | null

When they unsubscribed from marketing email. If you email this list from your own tools, exclude anyone with a value here.

is_erasedboolean

True on the stub of a contact erased under a data-protection request: the reference survives so you can find your copy, every identity field is null, and your copy should be erased too.

erased_atstring | null

When the erasure happened, UTC.

created_atstring

When the contact was created, UTC.

updated_atstring

When the contact last changed, UTC — what ?updated_since= compares against. Erasure moves it, so a sweep picks the stub up.

Example

Request
curl -X POST "https://api.frequentix.com/v1/integration/contacts" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 4f9e2b7c-1d0a-4c3e-9f68-2a5b7c9d1e3f" \
  -d '{"email": "amelia.hart@example.com", "first_name": "Amelia"}'
Response · 201
{
  "data": {
    "reference": "con_01k2p8xw3m6yq1v4b9d2f5g8hj",
    "email": "amelia.hart@example.com",
    "first_name": "Amelia",
    "last_name": null,
    "mobile": null,
    "unsubscribed_at": null,
    "is_erased": false,
    "erased_at": null,
    "created_at": "2026-08-22T14:11:05.000000Z",
    "updated_at": "2026-08-22T14:11:05.000000Z"
  }
}

Requires an Idempotency-Key header; replaying the same key returns the stored response instead of re-running.

A contact erased under a data-protection request answers 422 with code contacts.erased and is never recreated.

Check in a ticket

POST/v1/integration/scansscans:write

Record an online entry scan by ticket reference — the same evaluator as the door, so scan-once, session windows and validity windows all apply, and the organiser's ticket.scanned webhook fires.

Query parameters

ticketstring (body, required)

The ticket's reference (tkt_…).

Verdict object

allowedboolean

Whether the holder may enter.

reasonstring

Machine-readable verdict key, e.g. scanning.allowed, scanning.already_scanned.

messagestring

The verdict as a sentence.

sessionobject | null

Which date the ticket is for — the whole answer on scanning.outside_session_window.

seat_labelstring | null

The seat, so the door can direct the attendee; null for GA.

scanobject

The recorded scan — {reference, result, scanned_at}.

Example

Request
curl -X POST "https://api.frequentix.com/v1/integration/scans" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7a1c9e3f-5b2d-4e60-8f97-3c6d8e0f2a4b" \
  -d '{"ticket": "tkt_01k2f1rf2p9xz4w7b1m6d8e0hs"}'
Response · 200
{
  "allowed": true,
  "reason": "scanning.allowed",
  "message": "Entry allowed.",
  "session": null,
  "seat_label": null,
  "scan": {
    "reference": "scn_01k2p9av6r8tw2x5c0e3g6h9jk",
    "result": "allowed",
    "scanned_at": "2026-08-22T18:41:27.000000Z"
  }
}

An admitted scan answers 200; a denial answers 422 with the same verdict shape and allowed: false — read reason, don't treat the status alone as failure.

Requires an Idempotency-Key header. A replay returns the first verdict — on a scan-once ticket that is the difference between a repeated "allowed" and a wrong "already scanned".

List an event's entry scans

GET/v1/integration/events/{eventKey}/scansscans:read

The arrival feed: every recorded entry scan — admitted and denied — newest first. Check-ins never touch the ticket itself, so this list (or the ticket.scanned webhook) is the only place arrivals appear.

Path parameters

eventKeystring

The event's reference (evt_…) or its slug — both are accepted.

Query parameters

pageinteger

Page number, starting at 1. Ignored when updated_since is present (cursor pages).

updated_sincestring (ISO 8601)

Incremental mode: only rows updated on or after this instant, oldest change first, cursor-paged, with a top-level watermark to use as your next pointer. Inclusive — expect re-delivery around the boundary and dedupe by reference. See “Fetching what changed”.

Scan object

referencestring

Scan reference (scn_…).

ticketstring | null

The scanned ticket (tkt_…).

resultstring

allowed or denied.

reasonstring

Verdict key — scanning.allowed, scanning.already_scanned, ….

scanner_locationobject | null

The lane that scanned — {reference, name} — or null for online and staff check-ins.

sessionobject | null

The occurrence the scan resolved to — {reference, name, starts_at}; null on single-date events.

scanned_atstring

When the device scanned, UTC — device time, hours old on offline uploads.

created_atstring

When the platform recorded the row, UTC.

updated_atstring

What ?updated_since= compares against. Scans never change, so this is the moment the row landed — late offline uploads enter your sweep when they arrive.

Example

Request
curl "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/scans?updated_since=2026-10-02T18%3A00%3A00Z" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "current_page": 1,
    "data": [
      {
        "reference": "scn_01k2p9av6r8tw2x5c0e3g6h9jk",
        "ticket": "tkt_01k2f1rf2p9xz4w7b1m6d8e0hs",
        "result": "allowed",
        "reason": "scanning.allowed",
        "scanner_location": {
          "reference": "loc_01k0zqj6bh2uy5w8x1a4c7e0fn",
          "name": "Main doors"
        },
        "session": null,
        "scanned_at": "2026-10-02T18:41:27.000000Z",
        "created_at": "2026-10-02T19:03:04.000000Z",
        "updated_at": "2026-10-02T19:03:04.000000Z"
      }
    ],
    "first_page_url": "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/scans?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/scans?page=1",
    "links": [
      {
        "url": null,
        "label": "&laquo; Previous",
        "active": false
      },
      {
        "url": "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/scans?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": null,
        "label": "Next &raquo;",
        "active": false
      }
    ],
    "next_page_url": null,
    "path": "https://api.frequentix.com/v1/integration/events/evt_01k0zqj4d8v6snb2x9e7g3m5cr/scans",
    "per_page": 25,
    "prev_page_url": null,
    "to": 1,
    "total": 1
  }
}

scanned_at is the device's clock; updated_at is the platform's. The incremental pointer walks updated_at, so scans a device batched offline and uploaded later still enter your sweep when they land — a scanned_at cursor would miss them.

Denied attempts appear too, with their reason — useful for door-fraud reporting; filter on result yourself if you only want admissions.

Create a webhook subscription

POST/v1/integration/webhookswebhooks:write

Subscribe a URL to one or more event names (the REST-hook model automation platforms use). Deliveries ride the ordinary webhook pipeline: signed, retried, auto-disabled on repeated failure.

Query parameters

urlstring (body, required)

A public https/http endpoint — internal addresses are refused.

eventsarray (body, required)

Event names from the subscribable catalogue.

eventstring (body, optional)

Pin the subscription to one event (evt_…). Required for clients limited to specific events; omit for organiser-wide.

Subscription object (create includes `secret`)

referencestring

Subscription reference (whk_…).

urlstring

The endpoint deliveries are POSTed to.

eventsarray

The event names this subscription receives.

eventstring | null

Reference of the single event the subscription is pinned to; null means organiser-wide.

is_activeboolean

Whether deliveries are live.

disabled_reasonstring | null

Why the subscription was deactivated (repeated failures, or its client being revoked).

created_atstring

When it was created, UTC.

secretstring

Signing secret (whsec_…) — present on the create response only, never shown again.

Example

Request
curl -X POST "https://api.frequentix.com/v1/integration/webhooks" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://hooks.example.com/frequentix", "events": ["order.created"]}'
Response · 201
{
  "data": {
    "reference": "whk_01k2pa3c8t0vx4z7d2f5h8j1kn",
    "url": "https://hooks.example.com/frequentix",
    "events": [
      "order.created"
    ],
    "event": null,
    "is_active": true,
    "disabled_reason": null,
    "created_at": "2026-08-22T15:02:48.000000Z",
    "secret": "whsec_k3H9mQx2vT7bN4cW8pR1yD6fL0sJ5aZgEuVrOiMn"
  }
}

The signing secret is returned once, here, and never again.

A client may only see and delete its own subscriptions; ones configured in the console are invisible to it.

Creation is plan-gated exactly like the console (webhooks are a Pro feature); existing subscriptions keep delivering if the plan lapses.

List webhook subscriptions

GET/v1/integration/webhookswebhooks:write

The subscriptions this client created, newest first — without secrets.

Query parameters

pageinteger

Page number, starting at 1. Ignored when updated_since is present (cursor pages).

Subscription object

referencestring

Subscription reference (whk_…).

urlstring

The endpoint deliveries are POSTed to.

eventsarray

The event names this subscription receives.

eventstring | null

Reference of the single event the subscription is pinned to; null means organiser-wide.

is_activeboolean

Whether deliveries are live.

disabled_reasonstring | null

Why the subscription was deactivated (repeated failures, or its client being revoked).

created_atstring

When it was created, UTC.

Example

Request
curl "https://api.frequentix.com/v1/integration/webhooks" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "data": {
    "current_page": 1,
    "data": [
      {
        "reference": "whk_01k2pa3c8t0vx4z7d2f5h8j1kn",
        "url": "https://hooks.example.com/frequentix",
        "events": [
          "order.created"
        ],
        "event": null,
        "is_active": true,
        "disabled_reason": null,
        "created_at": "2026-08-22T15:02:48.000000Z"
      }
    ],
    "first_page_url": "https://api.frequentix.com/v1/integration/webhooks?page=1",
    "from": 1,
    "last_page": 1,
    "last_page_url": "https://api.frequentix.com/v1/integration/webhooks?page=1",
    "links": [
      {
        "url": null,
        "label": "&laquo; Previous",
        "active": false
      },
      {
        "url": "https://api.frequentix.com/v1/integration/webhooks?page=1",
        "label": "1",
        "active": true
      },
      {
        "url": null,
        "label": "Next &raquo;",
        "active": false
      }
    ],
    "next_page_url": null,
    "path": "https://api.frequentix.com/v1/integration/webhooks",
    "per_page": 25,
    "prev_page_url": null,
    "to": 1,
    "total": 1
  }
}

Delete a webhook subscription

DELETE/v1/integration/webhooks/{reference}webhooks:write

Remove one of this client's subscriptions; deliveries stop immediately.

Path parameters

referencestring

The subscription's reference (whk_…).

Response

messagestring

Confirmation message.

Example

Request
curl -X DELETE "https://api.frequentix.com/v1/integration/webhooks/whk_01k2pa3c8t0vx4z7d2f5h8j1kn" \
  -H "Authorization: Bearer $FREQUENTIX_TOKEN"
Response · 200
{
  "message": "Webhook subscription deleted."
}