Bulk create or upsert tenants
/tenant/bulk
Request Body
Environment to create the tenants in. Required for session auth; ignored for API tokens. Applied to every row in the batch — the endpoint does not let you mix environments in one request.
8a2b104d-74a6-47f2-b93e-c6b611e82391Collision behaviour. insert skips existing ids; upsert updates name/metadata on existing ids.
insertupsert
The list of tenants to create or upsert. Max 1000 per request — split larger inputs client-side. Only id, name, and metadata are allowed per item.
Tenant id. Free-form up to 255 characters, excluding control characters, leading or trailing whitespace, and the dot segments . and ...
acme-corpFree-form JSON object. Defaults to {} when omitted on insert; kept unchanged when omitted on upsert of an existing row.
{"tier":"gold"}Display name. Defaults to id when omitted on insert; kept unchanged when omitted on upsert of an existing row.
Acme CorpResponse Body
The tenants that were newly inserted.
The date and time when the tenant was created.
2026-07-02T09:14:03.117ZThe environment this tenant belongs to.
8a2b104d-74a6-47f2-b93e-c6b611e82391The tenant identifier — caller-chosen and immutable once created. Composite primary key with environment_id, so the same value can exist independently in development, staging, and production. Free-form up to 255 characters: whatever you already use to identify a customer, including /, spaces and non-ASCII. The only values rejected are the ones no URL path segment can carry — control characters, leading or trailing whitespace, and the dot segments . and ...
acme-corpFree-form JSON object stored verbatim. Truto does not interpret this field — use it for tier, region, billing plan, or any other customer attribute your app cares about.
{"tier":"gold","region":"wnam"}Display name shown in the dashboard. Defaults to the tenant id on create if not supplied; can be edited later via PATCH /tenant/{id}.
Acme CorpThe date and time when the tenant was last updated.
2026-07-02T09:14:03.117ZRows that were not inserted because a tenant with the same (id, environment_id) already existed. Only populated when mode is insert (the default), which uses INSERT ... ON CONFLICT DO NOTHING. Empty for upsert.
The tenant id that was skipped.
acme-corpWhy the row was skipped.
already_existsalready_exists
Tenants that already existed and were updated. Only populated when mode is upsert; always empty for insert.
The date and time when the tenant was created.
2026-07-02T09:14:03.117ZThe environment this tenant belongs to.
8a2b104d-74a6-47f2-b93e-c6b611e82391The tenant identifier — caller-chosen and immutable once created. Composite primary key with environment_id, so the same value can exist independently in development, staging, and production. Free-form up to 255 characters: whatever you already use to identify a customer, including /, spaces and non-ASCII. The only values rejected are the ones no URL path segment can carry — control characters, leading or trailing whitespace, and the dot segments . and ...
acme-corpFree-form JSON object stored verbatim. Truto does not interpret this field — use it for tier, region, billing plan, or any other customer attribute your app cares about.
{"tier":"gold","region":"wnam"}Display name shown in the dashboard. Defaults to the tenant id on create if not supplied; can be edited later via PATCH /tenant/{id}.
Acme CorpThe date and time when the tenant was last updated.
2026-07-02T09:14:03.117Zcurl -X POST 'https://api.truto.one/tenant/bulk' \
-H 'Authorization: Bearer <your_api_token>' \
-H 'Content-Type: application/json' \
-d '{
"mode": "insert",
"tenants": [],
"environment_id": "8a2b104d-74a6-47f2-b93e-c6b611e82391"
}'const body = {
"mode": "insert",
"tenants": [],
"environment_id": "8a2b104d-74a6-47f2-b93e-c6b611e82391"
};
const response = await fetch('https://api.truto.one/tenant/bulk', {
method: 'POST',
headers: {
'Authorization': 'Bearer <your_api_token>',
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
const data = await response.json();
console.log(data);import requests
url = "https://api.truto.one/tenant/bulk"
headers = {
"Authorization": "Bearer <your_api_token>",
"Content-Type": "application/json",
}
params = {
}
payload = {
"mode": "insert",
"tenants": [],
"environment_id": "8a2b104d-74a6-47f2-b93e-c6b611e82391"
}
response = requests.post(url, headers=headers, params=params, json=payload)
print(response.json())