Swarmz

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.

POSThttps://api.swarmz.net/functions/v1/platform-sso

Maps 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"
}
FieldTypeDescription
successbooleanAlways true on success. Note the envelope is success, not ok.
redirectTostringThe 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

StatuserrorreasonWhen
400missing_fieldstenant_id or external_ref requiredNeither identifier supplied (bearer path)
400missing_fieldsaccount_id required for internal SSOInternal-path call with no account_id
401unauthorizedmissing_bearer / invalid_key / account_disabledSee Authentication
404tenant_not_foundNo tenant matched the identifier under your account
404account_not_foundDefensive — your account row was not found after auth
405method_not_allowedAnything other than POST
409suspendedThe tenant is suspended — unsuspend to restore access
409account_inactivethe account statusYour platform account is not active (e.g. draft)
410terminatedThe tenant has been terminated
429rate_limitedper_key / per_ipRate limit hit — see Rate limits
500internal_errorServer-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_id from create; external_ref is the fallback.
  • ttl_seconds both defaults to and is capped at 1036800 (12 days). Request a shorter TTL by passing a smaller value; you cannot exceed the cap.
  • The minted JWT carries sub (the WHU's whu_uid), enterprise_account_id, and workspace_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_id parameter and X-Internal-Mint-Secret path exist for the reseller dashboard's server-to-server calls only; host integrations use the bearer key and never send account_id.

On this page