Skip to content

Business API

Business API

Read a business’s data over the same GraphQL the Sessions app uses, authenticated with a server-to-server API key instead of a user session. The key is scoped to one business and sees a deliberately narrow, read-only slice of the schema.

AuthAPI keyAccessRead-only
Endpoint
https://business.sessions.website/@<handle>/api/graphql
Access
Read-only
Scope
Per key
Rate limit
Per key & business

How you call it

This API speaks GraphQL — you send a query for exactly the fields you want and get JSON back in the same shape, all over a single endpoint. New to GraphQL? The official documentation is the best place to start.

endpoint
https://business.sessions.website/@<handle>/api/graphql

Authentication

There’s no user session — a scoped API key authenticates the request on its own, sent as a Bearer token over HTTPS.

bash
curl https://business.sessions.website/@<handle>/api/graphql \
  -H 'Authorization: Bearer sk_live_…' \
  --data '{"query":"{ activeBusiness { id } }"}'

Pagination

List fields use cursor pagination — pass first and an optional after cursor; each connection returns a pageInfo with hasNextPage and endCursor.

query
query {
  activeBusiness {
    participants(first: 25, after: "<cursor>") {
      nodes { id }
      pageInfo { hasNextPage endCursor }
    }
  }
}

The read surface

Enter through activeBusiness, which resolves to the key’s own business, then traverse into participants and — from each participant — their registrations and purchases.

The surface is default-deny: only the fields shown here are reachable with a key. Anything else — internal columns, cross-area data, every mutation — returns a FORBIDDEN error, so the API can never widen by accident.
query
query {
  activeBusiness {
    id
    name
    participants(first: 25) {
      nodes {
        id
        name
        email
        emailMarketingConsent { status at }
        registrations(first: 10) {
          nodes { id status confirmedAt activitySession { id } }
        }
        productPurchases(first: 10) {
          nodes { id status pricePaid purchasedAt product { id } }
        }
      }
    }
  }
}
200 response
{
  "data": {
    "activeBusiness": {
      "id": "gid://Sessions/Business/biz_3f9a",
      "name": "Tremble Studios",
      "participants": {
        "nodes": [
          {
            "id": "gid://Sessions/BusinessParticipant/p_91ac",
            "name": "Jordan Vega",
            "email": "jordan@example.com",
            "emailMarketingConsent": {"status": "granted", "at": "2026-06-01T14:32:08.000Z"},
            "registrations": {
              "nodes": [
                {
                  "id": "gid://Sessions/ActivityRegistration/reg_77b2",
                  "status": "confirmed",
                  "confirmedAt": "2026-05-28T18:00:00.000Z",
                  "activitySession": {"id": "gid://Sessions/ActivitySession/s_4c10"}
                }
              ]
            },
            "productPurchases": {"nodes": []}
          }
        ]
      }
    }
  }
}

Rate limits

Requests are capped per key and, in aggregate, per business, so one client can’t starve the others and a business can’t multiply its budget by minting more keys.

Over the limit returns HTTP 429 with a Retry-After header (in seconds). Back off for that long, then retry.

Errors

Errors come back in the standard GraphQL errors array. Each carries a machine-readable code in its extensions.

FORBIDDEN — the key lacks the scope, or the field isn’t exposed externally. RATE_LIMITED — you’re over a rate limit; honour Retry-After.

error
{
  "errors": [
    {
      "message": "You do not have permission to access this field.",
      "extensions": { "code": "FORBIDDEN" }
    }
  ]
}

Explore the types

The Business API reference lists every type and field a key can read, with the scope each one needs — generated straight from the live access policy, so it always matches what the API enforces.