Authentication#
Every request to a versioned route (/api/v1/...) carries a Bearer credential
and accepts an optional API version header, except provider OAuth callback routes
that are reached by external provider redirects. The /health probes are
unauthenticated.
There are two ways to authenticate, both sent as Authorization: Bearer <...>:
| Method | How | Scope |
|---|---|---|
| Service API key | Authorization: Bearer <service-api-key> (API_KEY, or optional API_KEY_2), validated at the edge. |
Not organization-scoped. |
| User token | Authorization: Bearer <user-token> plus ?organization_id=<id>. The token + org are validated against the TeamBoost platform API; the request proceeds only if the user belongs to that organization. |
Scoped to the given organization. |
The Bearer credential is matched against the configured service keys first; if it
is not a service key, it is treated as a user token, which requires
organization_id.
| Header / param | Value | Notes |
|---|---|---|
Authorization |
Bearer <service-api-key> or Bearer <user-token> |
Required. |
organization_id (query) |
Organization id, e.g. 590789 |
Required for user tokens; ignored for service keys. |
X-Api-Version |
CalVer YYYY.M.MICRO, e.g. 2026.6.2 |
Optional — omit to use the latest supported version. |
# Service API key
curl https://<host>/api/v1/providers \
-H "Authorization: Bearer <service-api-key>"
# User token scoped to an organization
curl "https://<host>/api/v1/providers?organization_id=590789" \
-H "Authorization: Bearer <user-token>"
Authentication outcomes#
| Situation | Response |
|---|---|
| Valid service key | 200, request proceeds |
| Valid user token, member of the organization | 200, request proceeds (org-scoped) |
User token without organization_id |
400 missing_parameter |
Non-integer organization_id |
422 validation_error |
| Invalid / unrecognized credential | 401 invalid_api_key |
| Valid user token, not a member of the organization | 403 insufficient_permissions |
| TeamBoost platform API unreachable | 503 service_unavailable |
Version header behavior#
When X-Api-Version is omitted, the service uses the latest supported version.
Send an explicit version to pin client behavior across releases. A version below
the minimum or above the latest is rejected with 400 invalid_api_version.
On a successful authenticated request the response echoes the supported range:
X-Api-Latest-Version— newest version the service supportsX-Api-Minimum-Version— oldest version still accepted
Provider credentials
The Bearer auth above governs access to this service. It is separate from the per-provider credentials (e.g. a Linear API key) an organization stores for sync — those are encrypted at rest and managed via the credential endpoints; see the Linear page. OAuth-backed providers such as Basecamp, Google Calendar, and Zoho Projects use the OAuth install endpoints instead of direct token upload. Plane supports either direct PAT storage or bot OAuth installation. Their encrypted OAuth material uses the same credential store. Webhook secrets are planned — see the Roadmap.
OAuth callback exception
GET /api/v1/providers/{provider}/oauth/callback is unauthenticated so an
OAuth provider can redirect to it. The callback must include the signed,
expiring state returned by the authenticated authorization URL route; invalid
state returns invalid_oauth_state.
OAuth install callback contract#
Start an organization-scoped OAuth install with the generic authorization route:
GET /api/v1/providers/{provider}/oauth/authorize?organization_id=<id>
When a provider requires an account or workspace to be selected before consent,
also send targetAccountId (maximum 256 characters). The service signs that value
into the ten-minute OAuth state; callback requests cannot replace it. State is
signed, not encrypted, so the target id must not contain a secret.
Providers can redirect directly to the unauthenticated callback:
GET /api/v1/providers/{provider}/oauth/callback?state=<state>&code=<code>&location=<value>
The callback accepts one state, at most one code, and at most one error.
Code-based providers require code; structural providers can instead require
bounded provider callback parameters. For example, Plane's bot flow requires
exactly one app_installation_id and does not use the callback code. Up to 16
additional, single-valued provider callback parameters fit the shared envelope.
Parameter names are 1–128 ASCII letters, digits, dots, underscores, or hyphens;
values are 1–2048 characters. code, state, error, organization, and
target-account names are reserved. Duplicate, reserved, malformed, or oversized
values are rejected.
An authenticated frontend can relay the equivalent callback through POST:
{
"state": "<signed-state>",
"code": "<authorization-code>",
"callbackParameters": {
"location": "<provider-value>"
}
}
For a provider error, omit code and send error instead. For a structural
code-less callback such as Plane, omit both and send the provider's required
callbackParameters. The relay requires the same organization-scoped user token
used to start authorization; the organization must match signed state. Callback
codes, errors, and extra callback values are not returned, logged, or generically
persisted. Successful token payloads and provider refresh handles are encrypted
at rest, and callback responses contain credential metadata only.