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.