Skip to content
EntryWick documentation

For a developer connecting a turnstile, an access-control system or their own scanning app to EntryWick.

Scanner API for your own scanners — entrywick.app/api/v1/events/{event}/scan

Who uses it: a developer connecting a turnstile, an access-control system or their own scanning app to EntryWick.

What they came to do: admit people with EntryWick's decision — exactly the one the EntryWick scanner makes — without pairing a phone.

True when they leave: their scanner calls three endpoints with one key and gets the answers the EntryWick scanner would, in the same envelope.

Getting a key

An organizer with tenant.api_keys (Owner, Admin or Developer) opens Organization → API keys, names the key, gives it the scanner scope and, if it should only see part of the organization, a group. A key can also expire, be limited to IP addresses or ranges, and have its own rate. The key is shown once; EntryWick keeps only a hash of it. Revoking a key stops it on its next request.

A group narrows what the key downloads — its roster is that group's people — not where it scans: a key may scan at any check-in point of the event, and that check-in point's own policy decides who it admits, exactly as it does for a member there.

Scanning with a key needs the Scale plan or above (api_scanner).

Test keys

Choose Test as the key's mode to get an ewk_test_… key for building and rehearsing. It calls the same endpoints and gets the same answers, but its check-ins are marked as tests:

  • they are left out of the live counts, the Live dashboard, attendance and reconciliation reports and their exports;
  • a person admitted with a test key is still admitted for real at the gate (and a second test scan is a duplicate within test mode only);
  • GET …/checkins with a test key lists test check-ins only, and with a live key live ones only;
  • an organization-wide admin can remove them from the event page with Clear test check-ins.

Use a test key against a real event's tickets before the day; switch to a live key for the day itself.

The calls

Every request goes to the scanner host with the key as a bearer token. POSTs also carry an Idempotency-Key, and each scan its own client_uuid, so a retry never admits anyone twice.

Call What it does
GET /api/v1/events/{event}/scan/manifest Days, check-in points and their policies, attendee types, and a signed link to the roster — the whole event, or the key's group. Send If-None-Match to get 304 when nothing changed.
POST /api/v1/events/{event}/scan One scan. The body names the check_in_point (a key is not pinned to one).
POST /api/v1/events/{event}/scan/batch Up to 500 scans made offline, applied in scanned_at order.
GET /api/v1/events/{event}/scan/roster?since=… What changed in the roster since a time.
GET /api/v1/events/{event}/checkins Check-ins so far, newest first.

{event} is the event's id (event.id in the manifest).

curl https://entrywick.app/api/v1/events/01jc3m4r7x8y9zabcdefghjkmn/scan \
  -H "Authorization: Bearer ewk_live_…" \
  -H "Idempotency-Key: 6f1c8a52-3a0e-4c55-9b7e-0d7c1e2f4a11" \
  -H "Content-Type: application/json" \
  -d '{"code": "EW1:DAY1-0042-HOU:3f9a1c0b", "check_in_point": "GATE1",
       "client_uuid": "0b8d3e5a-1f2c-4d6e-8a9b-7c6d5e4f3a21", "scanned_at": "2027-05-01T14:02:11Z"}'

The answer is the ScanResponse the EntryWick scanner reads: result (accepted, pre_checked, zone_entered, duplicate, day_locked, wrong_day, not_yet_open, closed, rejected, voided, unknown, …), the words to show, the person and ticket, and the check-in rows it wrote. Show the result's words to whoever is at the gate; decide what to do from result.

Refusals

Refusals use API v1's error envelope: {"error": {"code", "message", "request_id"}}.

Status code Meaning
401 api_key_unknown No key, or not one of ours.
401 api_key_revoked The key was revoked.
401 api_key_expired The key's time is up.
403 api_key_ip_not_allowed The request came from an address the key does not allow.
403 api_key_scope The key has no scanner scope.
403 entitlement_required The organization's plan does not include scanning with a key.
403 api_key_cannot_override Overriding a refusal needs a member at the check-in point, not a key.
404 not_found No such event in this organization.
400 validation_failed The body is missing something (details says what).
429 rate_limited Over the key's requests per minute; see Retry-After.

What a key cannot do

  • Override a refusal. An override is a person's decision with a reason; send the person to someone with the EntryWick scanner or the help desk.
  • Anything else in API v1, yet.

Everything a key does is recorded against the key.

Checking your scanner against ours

The check-in decision is pinned by a set of golden cases — the same file EntryWick's own server and scanner are tested against (scan-cases.json, published with this page). It describes a small world (days, check-in points and their policies) and, for each case, the tickets to set up and the scans to make, with the result each scan must get.

To run it against a scanner that decides locally: build the world in your scanner, replay each case's scans in order with at as the scan time, and compare result (and, for shared tickets, each person's result). To check an integration that calls the API: set the world up in a test event, send each scan to POST …/scan with at as scanned_at, and compare the result that comes back. Result codes must match; wording may differ.