- On-demand automation (scripts / CI jobs)
- An internal provisioning service integrated into your tooling
What Tenant Management is (and isn’t)
Tenant Management API is used to:- create/list/delete tenants
- create/list/delete tenant applications (region/cell-specific OAuth2 clients)
tenant_id to Documents API — the tenant is inferred from the tenant application credentials used to obtain the token.
Model A — On-demand scripts (simple, common)
Use a script when provisioning is infrequent or handled by engineering/ops. Typical pattern- A CLI/script (or CI job) uses organization-level credentials to:
- create a tenant (one tenant per downstream customer)
- create one or more tenant applications (per required cell/region)
- store the returned credentials securely (or hand them off to your secrets manager)
- early pilots / PoCs
- low tenant churn
- teams that want the least operational surface area
- avoid storing org-level credentials on laptops
- ensure provisioning is auditable (log who/why/when)
- avoid manual copy/paste of secrets where possible
Model B — Internal provisioning service (recommended at scale)
Some partners build a small backend service that exposes “Create tenant” to internal users (e.g., Customer Success, Account Managers) via a UI or internal workflow tool. Typical pattern- Your internal tool calls your provisioning service (not Resistant AI directly).
- The provisioning service uses org-level credentials to create tenants and tenant applications.
- The service stores outcomes in your system-of-record (admin DB / CRM) and stores sensitive material in a secrets manager.
- high volume onboarding
- delegated operations (non-engineers initiate provisioning)
- standardized workflows and governance
- RBAC: only approved internal roles can trigger tenant changes
- Approval flow (optional): for production tenants, require a second approver
- Idempotency: prevent double-creation (e.g., if a user clicks twice)
- Audit logging: record actor, timestamp, request parameters, response IDs (
tenant_id,application_id,client_id) - Secrets handling
- if using client secrets, store them immediately and never log them
- if using JWT client assertion (private key), keep the private key in a secrets manager and reuse across deployments
Region/cell decisions: how many tenant applications?
Tenant applications are cell/region-specific. Create:- one tenant application per cell you need to process documents in (most common), or
- multiple applications per cell if you need operational separation (e.g., key rotation, separate internal environments).
Store tenant metadata (strongly recommended)
A common operational failure mode is creating tenants but not storing the identifiers and URLs anywhere internally. This makes it hard for support, operations, and analysts to know:- which tenant_id to reference,
- which Web UI URL to use for deep links,
- which cells are enabled for a given downstream customer.
Minimum fields to persist (system-of-record)
Store these values immediately after provisioning:tenant_id- tenant name (and your downstream customer identifier)
- enabled cells (e.g.,
["eu-1", "us-1"]) - Web UI base URL(s) per stage/cell (or the hostname pattern + chosen cell)
- tenant applications per cell:
application_id,client_id, auth method (secret vs JWT)- created_at, rotated_at (if applicable)
- internal owner / audit fields:
- created_by, created_at, status (active/deprecated/deleted)
Lifecycle management (don’t ignore deletions)
Treat tenants as lifecycle-managed resources:- create tenants only for real downstream customers
- delete tenants you no longer need to reduce sprawl and simplify access governance
To delete a tenant, you must delete all tenant applications inside it first.
Common recommendation
If you’re unsure where to start:- Start with Model A (scripts) for your first 5–10 tenants.
- Move to Model B (internal provisioning service) once onboarding becomes frequent, delegated, or needs stronger audit/RBAC controls.