Overview
A tenant represents one of your end-users (or customers, or workspaces — whichever unit you connect integrations for) inside Truto. Every integrated account is owned by a tenant, and everything you send to third-party APIs through Truto is billed, logged, and rate-limited under the tenant that owns the account.
What is a Tenant?
A tenant is a lightweight, environment-scoped object that groups all the integrated accounts belonging to one of your end-users. You choose the ID — a string like acme-corp, usr_1a2b3c, or the UUID your own database uses — and Truto keeps that same ID with the tenant across every integration your user connects.
One tenant can own many integrated accounts: your customer "Acme Corp" might connect HubSpot, Salesforce, and Slack, and each of those becomes an integrated account under the same tenant. Filtering GET /integrated-account?tenant_id=acme-corp returns all three.
Tenants and Environments
Tenants are scoped to an environment. The same tenant_id value can exist in development, staging, and production independently — three separate tenant rows with three separate sets of connected accounts. That's the same isolation model as Environments: what's in one environment isn't in the others.
Because of that scope, the composite primary key of a tenant is (id, environment_id). The dashboard handles environment scoping automatically; API tokens are bound to a single environment, so you don't need to pass environment_id manually in API calls.
Tenant IDs
You pick the ID. Truto accepts any string up to 255 characters, except control characters (newlines included), leading or trailing whitespace, and the IDs . and ... Slashes, spaces and other separators are allowed. When you put an ID in a URL path such as /tenant/:id, URL-encode it — org/4567 becomes /tenant/org%2F4567.
Common choices:
- The primary key from your own users/organizations table (
user_1a2b3c,org-4567). - A slug your customer will recognize (
acme-corp). - The email domain, when you have one workspace per company (
acme.com).
Whatever you pick, treat it as immutable: it's referenced by every integrated account owned by that tenant, every link token created against it, every log line, and every webhook payload.
Where Tenants come from
There are three ways a tenant appears in Truto:
- You create it explicitly — via the dashboard, the API (
POST /tenant), the CLI (truto tenants create), or in bulk (POST /tenant/bulk). This is the recommended path when you're onboarding a new customer. - Truto auto-creates it during a connection — when an integrated account is created with a
tenant_idthat doesn't exist yet, and the ID matches the allowed pattern, Truto materializes the tenant row for you. Creating a link token alone does not create the tenant — your customer's first successful connection does. - You bulk-import a batch — from CSV or JSON. Useful when moving from another system or seeding staging with a known set of customers. See Bulk import.
Explicitly creating tenants first gives you a place to attach metadata (tier, region, billing plan) before the customer connects anything. If you don't need that, letting Truto auto-create them is fine.
Metadata
Tenants carry a free-form JSON metadata field. Truto stores it as-is; nothing in it changes platform behaviour. Use it for anything your team wants alongside the tenant record:
{
"tier": "gold",
"region": "wnam",
"signed_up_at": "2026-06-01",
"billing_email": "billing@acme.com"
}Metadata is returned on every GET /tenant / GET /tenant/:id.
Managing tenants
- Dashboard — Tenants — table view with per-tenant account counts, edit, delete, bulk import, and per-tenant detail with bulk-delete of connected accounts.
- API —
POST /tenant,GET /tenant,GET /tenant/:id,PATCH /tenant/:id,DELETE /tenant/:id, andPOST /tenant/bulk. See Creating tenants and Deleting tenants. - CLI —
truto tenants ..., includingtruto tenants create-bulkfor batch imports.
FAQ
Can the same tenant_id appear in multiple environments? Yes. acme-corp in development, staging, and production are three separate tenants with three separate sets of accounts — that's the environment isolation model.
Do I have to create the tenant before my customer connects an account? No. If you call POST /link-token (or create an integrated account directly) with a tenant_id that doesn't exist, Truto creates the tenant when the integrated account is created — as long as the ID matches the allowed pattern. Minting the link token alone does not materialize the tenant. Pre-creating gives you a place to attach metadata; auto-create is fine when you don't need that.
What if my legacy tenant IDs have characters like / in them? They work. Slashes, spaces and other separators are valid in tenant IDs, and auto-create materializes a tenant for them; URL-encode the ID when you call /tenant/:id. Auto-create only skips IDs that can't be valid tenant IDs — longer than 255 characters, containing control characters, with leading or trailing whitespace, or exactly . or ... Those still work as strings on integrated accounts, but Truto won't materialize a tenant row for them. Migrate to a compatible ID (or create the tenant explicitly with a compatible ID and re-point the account) to get first-class tenant management.
Can I rename a tenant's ID? No — the ID is the primary key. You can change the display name and metadata on PATCH /tenant/:id, but the ID is immutable. If you need a different ID, create a new tenant and migrate integrated accounts to it before deleting the old one.
Can I delete a tenant with connected accounts? No — the API returns 409 Conflict. Delete the accounts first (or POST /integrated-account/bulk-delete with tenant_id), then delete the tenant. See Deleting tenants.