Skip to content

Operator & team

Endpoints for your operator account and the people who work in it: read and update the operator record, manage your billing and correspondence contacts, define roles with a permission grid, and create portal users. These are client-role, operator-scoped endpoints; each is gated by a specific permission (for example operators.settings:write, users.roles:write, users.table:write).

Method Path Purpose Auth
GET /api/my-operator Read the operator record operator
PUT /api/my-operator Update the operator record operator
GET /api/client/dashboard Portal bootstrap aggregate operator
GET /api/me/permissions Your effective permissions + catalogue session
GET /api/my-operator/members List billing & correspondence contacts operator
GET /api/my-operator/users-search Search users to link to a contact operator
POST /api/my-operator/members Add a contact operator
PUT /api/my-operator/members/:id Update a contact operator
DELETE /api/my-operator/members/:id Remove a contact operator
GET /api/my-roles List roles operator
GET /api/my-roles/:id Read a role + its permission grid operator
POST /api/my-roles Create a role operator
PUT /api/my-roles/:id Update a role, permissions and venues operator
DELETE /api/my-roles/:id Delete a role operator
GET /api/my-users List portal users operator
POST /api/my-users Create a portal user operator
PUT /api/my-users/:id Update a user operator
DELETE /api/my-users/:id Delete a user operator
POST /api/my-users/:id/resend-invite Re-send a pending user invite operator

GET /api/my-operator reads your company record; PUT updates it (name is required).

Terminal window
curl -X PUT "https://thesidedoor.co/api/my-operator" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Acme Hospitality","company_name":"Acme Ltd","company_reg":"12345678","vat_number":"GB123456789"}'
{ "success": true }

GET /api/client/dashboard returns the aggregate the client portal loads on sign-in: the operator, your permissions, payout status, headline stats and your venues.

Terminal window
curl "https://thesidedoor.co/api/client/dashboard" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"operator": { "id": "op_1", "name": "Acme Hospitality", "status": "active", "stripe_connect_status": "enabled" },
"payout_status": { "provider": "stripe", "status": "enabled", "source": "cached" },
"stats": { "venues": 3, "total_guests": 4200, "month_guests": 380, "revenue": 0 },
"staff_summary": { "count": 6 },
"venues": [{ "id": "ven_123", "name": "The Attic", "status": "live" }]
}

GET /api/me/permissions returns your effective permission map plus the permission catalogue (tree) used to build a role grid. It supports If-None-Match/ETag for a 304.

Terminal window
curl "https://thesidedoor.co/api/me/permissions" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"role": "client",
"portal": "client",
"permissions": { "bookings.table": { "read": true, "write": false } },
"tree": [
{ "key": "bookings", "label": "Guest list", "actions": [], "children": [
{ "key": "bookings.table", "label": "Guest list", "actions": ["read"] },
{ "key": "bookings.booking", "label": "Guest list detail", "actions": ["read", "write"] }
] },
{ "key": "users", "label": "Access", "actions": [], "children": [
{ "key": "users.table", "label": "Users", "actions": ["write"] },
{ "key": "users.roles", "label": "Roles", "actions": ["write"] }
] }
]
}

These /members endpoints manage your operator’s billing and correspondence contacts, the people we email about invoices, account matters and general correspondence. They are contact details only: they do not grant any access to the platform. To add someone who actually signs into the portal, create a portal user with POST /api/my-users instead.

Each contact has a type (one of billing, primary, technical or general, defaulting to general), a name and a required, valid email. You may pass an optional user_id to link an existing account user, which fills in the name and email from that user if you leave them blank. GET /api/my-operator/users-search?q= finds candidate users to link, then POST /api/my-operator/members adds the contact.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-operator/members" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"billing","name":"Acme Accounts","email":"accounts@example.com","user_id":"usr_abc"}'
{ "success": true, "id": "oc_9f2a..." }

Update a contact’s type, name and email with PUT /api/my-operator/members/:id, or remove it with DELETE /api/my-operator/members/:id; both return { "success": true }.

A role is created with a name and description, then its permission grid and venue scope are set with PUT. Create a role first:

Terminal window
curl -X POST "https://thesidedoor.co/api/my-roles" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Front of House","description":"FOH staff"}'
{ "success": true, "id": "role_7f3" }

PUT /api/my-roles/:id replaces the permission grid and venue scope. Each grid row is { permission_key, can_read, can_write } - pull the available keys from the tree in /api/me/permissions. An empty or omitted venue_ids means all account venues.

Terminal window
curl -X PUT "https://thesidedoor.co/api/my-roles/ROLE_ID" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Front of House",
"permissions": [
{ "permission_key": "bookings.table", "can_read": true, "can_write": false },
{ "permission_key": "guests.table", "can_read": true, "can_write": false }
],
"venue_ids": ["VENUE_ID"]
}'
{ "success": true }

GET /api/my-roles/:id returns the stored grid as permissions and the scoped venue_ids; DELETE /api/my-roles/:id removes a role. A role can’t be deleted while it’s a system role or one of the account’s default roles.

Portal users sign in and are assigned exactly one role. POST /api/my-users takes name, email, a role_id that belongs to your account, and an optional phone - no password: the new user gets an emailed invite and sets their own password when they accept it.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-users" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Jane Doe","email":"jane@example.com","role_id":"ROLE_ID","phone":"+44..."}'
{ "success": true, "invited": true }

PUT /api/my-users/:id accepts any subset of name, email, password, phone and role_id (a new password is only set when non-empty, and sets it directly rather than sending an invite); DELETE /api/my-users/:id removes a user (you cannot delete yourself). Both return { "success": true }.

POST /api/my-users/:id/resend-invite sends a fresh invite email to a user who hasn’t yet accepted theirs - it mints a new link (superseding the old one) and re-sends it. It only works while the user is still pending; a user who has already accepted returns a 400.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-users/USER_ID/resend-invite" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{ "success": true }