Single sign-on
Mint a short-lived redirect that lands a web-host user in their dashboard, already logged in. Send their browser to it — mint a fresh token on every click.
https://api.swarmz.net/functions/v1/platform-ssoMaps to WHMCS ServiceSingleSignOn. Mints a short-lived WHU JWT (signed with the project's JWT secret so PostgREST accepts it natively) and returns a redirectTo URL that lands the customer in their dashboard, already logged in. Take the returned URL and send the customer's browser there with a 302. The token is embedded in the URL and is consumed on landing.
Address the tenant by tenant_id — the id returned by create — or fall back to your external_ref. Supply exactly one identifier.
Parameters
Prop
Type
Request
curl -X POST https://api.swarmz.net/functions/v1/platform-sso \
-H "Authorization: Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "aa7d7fae-0386-4d8a-b977-72f856eac242",
"ttl_seconds": 1036800
}'const res = await fetch('https://api.swarmz.net/functions/v1/platform-sso', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6',
'Content-Type': 'application/json',
},
body: JSON.stringify({
tenant_id: 'aa7d7fae-0386-4d8a-b977-72f856eac242',
ttl_seconds: 1036800,
}),
});
const { redirectTo } = await res.json();
// Send the customer's browser to redirectTo with a 302.import requests
res = requests.post(
"https://api.swarmz.net/functions/v1/platform-sso",
headers={"Authorization": "Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"},
json={"tenant_id": "aa7d7fae-0386-4d8a-b977-72f856eac242", "ttl_seconds": 1036800},
)
redirect_to = res.json()["redirectTo"]
# Send the customer's browser to redirect_to with a 302.Response
{
"success": true,
"redirectTo": "https://swarmz.net/sso?token=<jwt>&workspace=aa7d7fae-0386-4d8a-b977-72f856eac242"
}| Field | Type | Description |
|---|---|---|
success | boolean | Always true on success. Note the envelope is success, not ok. |
redirectTo | string | The login-landing URL: <origin>/sso?token=<jwt>&workspace=<tenant_id>. Issue a 302 to it. |
The envelope is success / redirectTo
Unlike the other endpoints, SSO returns success and redirectTo rather than
ok. Read redirectTo and issue the 302; the landing page at /sso consumes
the token and establishes the session.
Where redirectTo points
The redirectTo origin defaults to the apex https://swarmz.net. It switches
to your custom domain only once that domain is fully verified — i.e. your
account's custom_domain_status is active. Any other status
(none / pending / verifying / failed) falls back to the apex, so a half-set-up
domain never strands an SSO landing on a host that cannot yet serve the editor.
There is no <your-slug>.swarmz.net host — the apex serves your branded editor
until the custom domain goes active.
Errors
| Status | error | reason | When |
|---|---|---|---|
| 400 | missing_fields | tenant_id or external_ref required | Neither identifier supplied (bearer path) |
| 400 | missing_fields | account_id required for internal SSO | Internal-path call with no account_id |
| 401 | unauthorized | missing_bearer / invalid_key / account_disabled | See Authentication |
| 404 | tenant_not_found | — | No tenant matched the identifier under your account |
| 404 | account_not_found | — | Defensive — your account row was not found after auth |
| 405 | method_not_allowed | — | Anything other than POST |
| 409 | suspended | — | The tenant is suspended — unsuspend to restore access |
| 409 | account_inactive | the account status | Your platform account is not active (e.g. draft) |
| 410 | terminated | — | The tenant has been terminated |
| 429 | rate_limited | per_key / per_ip | Rate limit hit — see Rate limits |
| 500 | internal_error | — | Server-side failure (e.g. token signing); safe to retry |
Idempotency
SSO has no idempotency key. Each call mints a fresh token. See Idempotency.
Notes
Mint per click — never cache a token
There is no server-side token store and no revoke list. The token is valid for
its full ttl_seconds once minted, so to force a WHU out you
suspend the tenant — the next SSO call then returns
409 suspended, but any already-minted token stays valid until it expires.
Mint a fresh token on each click rather than caching one, so the suspend gate
is hit on every entry.
- Address the tenant by
tenant_idfromcreate;external_refis the fallback. ttl_secondsboth defaults to and is capped at1036800(12 days). Request a shorter TTL by passing a smaller value; you cannot exceed the cap.- The minted JWT carries
sub(the WHU'swhu_uid),enterprise_account_id, andworkspace_id, and is signed with the project JWT secret so PostgREST accepts it directly. - SSO is the hot path and has a much higher budget than the other endpoints: 600 requests/min per key and 1200/min per IP. See Rate limits.
- The
account_idparameter andX-Internal-Mint-Secretpath exist for the reseller dashboard's server-to-server calls only; host integrations use the bearer key and never sendaccount_id.
Terminate a tenant
Permanently delete a tenant and all of its infrastructure. Final and irreversible — a missing workspace is treated as idempotent success.
Usage report
A read-only roll-up of credit and cloud usage across your tenants, for reconciliation. Calendar-aligned, UTC, and safe to call repeatedly.