Organizations & Workspaces
Overview
qr3.app uses a two-level hierarchy:
Organization (company/agency) └── Workspace 1 (Client A) └── Workspace 2 (Client B) └── Workspace 3 (Internal team)- Organization — top level, tied to a Stripe account and plan
- Workspace — isolated scope for QR codes, scans, and API keys
Organizations API
GET /v1/organizations
Returns the organization the current API key belongs to.
curl https://qr3.app/v1/organizations \ -H "Authorization: Bearer qr3_sk_..."billing_email, notification_email and stripe_customer_id are returned only to an org_admin and the organization owner, and to an API key created by an org_admin or the owner (checked on every request). Every other role and key gets the three fields as null. The same applies to GET /v1/organizations/:id.
GET /v1/organizations/usage
Returns the organization’s live usage against its plan limits — summed across all workspaces and computed live: scans for the current billing month (vs max_scans_per_month) and dynamic_codes, the count of active dynamic codes (vs max_dynamic_codes). Neither is blocked at the limit, so use this to power usage meters and upgrade prompts.
curl https://qr3.app/v1/organizations/usage \ -H "Authorization: Bearer qr3_sk_..."{ "data": { "scans": { "used": 4120, "limit": 5000, "usage_pct": 82, "remaining": 880, "period": "2026-06", "period_start": "2026-06-01T00:00:00.000Z" }, "dynamic_codes": { "used": 142, "limit": 500, "usage_pct": 28, "remaining": 358 } }}POST /v1/organizations
Creates a new organization. Only a person signed in to the dashboard can do this: they become the organization’s owner and get its first workspace with the org_admin role. Requests authenticated with an API key are rejected with 403, for every key type and before the body is checked — an API key is bound to its own workspace and would not reach the new organization. An invalid body gives 422 (errors/validation), a slug that is taken 409.
{ "name": "Digital Heroes Ltd", "slug": "digital-heroes"}PATCH /v1/organizations/:id
Updates the organization’s name, billing email and notification email.
Only an org_admin can change them, in a dashboard session. Requests authenticated with an API key are rejected with 403 — qr3_sk_ and qr3_test_sk_ keys included — so a leaked key cannot redirect the billing or notification address.
DELETE /v1/organizations/:id
Soft-deletes the organization and all associated workspaces.
Requires the org_admin role (dashboard session). Requests authenticated with a plain API key are rejected with 403 — API keys never carry an admin role, so a leaked key cannot delete the organization.
Workspaces API
GET /v1/workspaces
Lists the workspaces visible to the caller: org_admin and the organization owner see every workspace of the organization, other members only the workspaces they belong to, and an API key only its own workspace. A workspace the caller cannot see answers 404 on every /v1/workspaces/:id route, exactly like an unknown ID.
POST /v1/workspaces
curl -X POST https://qr3.app/v1/workspaces \ -H "Authorization: Bearer qr3_sk_..." \ -H "Content-Type: application/json" \ -d '{ "name": "Client A — Campaign Q2", "slug": "client-a-campaign-q2" }'With an API key, only a key created by an org_admin or the organization owner may create a workspace; every other key gets 403, before the slug is checked (so the answer does not reveal which slugs are taken). The creator’s role is checked on every request: a key loses the right when its creator is demoted. An API key is bound to its own workspace and does not see the new one afterwards: its id is in the 201 response; an org_admin opens it in the dashboard and can create a key for it there. In the dashboard, only an org_admin may create workspaces.
PATCH /v1/workspaces/:id
Update name, description, or settings.
DELETE /v1/workspaces/:id
Soft-deletes the workspace. Cannot delete the default workspace.
Requires org_admin, or ws_admin of the workspace being archived; other roles get 403. A workspace the caller cannot see answers 404 — for an API key that is every workspace except its own, which it cannot archive either.
The API keys of an archived workspace stop working: every request made with them gets 401.
Plan Limits
| Plan | Workspaces |
|---|---|
| Free | 1 |
| Pro | 1 |
| Business | 10 |
| Agency | 50 |
| Enterprise | 500 |
Audit logs
GET /v1/audit-logs lists audit events for the authenticated workspace, newest first and cursor-paginated.