Booth API
All under /booth, all bearer-keyed. List, pick, upload, complete. Photo bytes
go straight to R2 on a signed URL and never pass through this API.
The booth never creates a session and never names a guest: the kiosk does that, and the booth picks one already waiting on its set.
Walkthrough
Section titled “Walkthrough”-
Events and sets.
Terminal window curl -sS https://api.theloungebooth.com/booth/events \-H "Authorization: Bearer $BOOTH_API_KEY"{"events": [{"id": "7Kq2mZ0aBx91Tc","slug": "city-launch","name": "City Launch","startAt": 1758499200000,"endAt": null,"sets": [{ "id": "Rd8vN3pLw0Ymqe", "slug": "set-1", "name": "Set 1" },{ "id": "Jf4bQ7tHs2Xzvi", "slug": "set-2", "name": "Set 2" }]}]}Started, or starting within a day; not ended more than a day ago. Open-ended events stay listed. Ordered by start, then set name.
-
The queue.
Terminal window curl -sS https://api.theloungebooth.com/booth/sets/Rd8vN3pLw0Ymqe/sessions \-H "Authorization: Bearer $BOOTH_API_KEY"{"sessions": [{"id": "Mv6xC1kRp8Wdzn","label": "Alex and Sam","createdAt": 1758501330000,"guests": [{ "firstName": "Alex", "lastName": "Reyes" },{ "firstName": "Sam", "lastName": "Okafor" }]}]}Active only, oldest first.
labelis the gallery heading, already built from the first names. An unknown set id returns an empty list, not a 404. -
One signed PUT per photo.
Terminal window curl -sS -X POST \https://api.theloungebooth.com/booth/sessions/Mv6xC1kRp8Wdzn/uploads \-H "Authorization: Bearer $BOOTH_API_KEY"{"key": "sessions/Mv6xC1kRp8Wdzn/Zp3nT8wQ1eLk52.jpg","url": "https://<account>.r2.cloudflarestorage.com/tlb-photos/sessions/...&X-Amz-Expires=600","contentType": "image/jpeg","expiresIn": 600}No body. Each call mints its own key; reusing one overwrites the object. Ten minutes, so ask when you are ready to send the bytes.
-
PUT the bytes.
Terminal window curl -sS -X PUT "$url" \-H "Content-Type: image/jpeg" \--data-binary @frame-01.jpgContent-Typeis part of the signature: exactlyimage/jpeg, no charset, or R2 answers403and it reads like a broken signature. No bearer key here, different host. -
Complete.
Terminal window curl -sS -X POST \https://api.theloungebooth.com/booth/sessions/Mv6xC1kRp8Wdzn/complete \-H "Authorization: Bearer $BOOTH_API_KEY" \-H "Content-Type: application/json" \-d '{"photos": [{ "key": "sessions/Mv6xC1kRp8Wdzn/Zp3nT8wQ1eLk52.jpg", "width": 2048, "height": 2560 },{ "key": "sessions/Mv6xC1kRp8Wdzn/Hb9dK4sVu7Rm03.jpg", "width": 2048, "height": 2560 }]}'{"id": "Mv6xC1kRp8Wdzn","status": "completed","completedAt": 1758501902000,"photos": 2}Gallery order is array order. Every key is HEADed and checked against the session’s prefix before anything is written. One call per session, at the end: completing publishes the gallery and sends each guest their link on every channel they gave.
bytescomes from R2;widthandheightare yours, and the gallery lays out the grid from them.
Cancelling
Section titled “Cancelling”curl -sS -X POST \ https://api.theloungebooth.com/booth/sessions/Mv6xC1kRp8Wdzn/cancel \ -H "Authorization: Bearer $BOOTH_API_KEY"{ "id": "Mv6xC1kRp8Wdzn", "status": "cancelled" }Active sessions only, and the only undo: no retake, no reopening a completed session. The group re-registers at the kiosk, or staff add photos from admin.
Reference
Section titled “Reference”GET /booth/events
Section titled “GET /booth/events”200 { events: [{ id, slug, name, startAt, endAt, sets: [{ id, slug, name }] }] }.
endAt is null when open-ended. An event with no sets does not appear.
GET /booth/sets/:setId/sessions
Section titled “GET /booth/sets/:setId/sessions”200 { sessions: [{ id, label, createdAt, guests: [{ firstName, lastName }] }] }.
lastName can be empty: the kiosk takes one name field and splits on the first space.
POST /booth/sessions/:id/uploads
Section titled “POST /booth/sessions/:id/uploads”200 { key, url, contentType, expiresIn }
404 { "error": "no such session" }
409 { "error": "session is completed" } or "session is cancelled"
POST /booth/sessions/:id/complete
Section titled “POST /booth/sessions/:id/complete”{ photos: [{ key, width: int > 0, height: int > 0 }] }, 1–200 entries.
200 { id, status: "completed", completedAt, photos }
400 validation, see error shapes
404 { "error": "no such session" }
409 { "error": "session is completed" }, "session is cancelled", or { "error": "session completed concurrently" } when two completes race the status guard
422 { "error": "objects not found", "missing": ["sessions/…/….jpg"] } — key never uploaded, URL expired, or key from another session. Nothing was written; re-upload and call again.
Photos append after any staff already added.
POST /booth/sessions/:id/cancel
Section titled “POST /booth/sessions/:id/cancel”200 { id, status: "cancelled" }
404 { "error": "no active session with that id" }, including already completed or cancelled.
Retries
Section titled “Retries”/booth/* is not rate limited; the key is the control. Nothing is idempotent:
two uploads calls give two objects, a second complete gives a 409. A failed
PUT needs a fresh key and url, not a retry of the expired one.