REST API

Arrivals

Read-only feed of every check-in, check-out, undo and rejected scan, with the station, device and staff member behind each one.

An arrival is one record of a credential being presented and ruled on: a guest checked in at a gate, a pass rejected outside its valid window, a check-in undone by a supervisor. Each row carries when it happened, what the outcome was, and which station, device and staff member handled it.

This is the endpoint to use for live attendance, gate-by-gate breakdowns, and keeping an external system in step with check-ins. Arrivals are also reachable nested on a ticket via GET /tickets?include=scans, but that relation is keyed scans for historical reasons and cannot be filtered or paged independently.

Arrivals are read-only. Check-ins are written with PATCH /tickets/{id}/check_in.

The collection is not filtered for you

GET /arrivals returns every row, including rejected scans, check-outs and undos, in the same way that /orders returns refunded orders. The action field carries the outcome. Nothing is hidden by default, including archived arrivals.

Three groupings are worth knowing:

Meaning action values
A person was admitted in, pickup, entitlement
An admission was cancelled revalidated
Everything else rejections, check-outs, and diagnostic rows

A net attendance count is the number of admissions minus the number of cancellations. A revalidated row carries reverses_arrival_id, pointing at the arrival it cancels, so you can settle the count against the correct day rather than the day someone pressed undo.

Default response fields

id, created_at, updated_at, scanned_at, action, source, data, message, use_count, ticket_id, event_id, station_id, device_id, staff_id, reverses_arrival_id, deleted_at.

{
  "id": 88213045,
  "created_at": "2026-08-14T14:22:07.481Z",
  "updated_at": "2026-08-14T14:22:07.481Z",
  "scanned_at": "2026-08-14T14:22:07.480Z",
  "action": "in",
  "source": "lookup",
  "data": "9f2c41ab",
  "message": "",
  "use_count": 1,
  "ticket_id": 41902277,
  "event_id": 913044,
  "station_id": 1040,
  "device_id": 66132,
  "staff_id": 24518,
  "reverses_arrival_id": null,
  "deleted_at": null
}

Removed arrivals

An arrival can be deleted after the fact, for example when a check-in is undone or an order is refunded. Deleted arrivals are excluded by default, so deleted_at is null on every row you get back unless you ask for them.

This matters if you keep your own copy of the feed. Polling updated_at tells you about new and changed arrivals, but never about removed ones, so a mirror built only on that cursor keeps rows we no longer have.

Deleting an arrival moves its updated_at, so removals are pollable the same way everything else is. Run a second pass against filter[permanence]=discarded on its own updated_at cursor, and mark what it returns as removed on your side:

GET /arrivals?filter[permanence]=discarded&sort[updated_at]=asc&page[size]=100

filter[permanence]=all returns live and deleted arrivals together. It is there for a one-off audit rather than routine polling, and it is the slower of the two, so prefer discarded for an ongoing sync.

scanned_at is when the guest was admitted, as reported by the device that admitted them. created_at is when our servers stored the record. The two are the same for an arrival recorded online, and differ when a device was offline at the time — see keeping an external system up to date below.

Sort on scanned_at when you want the order guests arrived in. created_at follows the order we received the records, which for a device that spent time offline is not the same thing.

station_id, device_id and staff_id resolve through Stations, Devices and Staff.

station_id is nullable. A station is only recorded when the scanning app knows which one it is: Shopify POS assigns one automatically per location, while the iPad scanner and web check-in record null unless a station was chosen. If you are breaking attendance down by gate, count the nulls rather than assuming they are zero.

source describes how the credential was read: camera for a device camera, laser for a barcode scanner, and lookup when there was no scan at all — someone found the guest in a list and checked them in, which is what a web check-in, a bulk check-in and a check-in through this API always are.

data is the raw barcode or search term submitted, and is null when a check-in was performed by tapping a name in a list rather than scanning.

The event, station, device and staff relationships are returned only when listed in ?include=.

ticket behaves differently for historical reasons: on GET /arrivals it is returned only when included, but on GET /arrivals/{id} the full ticket is embedded by default. Use ?fields= if you want to trim it.

List arrivals

GET /arrivals

List today’s arrivals at one gate

curl -X GET \
  'https://app.guestmanager.com/api/public/v2/arrivals?filter[station_ids]=1040&filter[scanned_at][from]=2026-08-14&page[cursor]=&page[size]=100' \
  -H 'Authorization: Token abcdefg' \
  -H 'Content-Type: application/json'

Request parameters

Parameter Type Description
page[cursor] string Opaque cursor token. Send empty for the first page. See Pagination.
page[size] integer Records per page. Default 10, maximum 100.
sort[{field}] string Sort by id, created_at, updated_at, scanned_at. Value is asc or desc.
include string Comma separated: ticket, event, station, device, staff.
filter[scanned_at][from] date Arrivals at or after this time.
filter[scanned_at][to] date Arrivals at or before this time.
filter[action] string One action value, e.g. in.
filter[station_ids] integer Station ID.
filter[device_ids] integer Device ID.
filter[staff_ids] integer Staff ID.
filter[event_ids] integer Event ID.
filter[ticket_ids] integer Ticket ID.
filter[source] string lookup, camera or laser.
filter[is_successful] boolean 1 for successful operations only, 0 for rejections only.
filter[archived] string unarchived excludes archived arrivals, archived returns only those.
filter[permanence] string discarded returns only deleted arrivals, all returns live and deleted together. Omit to exclude deleted arrivals.

Get arrival

GET /arrivals/{id}

curl -X GET \
  'https://app.guestmanager.com/api/public/v2/arrivals/88213045?include=station,staff' \
  -H 'Authorization: Token abcdefg' \
  -H 'Content-Type: application/json'

Keeping an external system up to date

Page on updated_at, not on scanned_at. Sort by sort[updated_at]=asc, walk with page[cursor], and remember the updated_at of the last row you stored. On the next run, resume from there.

This matters more than it looks. scanned_at is reported by the scanning device, not by our servers. A scanner that loses connectivity keeps admitting guests offline and uploads the backlog when it reconnects, so arrivals appear stamped with the time they happened, which may be hours in the past. If you page on scanned_at, those rows land behind a cursor you have already passed and you will never see them, with no error to tell you so.

updated_at is set by our servers when the row is stored, so a late upload still sorts after everything you have already collected. It also moves when an arrival is changed, so undos and corrections come back around too.

For the same reason, treat an arrival you have already stored as mutable: match on id and update in place rather than inserting blindly.

Deletions do not appear on this cursor, because a deleted arrival leaves the default view entirely. Poll for them separately with filter[permanence]=discarded, as described under Removed arrivals.