Skip to main content
Orgo is multi-tenant. Every organization that uses Orgo gets its own isolated workspace — its own users, events, payments, contracts, files. Two organizations cannot see each other’s data, ever, even if a query is misconfigured. This page explains how the API knows which tenant a request is for, and what to do when the answer is wrong.

Tenant resolution: the Host header

The tenant is resolved from the HTTP Host header of the incoming request. Each organization has either a subdomain on orgo.space or a fully-custom domain:
There is no header, query parameter, or JWT claim that overrides this. The host is the tenant selector.
The OpenAPI spec lists https://app.orgo.space as the base URL only because the API playground needs some URL. For real requests, swap that for your tenant’s host.

Why this matters for tokens

Tokens are tenant-scoped at the moment they are issued:
  • Api-Token: tied to the user who created it; that user belongs to one tenant; the token only works against that tenant’s host.
  • JWT (from /login-check or /verify-login-otp): contains a session_id claim bound to the tenant of the host the login was performed against.
  • OAuth access tokens: bound to the tenant where the OAuth application was registered.
A token from tenant A cannot be used against tenant B. Trying produces 401 Unauthorized.

Cross-tenant access is blocked at the persistence layer

Inside Orgo’s backend, Doctrine extensions automatically add WHERE entity.tenant = current_tenant to every read. Even if a developer wrote SELECT * FROM users without a tenant filter, the extension would inject the filter before the query runs. This is enforced at the ORM level so no API endpoint can leak across tenants. The one exception is OTP-issued JWTs used by the event-app surface (members opening an event landing page from a different tenant they were invited to). Those JWTs carry an auth_strength: OTP claim and a verified_email instead of a session_id, and they can cross tenants but only for the event-attendance endpoints.

Resolving your tenant host

Every tenant admin can find their host in the admin UI under Settings → Organisation → Domains. Common shapes: The default subdomain always works, even when a custom domain is also configured. Use it for integrations to avoid breakage if the admin changes the custom-domain setup.

What happens when the tenant is missing or wrong

The 404 in the last row is intentional. From outside, “not found” and “exists in another tenant” are indistinguishable. This is the same pattern GitHub uses for private repos.

Tenant context in webhook deliveries

Webhook payloads carry a top-level tenant_id field so a single receiver subscribed to multiple tenants can route events. See Webhooks.

Common scenarios

Check that the host you are calling matches the tenant the token was issued for. The same token against the wrong host produces 401, not 403.
Generate one Api-Token per tenant (each from an admin user in that tenant) and route by hostname server-side. There is no “super-token” that crosses tenants.
Switch to the *.orgo.space default subdomain. It is permanent and never changes.
Yes — GET /api/v1/tenant-host/{slug} returns the current canonical host for a tenant slug. This endpoint is public (no auth needed).

  • Authentication — how tokens carry tenant scope
  • Errors — what each tenant-mismatch error looks like