Cross-Account API Access
By default, an API token is bound to exactly one tenant — the workspace it was created in — and that binding is immutable. This page describes the one supported way to act on other sub-accounts from a single token: the tenants:manage grant combined with the X-Tenant-ID header.
This is what lets a platform partner drive dozens of customer workspaces from one credential, without logging into each one.
How it works
- A billing-account owner creates an API token in their home tenant and attaches the special
tenants:managescope. - On any request, the token may include an
X-Tenant-ID: <target_tenant_id>header. - If the target tenant belongs to the same billing account as the token's home tenant, the request is executed against the target tenant. The token's other scopes (e.g.
webhooks:create,channels:create) are what actually authorize the action there. - If the target tenant is in a different billing account — or doesn't exist — the request is rejected with
403.
Parent token (home = Tenant A, scopes: tenants:manage + webhooks:create)
│
├─ POST /webhook-endpoints → acts on Tenant A (home)
├─ POST /webhook-endpoints X-Tenant-ID: B → acts on Tenant B ✅ (same billing account)
└─ POST /webhook-endpoints X-Tenant-ID: Z → 403 ❌ (different billing account)
Without the tenants:manage grant, the X-Tenant-ID header is ignored for API tokens (the request stays on the token's home tenant) — exactly as before. Cross-tenant access is strictly opt-in, per token and per request.
Step 1 — Create a parent token with tenants:manage
The tenants:manage scope can only be attached by a verified owner of the billing account that owns the token's home tenant. A regular tenant admin — even one with *:* — cannot grant it to themselves.
curl -X POST "https://api.sendseven.com/api/v1/api-tokens" \
-H "Authorization: Bearer <billing_account_owner_credential>" \
-H "Content-Type: application/json" \
-d '{
"name": "Platform parent token",
"scopes": [
"tenants:manage",
"webhooks:create",
"webhooks:read",
"channels:create",
"channels:read",
"contacts:create"
]
}'
Grant the token whichever action scopes you need it to exercise across your sub-accounts, alongside tenants:manage. The plaintext token (s7_api_…) is returned once — store it securely.
- Only a billing-account owner can create a token carrying
tenants:manage. The request is403otherwise. - The grant is matched by its exact literal string. A wildcard scope such as
*:*does not implytenants:manage— it must be listed explicitly.
Step 2 — Act on a sub-account with X-Tenant-ID
Send any normal API request with the parent token and add the X-Tenant-ID header naming the sub-account:
curl -X GET "https://api.sendseven.com/api/v1/channels" \
-H "Authorization: Bearer s7_api_PARENT_TOKEN" \
-H "X-Tenant-ID: tenant_acme_123"
The response contains Tenant B's channels. The same pattern works for any tenant-scoped endpoint — contacts, conversations, campaigns, channels, webhooks — with no per-endpoint change.
Registering webhooks for a sub-account
A common workflow: right after creating a sub-account, register your webhook endpoint into it so you start receiving its events.
curl -X POST "https://api.sendseven.com/api/v1/webhook-endpoints" \
-H "Authorization: Bearer s7_api_PARENT_TOKEN" \
-H "X-Tenant-ID: tenant_acme_123" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme events → our platform",
"url": "https://yourapp.com/webhooks/acme",
"subscribed_events": [
"message.received",
"conversation.created",
"channel.created",
"channel.updated"
]
}'
The webhook is created inside Tenant B. Subscribing to channel.* events here means you'll be notified when that customer connects a channel or one of their channels goes offline — ideal when paired with channel connect links.
Every webhook delivery envelope includes tenant_id, so a single receiving endpoint can serve many sub-accounts and route each event by its tenant. You can also register a distinct URL per sub-account, as above.
Managing channels for a sub-account
channels:create on the parent token plus X-Tenant-ID lets you generate channel connect links, list channels, and manage them for that sub-account:
curl -X POST "https://api.sendseven.com/api/v1/channel-connect-tokens" \
-H "Authorization: Bearer s7_api_PARENT_TOKEN" \
-H "X-Tenant-ID: tenant_acme_123" \
-H "Content-Type: application/json" \
-d '{"allowed_channel_types": ["whatsapp", "telegram"], "max_uses": 1}'
The resulting connect link onboards the channel into Tenant B.
What a parent token CAN and CANNOT do
CAN
- Act on any sub-account that shares its billing account, selected per-request via
X-Tenant-ID. - Exercise, on that sub-account, whatever action scopes it carries (create webhooks, connect links, contacts, read data, …).
- Serve many sub-accounts from one credential — no per-workspace login.
CANNOT
- Touch a tenant in a different billing account — always
403, with no disclosure of whether that tenant exists. - Perform an action whose scope it lacks —
tenants:managegrants reach, not permissions. A token with onlytenants:manageand nowebhooks:createis403when it tries to create a webhook. - Be created by a non-owner of the billing account.
- Be enabled via a wildcard — the literal
tenants:manageis required. - Switch tenants silently — omit the header and the token always acts on its home tenant.
Security model
- Same-billing-account only. The override verifies, on every request, that the target tenant's
billing_account_idmatches the token's home tenant's. This is checked live, so if a tenant is later moved out of your billing account, the token immediately loses access to it. - Owner-gated at creation. Only billing-account owners can mint a
tenants:managetoken, so the blast radius is limited to accounts you already own. - Scopes still apply per action. Reaching a sub-account does not bypass scope checks — the token's own scopes are enforced against every action.
- Blocked/suspended sub-accounts stay blocked. Account-block, deactivation, and billing gates are evaluated against the resolved (target) tenant. A parent token cannot act on a suspended sub-account.
tenants:manage token as highly privilegedIt can reach every workspace in your billing account. Store it like a master credential, scope it to only the action scopes you need, rotate it regularly, and revoke it immediately if exposed.
Not available to OAuth apps
Cross-account access is API-token only. OAuth access tokens can never carry tenants:manage — it cannot be requested by an OAuth app or granted at consent. This keeps the capability tied to an explicit, billing-account-owner-issued API token. If you're building an OAuth integration that needs to operate across sub-accounts, use a tenants:manage API token for the cross-account operations.
Next steps
- Channel Connect Links — onboard customer channels into any sub-account
- Webhook Events Reference — including the
channel.*lifecycle events - Authentication — API token basics and scopes