Skip to content

Organization API

העתקת עמוד

The key-authenticated /api/v1/org/* API for servers and SDKs acting as the whole organization: list/create/revoke any pass, list facilities, and read the member directory. Scopes org:passes:*, org:facilities:read and org:members:*.

עודכן

The organization API is the server-to-server data plane: endpoints for a backend or SDK acting as the whole organization rather than a single signed-in user. Authenticate with an organization API key and org:* scopes.

Base: https://entrybit.net · Auth: Authorization: Bearer eb_sk_… (or X-API-Key) · see Authenticating requests.

It mirrors the user-delegated passes API, but organization-wide: it lists and revokes any pass in the company, adds a facilities endpoint SDKs need to create passes, and exposes a read-only member directory (who is in the organization). Everything stays tenant-scoped — a key only ever touches its own organization’s data.

List all passes

GET /api/v1/org/passes?limit&cursor&search

Scope: org:passes:read. Every non-deleted pass in the organization, keyset-paginated newest first. Rows include created_by (the inviting user’s id) for attribution.

Parameters: limit (1–100, default 30), cursor, search — see pagination.

curl "https://entrybit.net/api/v1/org/passes?limit=50" \
  -H "Authorization: Bearer $ENTRYBIT_API_KEY"
{
  "success": true,
  "items": [
    { "public_id": "gst_9f1c…", "first_name": "Dana", "status": "checked_in", "arrival_date": "2026-07-12", "facility_name": "North Gate", "created_by": 90210 }
  ],
  "total": 340,
  "next_cursor": "eyJpZCI6…",
  "has_more": true
}

The Pass object is identical to the user-delegated API. (The usage allowance block is a user-delegated concept and does not appear here.)

Create pass(es)

POST /api/v1/org/passes
Content-Type: application/json

Scope: org:passes:write. Creates 1–10 passes with the same request body, validation, quota, QR and delivery as POST /api/v1/passes. Attribution and the invite quota go to the admin who minted the key.

curl -X POST https://entrybit.net/api/v1/org/passes \
  -H "Authorization: Bearer $ENTRYBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Dana",
    "email": "dana@example.com",
    "arrival_date": "2026-07-12",
    "facility_id": 42,
    "quantity": 1
  }'

Returns 201 with the same PassCreateResponse shape (public_id, qr_values, pass_link, qr_sent, sms_sent, …). Errors: 400 validation, 402 quota, 404 facility not found, 409 facility deactivated or suspended.

Revoke any pass

DELETE /api/v1/org/passes/{public_id}

Scope: org:passes:write. Cancels the pass and deactivates its QR credential — regardless of which user created it (still scoped to the key’s organization).

{ "success": true, "public_id": "gst_9f1c2ab34cd56ef7", "revoked": true }

Returns 409 when the pass is no longer active, 404 when no such pass exists in the organization.

List facilities

GET /api/v1/org/facilities

Scope: org:facilities:read. The facility ids an SDK needs before it can create passes.

curl https://entrybit.net/api/v1/org/facilities \
  -H "Authorization: Bearer $ENTRYBIT_API_KEY"
{
  "success": true,
  "facilities": [
    { "id": 42, "name": "North Gate", "description": null, "is_active": true, "suspended": false }
  ]
}

The Facility object

FieldTypeNotes
idintegerUse as facility_id when creating passes.
namestring
descriptionstring | null
is_activeboolean
suspendedbooleanSuspended facilities pause new invites.

List members

GET /api/v1/org/members?limit&cursor&search&fields&status

Scope: org:members:read — plus org:members:contact:read to read contact fields. The organization’s member directory, keyset-paginated newest first. Active members only by default — pass status=inactive or status=all to include deactivated members. Guest shadow rows never appear.

Parameters: limit (1–100, default 30), cursor — see pagination; search — case-insensitive match on the member’s name (and on email/phone when the credential carries the contact scope); fields — a comma-separated subset of the Member object (see field selection); statusactive (default), inactive, or all.

curl "https://entrybit.net/api/v1/org/members?limit=50&fields=id,name,job_title,email" \
  -H "Authorization: Bearer $ENTRYBIT_API_KEY"
{
  "success": true,
  "items": [
    { "id": "emp_7b2d1ac98ef04c35", "name": "Dana Cohen", "job_title": "Facilities Manager", "email": "dana@example.com" }
  ],
  "total": 87,
  "next_cursor": "eyJpZCI6…",
  "has_more": true
}

Get a member

GET /api/v1/org/members/{public_id}

Scope: org:members:read. One member by public id (emp_…) — 404 when no such member exists in the organization. Deactivated members are returned here (with "status": "inactive") — their id stays addressable, Directory-style. Accepts the same fields parameter.

{ "success": true, "member": { "id": "emp_7b2d1ac98ef04c35", "name": "Dana Cohen", "first_name": "Dana", "last_name": "Cohen", "job_title": "Facilities Manager", "department": "Operations", "status": "active", "created_at": "2026-05-19T09:30:00" } }

The Member object

FieldTierTypeNotes
idbasicstringPublic identifier, e.g. emp_7b2d1ac98ef04c35.
namebasicstringDisplay name (first + last).
first_namebasicstring
last_namebasicstring
job_titlebasicstring | null
departmentbasicstring | nullThe department’s display name.
statusbasicstringactive or inactive.
created_atbasicstring | null
emailcontactstring | nullRequires org:members:contact:read.
phonecontactstring | nullRequires org:members:contact:read.

Contact fields are stored encrypted at rest and decrypted server-side only when the credential carries the contact scope. The API never returns credential material, photo URLs, or internal indexes.

Field selection and tiers

Graph-style sparse fieldsets: pass fields as a comma-separated subset of the table above. Omit it and you get every field your credential’s tier allows — the basic tier with org:members:read, plus the contact tier when the key also carries org:members:contact:read.

  • An unknown field returns 400, and the message lists the allowed fields.
  • A contact field on a basic-only key returns 403 insufficient_scope, and the challenge names the missing scope:
# Key carries org:members:read only — email is a contact-tier field
curl "https://entrybit.net/api/v1/org/members?fields=id,name,email" \
  -H "Authorization: Bearer $ENTRYBIT_API_KEY"
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer error="insufficient_scope", scope="org:members:contact:read"

{ "error": "insufficient_scope" }

Signed-in access — the members:read scope

Both member endpoints also accept a user-delegated OAuth access token carrying the members:read scope — for apps a member signs into that need the directory without a server-side key. The call is then double-gated: the token must carry the scope and the signed-in user must still hold the organization’s employee-view role — a removed user cannot keep reading the directory through an old grant. The response is scoped to the user’s own organization, and members:read unlocks the full field set (the user’s role already grants the in-app member list).

Scope summary

EndpointScope
GET /api/v1/org/passesorg:passes:read
POST /api/v1/org/passesorg:passes:write
DELETE /api/v1/org/passes/{public_id}org:passes:write
GET /api/v1/org/facilitiesorg:facilities:read
GET /api/v1/org/membersorg:members:read (+ org:members:contact:read for contact fields)
GET /api/v1/org/members/{public_id}org:members:read (+ org:members:contact:read for contact fields)

Auth failures (401/403/429) follow the API-key challenge rules; business errors follow the error catalog.