Team API — Overview
Add and manage the team members who operate your events — door staff, back-of-house, and assigning them per-event access.
The Team API is the admin layer — granting and revoking event access for staff. Typical integrators don't touch this often: once team is set up, day-to-day operations run via Guests and Comms. But when you onboard new venue staff, transition a member off, or want to see how many guests someone checked in, this is the surface.
URL pattern
All endpoints on this page live under:
https://api.qflowhub.io/checkin/v1/api/<endpoint>
Two route conventions live side by side on this controller — important to keep straight:
/api/teammember/*(singular) — CRUD on a single team member (POSTto create,PUTto update,DELETEto delete) plusassign/unassignevent linkage./api/teammembers/*(plural) — listing / lookup of one or more team members across events or your enterprise.
Plus one stat-rollup endpoint under a different prefix: /api/team/event/{eventId} for per-team-member check-in counts on a specific event.
Every request needs both an OAuth bearer token AND an Ocp-Apim-Subscription-Key header — see Authentication.
What it does
Team members
Create, update, delete team members — the CRUD layer for staff who'll log into the check-in app.
Listing & lookup
Across events, across your enterprise, per-event roster, or events one member is assigned to.
Event assignments
Link / unlink a team member to / from a specific event — the gate on what staff can see in the app.
Check-in stats
Per-team-member check-in counts on one event + 5-minute arrival-curve buckets.
Quick start — onboard one team member end-to-end
Create the team member:
curl -X POST 'https://api.qflowhub.io/checkin/v1/api/teammember' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>' \
-H 'Content-Type: application/json' \
-d '{
"userName": "kelly.door",
"email": "kelly@example.com",
"firstName": "Kelly",
"lastName": "Door"
}'
Save the returned id, then assign them to an event:
curl -X POST 'https://api.qflowhub.io/checkin/v1/api/teammember/<teamMemberId>/assign/<eventId>' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>'
They can now log into the Qflow check-in app and scan guests at that event.
Read in this order
- Team members — the single-record shape and CRUD.
- Listing & lookup — discovery across events / enterprise.
- Event assignments — link them to specific events.
- Check-in stats — per-member activity rollups.
For full request/response schemas + try-it, see the auto-generated API Reference.
Team members
Create, update, and delete team-member records. The CRUD layer for the staff who'll log into the check-in app at the door.
The shape of a team member
Every team member has a userName, an email, and an id. Names (firstName / lastName) and password are optional.
Usernames are lowercased and trimmed. On enterprise accounts they're also namespaced — stored as <enterprise>/<userName> server-side (standalone accounts keep the bare username). Emails are lowercased and trimmed too.
Creating a team member
POST /api/teammember. Required: userName and email. Server returns the persisted record (id, email, userName, firstName, lastName).
curl -X POST 'https://api.qflowhub.io/checkin/v1/api/teammember' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>' \
-H 'Content-Type: application/json' \
-d '{
"userName": "kelly.door",
"email": "kelly@example.com",
"firstName": "Kelly",
"lastName": "Door",
"password": "ChangeMe-9182"
}'
A few notes:
- Duplicate username is idempotent, not an error —
POSTwith auserNamethat already exists in your enterprise returns the existing record with200 OK. Safe to re-call on retry. - Password handling — if you omit
password(or pass empty), the server generates one but does not return it in the response. There's no "show me the password" endpoint either. Practical implication: always pass an explicitpasswordon create so you know what it is, or set one afterwards via the update endpoint below (send apasswordvalue). - Email is just a label here — Qflow doesn't send a welcome / verification email automatically. If you want one, send it yourself via the Comms API using a template you author.
Updating a team member
PUT /api/teammember/update updates editable fields on an existing member. Send the full record (the server uses what you send to replace what's there). The id is required.
curl -X PUT 'https://api.qflowhub.io/checkin/v1/api/teammember/update' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>' \
-H 'Content-Type: application/json' \
-d '{
"id": "<teamMemberId>",
"userName": "kelly.door",
"email": "kelly.new@example.com",
"firstName": "Kelly",
"lastName": "Door"
}'
To change the password, include a new value in the body. Omit / blank password to leave it untouched.
Deleting a team member
DELETE /api/teammember/delete removes the team member entirely — including their event assignments. Deletion is permanent; to bring someone back you'd re-create them + re-assign their events.
curl -X DELETE 'https://api.qflowhub.io/checkin/v1/api/teammember/delete' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>' \
-H 'Content-Type: application/json' \
-d '{ "id": "<teamMemberId>" }'
If you might want them back later (seasonal staff, recurring contractors), prefer unassigning them from active events via Event assignments rather than deleting — keeps their id stable for stat history.
Where to next
- Listing & lookup — find existing members.
- Event assignments — link them to specific events.
- Check-in stats — see what they've done.
Listing & lookup
Four read endpoints — across events, across your whole enterprise, scoped to one event, or scoped to one member's events.
Four read shapes
The Team API has four list endpoints, each scoped differently:
/api/teammembers— members across every event you own (you're the event's primary user)./api/teammembers/all— every member in your enterprise, regardless of who owns the events they're assigned to. Useful for enterprise admins; ignored for non-enterprise accounts./api/teammembers/event/assigned/{eventId}— members assigned to one specific event./api/teammembers/user/{username}/events— events one team member is assigned to (inverse lookup).
All members across your events
GET /api/teammembers — the most common read. Returns every team member who's assigned to any event you own.
curl 'https://api.qflowhub.io/checkin/v1/api/teammembers' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>'
Deduplicates — a member assigned to multiple events appears once. Good for "give me everyone I might want to manage".
All members in your enterprise
GET /api/teammembers/all — the enterprise-wide variant. Returns every team member in your enterprise namespace, including those assigned to events owned by other users in the same enterprise.
curl 'https://api.qflowhub.io/checkin/v1/api/teammembers/all' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>'
Enterprise accounts only. Calling this on a non-enterprise (standalone) account returns 502 Bad Gateway — not a fallback. Use /api/teammembers (above) for standalone accounts.
Members assigned to one event
GET /api/teammembers/event/assigned/{eventId} — narrow the list to a single event's roster. Use for door-side displays ("who's working tonight?").
curl 'https://api.qflowhub.io/checkin/v1/api/teammembers/event/assigned/<eventId>' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>'
Returns 200 with an empty array if the event has no team assigned, doesn't exist, or you don't have access. No 404 and no ownership check — pass an unknown / unauthorised eventId and you'll get the same empty-array response as a real-but-empty event. Validate the eventId on your side if telling those apart matters.
Events one member is assigned to
GET /api/teammembers/user/{username}/events — the inverse direction. Given a team member's username, list every event they're currently assigned to.
curl 'https://api.qflowhub.io/checkin/v1/api/teammembers/user/<username>/events' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>'
Use the Enterprise-namespaced username — what you'd see in the response from any of the list endpoints above (typically <enterprise>/<member>), not the bare value you passed at create time.
Where to next
- Team members — drill into the single-record shape.
- Event assignments — link / unlink to specific events.
Event assignments
Link or unlink a team member to a specific event — the gating mechanism that controls who can scan guests where.
Concept
A team member only has access to events they're explicitly assigned to. Creating the team member just makes the record; until you assign them to an event, they won't see anything in the check-in app.
Two symmetric endpoints — both take teamMemberId and eventId in the URL, no body.
Assigning a team member
POST /api/teammember/{teamMemberId}/assign/{eventId} grants access. Idempotent — calling on an already-assigned member returns success without duplicating the link.
curl -X POST 'https://api.qflowhub.io/checkin/v1/api/teammember/<teamMemberId>/assign/<eventId>' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>'
After this call, the team member can sign into the Qflow check-in app and operate on that event's attendees (look up, admit, etc.). Other events stay invisible to them.
Pass ?notifyTeamMember=true to email the member a welcome with the event details and app download links; omit it (or send false) to assign silently.
Returns 400 Bad Request if either id is missing / malformed / unknown, or if you don't own the event. (The shape's a little blunter than 404 would be — but the failure path is the same either way: assignment didn't happen.) Symmetric for unassign below.
Unassigning a team member
POST /api/teammember/{teamMemberId}/unassign/{eventId} revokes access. Existing check-in history is preserved (so stats still attribute past scans to them); they just lose access to do more.
curl -X POST 'https://api.qflowhub.io/checkin/v1/api/teammember/<teamMemberId>/unassign/<eventId>' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>'
Idempotent — calling on an already-unassigned member is a no-op.
Bulk operations?
There's no bulk-assign endpoint. For onboarding multiple staff to one event (or one staff member to multiple events), loop the single-assign call client-side — the calls are inexpensive and idempotent, with no rate-limit concerns at typical onboarding volumes.
Where to next
- Team members — create the member first.
- Listing & lookup — verify the assignment landed via the per-event or per-user list endpoints.
- Check-in stats — see what they've been doing once they're working.
Check-in stats
Per-team-member check-in and check-out counts for one event, plus 5-minute time-slice activity for an arrivals curve.
Concept
The stats endpoint returns one row per team member assigned to the event, each with their checkedIn count, checkedOut count, and a checkedInActivity array of 5-minute time slices. It's what powers the "who scanned how many" leaderboard and the arrivals-rate chart in the dashboard.
Stats are computed live on each call — no cache. Inexpensive for events under ~10k attendees; the cost grows with attendee count above that.
Reading the stats
GET /api/team/event/{eventId} — note the different URL prefix from everything else on this page (/api/team/ not /api/teammember/ or /api/teammembers/).
curl 'https://api.qflowhub.io/checkin/v1/api/team/event/<eventId>' \
-H 'Authorization: Bearer <access_token>' \
-H 'Ocp-Apim-Subscription-Key: <subscription_key>'
Returns an array — one entry per team member assigned to the event (including those with no check-ins yet). Each entry includes:
teamMemberId/username— who.checkedIn— how many attendees they've admitted.checkedOut— present on the response schema but not populated server-side today. Treat as zero / ignore until the server-side rollup ships.checkedInActivity— array of{admitted, admittedCount}time-slice buckets.admittedis a short time-of-day string (e.g.14:30) at the start of a 5-minute window;admittedCountis how many scans happened in it.
Time-slice arrival curves
checkedInActivity is shaped specifically to drive an arrivals-rate chart. Each 5-minute bucket has a start time and a count — plot time on X and count on Y and you get the venue's arrivals curve over time.
Empty buckets (no scans in a 5-minute window) are not included — interpolate gaps client-side if you want a continuous timeline. The admitted value is a time-of-day only (no date), so it's intended for plotting a single event's curve.
Polling considerations
The endpoint is inexpensive to poll on small events but scales with the attendee count of the event. Sensible bounds:
- Under 1,000 attendees: polling once a second is fine.
- 1,000–10,000: every 3–5 seconds keeps the chart responsive without excessive load.
- 10,000+: prefer driving the chart from the check-in webhook — each admission fires an event carrying the team member who scanned — rather than polling.
For a single team member's events list, use the inverse-lookup endpoint in Listing & lookup instead — that's lighter.
Where to next
- Event assignments — only assigned members appear in the stats.
- Listing & lookup — find who's assigned before slicing their numbers.
API Reference
Interactive reference for the Team surface — adding and managing team members who operate an event.