Multitenancy
Stateway implements multitenancy by API key. Every resource is isolated per tenant, and the API key automatically handles tenant resolution.
How It Works
When a request arrives with a valid X-API-Key header:
- The key is validated and looked up
- The associated tenant is resolved automatically
- All subsequent operations are scoped to that tenant
You never need to pass tenant_id in any API request. The API key handles tenant resolution transparently.
Data Isolation
Every resource in Stateway is scoped to a tenant:
| Scenario | Result |
|---|---|
| Tenant A lists definitions | Only sees Tenant A's definitions |
| Tenant A queries instance by ID | 404 if instance belongs to Tenant B |
| Tenant A tries to complete Tenant B's task | 404 — task not found |
| Tenant A evaluates Tenant B's decision | 404 — decision not found |
There are no cross-tenant operations exposed through the API.
Registration Flow
Registration is a two-step process to verify email ownership.
Step 1 — Register
Request:
curl -X POST https://api.stateway.io/v1/register \
-H "Content-Type: application/json" \
-d '{
"email": "admin@acme.com",
"name": "Acme Corp",
"slug": "acme"
}'
Response:
{
"data": {
"tenantId": "ten_01j...",
"message": "Verification code sent to admin@acme.com"
}
}
A 6-digit verification code is sent to the provided email. The slug field is optional — if omitted, Stateway generates one from the name.
Step 2 — Verify
Request:
curl -X POST https://api.stateway.io/v1/register/verify \
-H "Content-Type: application/json" \
-d '{
"tenantId": "ten_01j...",
"verificationCode": "482931"
}'
Response:
{
"data": {
"tenant": {
"id": "ten_01j...",
"name": "Acme Corp",
"slug": "acme"
},
"apiKey": "sw_live_...",
"scopes": ["admin"]
}
}
The API key is returned only once at this point. Store it securely — it cannot be retrieved again.
Multiple API Keys per Tenant
A single tenant can have multiple API keys — useful for different environments, integrations, or scoped permissions:
Request:
curl -X POST https://api.stateway.io/v1/auth/keys \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"name": "CI/CD Pipeline",
"scopes": ["definitions:write", "instances:read"]
}'
Response:
{
"data": {
"id": "key_01j...",
"key": "sw_live_...",
"name": "CI/CD Pipeline",
"scopes": ["definitions:write", "instances:read"],
"created_at": "2026-04-26T12:00:00.000Z"
}
}
The key value is returned only at creation time.
List API Keys
Request:
curl https://api.stateway.io/v1/auth/keys \
-H "X-API-Key: sw_live_your_key"
Response:
{
"data": [
{
"id": "key_01j...",
"name": "Production App",
"scopes": ["admin"],
"last_used_at": "2026-04-26T14:00:00.000Z",
"expires_at": null,
"revoked_at": null
}
]
}
The key value itself is never returned in list or get responses.
Revoke an API Key
Request:
curl -X DELETE https://api.stateway.io/v1/auth/keys/{key_id} \
-H "X-API-Key: sw_live_your_key"
Returns 204 No Content.
API keys are cached for up to 60 seconds. A revoked key may remain valid for up to 60 seconds after revocation.
Tenant Management
Get Current Tenant
Request:
curl https://api.stateway.io/v1/tenant \
-H "X-API-Key: sw_live_your_key"
Response:
{
"data": {
"id": "ten_01j...",
"name": "Acme Corp",
"slug": "acme",
"email": "admin@acme.com",
"status": "active",
"created_at": "2026-04-26T12:00:00.000Z"
}
}
Update Tenant Settings
Request:
curl -X PUT https://api.stateway.io/v1/tenant \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Acme Corp (Updated)" }'
Response:
{
"data": {
"id": "ten_01j...",
"name": "Acme Corp (Updated)",
"slug": "acme",
"email": "admin@acme.com",
"status": "active",
"created_at": "2026-04-26T12:00:00.000Z"
}
}
Best Practices
- One tenant per organization — don't create multiple tenants for the same company
- Use separate API keys per environment — production, staging, CI/CD each get their own key
- Use scoped keys — grant only the scopes needed; reserve
admin-scoped keys for privileged operations - Rotate keys regularly — revoke old keys and create new ones periodically
- Never log API keys — they are the equivalent of tenant credentials
- Account for revocation latency — keys are cached for up to 60 seconds; time-sensitive revocation should account for this window