Skip to main content
Audact
See the offer

Tenancy model — two supported shapes

Audact supports both public keyless and org-owned tenant provisioning. Choose the shape that fits your integration.

Audact supports both of the tenant-provisioning shapes an integrator might be choosing between — this is a design decision on the caller's side, not a gap in the API.

Shape 1 — Public, keyless tenant creation

POST /v1/tenants (tenant-management, unauthenticated)

  • No API key or org account required to call this endpoint.
  • IP rate-limited to 5 creations per IP per hour since it is otherwise open.
  • Tenant lifecycle from here on: GET /v1/tenants/{tenant_id} (viewer+), PUT /v1/tenants/{tenant_id} (owner), API keys via POST/GET/DELETE /v1/tenants/{tenant_id}/keys[/{key_id}] (owner to mint/revoke, developer+ to list).

Shape 2 — Org-owned tenants with full lifecycle

POST /v1/org/tenants (org-management, requires an authenticated, verified organization) — provisions a tenant owned by the caller's organization, deliberately without an API key or default configuration; those are deferred to a separate initialize step so tenant creation and tenant activation are two auditable actions.

Full lifecycle under the org-owned model:

EndpointEffect
POST /v1/org/tenantsCreate the tenant row, owned by the org. No key, no configuration yet.
POST /v1/org/tenants/{id}/initializeSeeds the tenant's first sealed default configuration and reveals its first owner API key (idempotent — replays 409 already_initialized on a second call rather than duplicating).
POST /v1/org/tenants/{id}/keysMints an additional owner API key without touching configuration.
POST /v1/org/tenants/{id}/enableSets status=active, clears the org:tenant-disabled Redis marker.
POST /v1/org/tenants/{id}/disableThis is PAUSE — see below.
DELETE /v1/org/tenants/{id}Logical delete: sets deleted_at, sets the org:tenant-disabled marker. The tenant's KMS HMAC key is retained, never deprovisioned.
POST /v1/org/tenants/{id}/restoreClears deleted_at on a soft-deleted tenant; reuses the original hmac_key_arn as-is (no re-provisioning, no new configuration/key).
POST /v1/org/tenants/{id}/impersonateMints a short-lived (~20 min) tenant-scoped JWT so the org admin can act as the tenant's owner against tenant-facing services; every call is audit-logged.

disable is a real PAUSE

POST /v1/org/tenants/{id}/disable transitions the tenant to status=disabled and sets the org:tenant-disabled:{tenant_id} Redis marker. From that point:

  • The API key authentication middleware checks this marker on the hot path and rejects every request authenticated with that tenant's API keys with 403, error code tenant_disabled — including impersonation-minted tokens.
  • The check fails open (allows the request through, logs a warning) if Redis itself is unreachable, so a Redis outage cannot itself become an availability incident for tenants that are not disabled.
  • enable clears the marker and restores status=active; the reversal is immediate.

This is the tenant-granularity equivalent of a PAUSE. DID-level pause — holding a phone number without routing it — is a separate concept.

Per-tenant isolation in both shapes

  • API keys and the webhook HMAC signing secret are per-tenant regardless of which shape created the tenant — there is no shared/global signing secret.
  • Every query in tenant-management/org-management scopes by tenant_id taken from the authenticated context, never from a request body field.

Recommendation

One Audact tenant per integrator-side tenant gives you per-tenant API key/secret isolation, the disable → PAUSE mapping at exactly the granularity you likely want, and Audact's existing cross-tenant isolation boundary — for free, with no extra plumbing. The API does not force this mapping, but it is the simplest one to reason about.

Source updated: October 19, 2026