Team API

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 for 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. To configure what a member can do on the device once assigned (restrictions, settings, scan behaviour), pair this with the Profiles API.

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, and it is important to keep them straight:

  • /api/teammember/* (singular): CRUD on a single team member (POST to create, PUT to update, DELETE to delete) plus assign / unassign event 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

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

  1. Team members: the single-record shape and CRUD.
  2. Listing & lookup: discovery across events / enterprise.
  3. Event assignments: link them to specific events.
  4. Check-in stats: per-member activity rollups.

For full request/response schemas + try-it, see the auto-generated API Reference.

Team API

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. A POST with a userName that already exists in your enterprise returns the existing record with 200 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 explicit password on create so you know what it is, or set one afterwards via the update endpoint below (send a password value).
  • 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. That keeps their id stable for stat history.

Where to next

Try it
POST/teammember PUT/teammember/update DELETE/teammember/delete POST/teammember/{teamMemberId}/unassign/{eventId}
Team API

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 is 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 is 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} narrows 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 works in 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, as 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

Try it
GET/teammembers GET/teammembers/all GET/teammembers/user/{username}/events
Team API

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. It is 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.

To control what they can do once they're on the event (lock settings, preset scan behaviour, cap or PIN-protect actions), assign them a Profile for the event. Assignment to the event (here) gates access; the profile gates capability.

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.
  • Profiles API: lock down and configure what an assigned member can do on the device.
Try it
GET/teammembers/event/assigned/{id} POST/teammember/{teamMemberId}/assign/{eventId}
Team API

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, with 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. admitted is a short time-of-day string (e.g. 14:30) at the start of a 5-minute window; admittedCount is 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 rather than polling. Each admission fires an event carrying the team member who scanned.

For a single team member's events list, use the inverse-lookup endpoint in Listing & lookup instead, as it's lighter.

Where to next

Try it
GET/team/event/{id}
Team API

API Reference

Interactive reference for the Team surface: adding and managing team members who operate an event.