Docs · Partners and devices
Booth devices
Pair a booth, call with a device key, sync the library, receive commands and keep Folio Live up to date.
Folio Live on a booth machine talks to /v1/device/… with a device key. Everything here is for software that runs in the booth.
- Console to Booth: A member reads out the six-digit code
- Booth to Folio: POST /v1/devices/pair
- Folio to Booth: Device key, shown once
- Booth to Folio: GET /v1/device/commands (long poll)
- Folio to Booth: sync_now, update_available or revoke
- Booth to Folio: POST /v1/device/commands/{command}/ack
Pairing#
- A signed-in member with
live:controlcreates a six-digit code in the console. It is valid for 10 minutes and is shown only once. - The booth trades the code for its key:
curl -X POST "$FOLIO_API_URL/v1/devices/pair" \
-H "Content-Type: application/json" \
-d '{
"code": "482913"
}'{
"status": true,
"message": "device paired",
"data": { "object": "device_pairing", "paired": true, "id": "dev_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012", "device": "Sanctuary booth", "key": "folio_booth_a1b2c3d4e5f60718293a4b5c6d7e8f90" }
}The code is single use and is stored hashed. Unknown, expired and used codes all answer the same 422, and repeated tries from one address or one code prefix answer 429. Store the key securely; it is shown once.
Every request#
Authorization: Bearer folio_booth_…
X-Folio-Device-Contract: 1A contract version outside the supported range answers 426; update the app. Every route also checks that the key is active, the church is not suspended, the church's plan includes the booth, and the per-device and per-church rate limits.
curl -X GET "$FOLIO_API_URL/v1/device/me" \
-H "Authorization: Bearer $FOLIO_DEVICE_KEY" \
-H "X-Folio-Device-Contract: 1"A revoked key answers 401 on its next call. Treat that as revoked and forget the key.
Commands#
Long-poll for commands the console queued. Store next_since and send it as since next time.
curl -X GET "$FOLIO_API_URL/v1/device/commands?since=0&wait=25" \
-H "Authorization: Bearer $FOLIO_DEVICE_KEY" \
-H "X-Folio-Device-Contract: 1"Kinds: sync_now (pull the library), update_available and revoke. Acknowledge each one; acknowledging revoke revokes the key.
curl -X POST "$FOLIO_API_URL/v1/device/commands/cmd_0192f7a8-3b1c-7d2e-9a40-5c6d7e8f9012/ack" \
-H "Authorization: Bearer $FOLIO_DEVICE_KEY" \
-H "X-Folio-Device-Contract: 1"Library sync#
Objects have a kind (song, theme, service_plan, service_record), a library-wide version and a per-object revision. Pull changes with since until more is false, and store next_since:
curl -X GET "$FOLIO_API_URL/v1/device/library/changes?since=400&limit=100" \
-H "Authorization: Bearer $FOLIO_DEVICE_KEY" \
-H "X-Folio-Device-Contract: 1"Push with the base_revision you last saw. If someone changed the object meanwhile, its result is a conflict that includes the current object: merge and retry that object. Deletes are tombstones (deleted: true).
Recordings#
The booth creates a teaching the same way an API key does, with the same plan checks, so it needs no second credential. Create the teaching, PUT the file to the returned URL, then complete it:
curl -X POST "$FOLIO_API_URL/v1/device/teachings" \
-H "Authorization: Bearer $FOLIO_DEVICE_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: booth-service-2026-11-01" \
-H "X-Folio-Device-Contract: 1" \
-d '{
"title": "Sunday service",
"filename": "service.mp4",
"content_type": "video/mp4"
}'Updates#
GET /v1/device/update?platform=windows¤t=1.4.2 returns the latest and minimum supported version and where to download. It works even when the contract header is too old, so a stale booth can learn where to update. The King James Version text pack is the only scripture pack.
Verified against API version 0.0.0-dev. Generated from the live OpenAPI document.