The shape of the integrationLink to this section
Three parties, one flow: your identity provider issues a token for a tenant, your platform mints that tenant’s key, and the tenant’s runtime calls the API.
identity provider ──► your platform ──► Sylphx admin route ──► one key per tenant
(org-scoped token) POST /v1/admin/tenants/{org}/keys sk-sx-…
tenant runtime ──► https://api.models.sylphx.ai/v1/responses
Authorization: Bearer sk-sx-…
- The token your platform presents must be scoped to the organization named in the path: the token’s
org_idmust equal{org}. Anything else fails closed — a tenant token can never mint for another tenant. The token must also carry an owner or admin role for that organization. - The minted key is an ordinary organization service key: it authenticates on the inference surface exactly like a console key.
- Keys are per tenant, so usage, stored responses, and files stay isolated per organization with no extra work on your side.
Provision a keyLink to this section
One POST per tenant, executed from your backend — never from tenant-visible code.
Get an organization-scoped access token for the tenant
Your identity provider issues it. The token identifies the tenant’s organization and carries an owner or admin role for that organization; your platform keeps it server-side and renews it on its own schedule.
Mint the key
Name the tenant’s organization in the path and give the key a name you can find again, such as the runtime or environment it belongs to.
POST /v1/admin/tenants/{org}/keys201 · key shown oncecurl https://api.models.sylphx.ai/v1/admin/tenants/acme/keys \ -H "Authorization: Bearer $PLATFORM_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"acme-runtime","tier":"pro"}' # 201 Created # { "id": "0f3c…", "name": "acme-runtime", # "key": "sk-sx-…", "key_prefix": "sk-sx-12chars…" }Store it in your secret manager
The plaintext key is returned once. Save it against the tenant, hand it to that tenant’s runtime, and never log it.
nameis required. An optionaltierofpro(the default) orsandboxis accepted; keys on either tier are not subject to the free-tier request envelope.- An organization can hold up to 1,000 active keys. Revoke unused keys before you reach the cap.
- Provisioning runs on the same host as the API and requires the platform surface to be available; a failure returns a typed error rather than a half-created key.
Call the API from the tenant runtimeLink to this section
Once the tenant has its key, nothing about the runtime is special: it is a normal Responses client with its own organization scope.
export SYLPHX_API_KEY="sk-sx-…" # this tenant's key
curl https://api.models.sylphx.ai/v1/responses \
-H "Authorization: Bearer $SYLPHX_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"model": "openai/gpt-5.5",
"input": "Hello from the runtime."
}'
Verify a fresh key with GET /models: it should return the catalog for that key with no errors. From there, the quickstart applies unchanged.
Rotate and revokeLink to this section
Three management routes keep tenant keys healthy. Each one is scoped by the same organization token, and each names its effect before it happens.
List
curl https://api.models.sylphx.ai/v1/admin/tenants/acme/keys \
-H "Authorization: Bearer $PLATFORM_ACCESS_TOKEN"
# { "object": "list", "data": [
# { "id": "0f3c…", "name": "acme-runtime", "key_prefix": "sk-sx-…",
# "created_at": "…", "last_used_at": "…",
# "rotation_grace_expires_at": null } ] }
Rotate
curl https://api.models.sylphx.ai/v1/admin/tenants/acme/keys/0f3c…/rotate \
-H "Authorization: Bearer $PLATFORM_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"grace_seconds": 86400}'
# { "id": "0f3c…", "key": "sk-sx-…", "key_prefix": "…",
# "previous_key_expires_at": "…" }
The default grace window is one day and the maximum is seven days (604800 seconds). During the window the previous key keeps working, so you can roll a runtime without downtime; after it expires only the new key authenticates.
Revoke
curl -X DELETE https://api.models.sylphx.ai/v1/admin/tenants/acme/keys/0f3c… \
-H "Authorization: Bearer $PLATFORM_ACCESS_TOKEN"
# { "revoked": true }
Revoking stops the key immediately. Revoke on tenant offboarding or when a key may have leaked; revoking twice returns 409 already_revoked, and an unknown id returns 404 key_not_found.
Machine keys and console keysLink to this section
Both kinds are the same wire credential. The difference is who is allowed to mint and manage them.
| Credential property | Console key | Machine key |
|---|---|---|
| Who mints | A signed-in person in the console | Your platform, per tenant |
| Mint auth | Console session after human login | Organization-scoped access token |
| Wire credential | Bearer sk-sx-… | Bearer sk-sx-… |
| Scope | One organization | One organization (the tenant) |
| Shown | Once, at mint time | Once, at mint time |
| Managed | Console: mint and revoke | Admin routes: list, rotate, revoke |
POST /v1/platform/keys is retired: it returns 404 shared_provision_retired and names the tenant route that replaced it. Use POST /v1/admin/tenants/{org}/keys for every integrator.Production practiceLink to this section
Four habits keep a multi-tenant integration clean.
- One key per tenant runtime. Do not share a key across tenants: isolation, usage attribution, and revocation all depend on it.
- Keep the org token server-side. The organization-scoped token belongs to your provisioning service, never to tenant code or a mobile app.
- Rotate on a schedule and on offboarding. The grace window makes rotation boring; use it.
- Send idempotent retries from the runtime. The same
Idempotency-Keyrules apply to every client — see retries.