Acting for a tenant
Send these headers with the partner key on every/v1 route:
Everything the request reads or creates belongs to that tenant alone: another
tenant’s resources answer
404 exactly as if they did not exist. Platform
domains and extraction schemas stay visible to every tenant.
A malformed
X-NDI-Tenant answers 404 like an unknown one, so no answer
tells you which tenants exist. A partner key acts for a tenant only through
X-NDI-Tenant: X-NDI-External-Account is for service keys that are not a
partner’s. The legacy /api/v1 routes, including /api/v1/example and
/api/v1/health/load, answer 403 to a partner key.
Managing tenants
Call these with the partner key and withoutX-NDI-Tenant.
PUT accepts display_name (up to 128 characters), disabled,
data_retention, retention_tier and limits (rpm, max_concurrent_jobs). Creating a tenant
past the partner’s tenant cap answers 409 tenant_limit_reached; disabled
tenants count toward the cap.
rpmis the tenant’s requests per minute. A request over it answers429.max_concurrent_jobsis how many parse, split, classify, categorize, extract, ground and agent jobs the tenant may have running at once. More jobs wait in the queue instead of being refused. NDI’s own per-tenant cap applies when it is lower, so this setting can lower a tenant’s concurrency but not raise it. Ingestion isn’t counted.- A limit above the partner’s own is lowered to it. The partner’s own limit is
the lower of its own value and its partner-wide cap (
partner.rpm,partner.concurrent_jobs), when one is set. - Lowering the partner’s limits later doesn’t rewrite existing tenants. The partner-wide caps bound all of its tenants together, and so each of them too.
data_retentionis how the tenant’s document operations retain data,shortorzero_retention. Omit it on create to inherit your own setting, or on update to leave the tenant’s setting unchanged. The tenant is returned with the setting in force for it: on a deployment that has not enabled zero retention, that isshort. Underzero_retention, results are never stored: a request must passwait_secondsand read the result from the response, or it answers422wait_required_for_zero_retention. Settingzero_retentionon a deployment that has not enabled it answers422invalid_request.retention_tieris the tenant’s account tier for job retention,paidorfree. A paid tenant’s job inputs, outputs and processing files are removed 48 hours after the job completes, a free tenant’s 7 days after; a failed or cancelled job counts from the failure or cancel. A tenant never given a tier ispaid. Omit it on update to leave the tier unchanged. A change applies to jobs that finish afterwards. See Data retention.
Purging a tenant
DELETE /v1/tenants/{external_ref}?purge=true permanently deletes everything
the tenant holds. It cannot be undone. Without purge=true, DELETE only
disables the tenant and keeps its data.
Call it with the partner key and no X-NDI-Tenant, like the other management
routes.
The call answers 202 with a tenant_purge job. The tenant is disabled at
once and its running jobs are cancelled. Every file’s bytes, every result,
cache entry and webhook payload of the tenant is then deleted, and its keys are
revoked. Only anonymized metadata is kept: the job records (ids, kinds,
statuses, timestamps, pages, units, bytes, credits, token counts per model and
error codes, with no job names, inputs, results or error messages), an
anonymized record for each deleted file and for each console user whose only
organization it was, the tenant’s workspaces and keys as renamed rows with no
settings and no usable key hash, and its other records (memberships,
invitations, uploads, webhook endpoints and events, access labels) marked
deleted, with no names, addresses, URLs, secrets or payloads. See
What we keep after deletion.
Poll the job with GET /v1/jobs/{job_id} using the partner key and without
X-NDI-Tenant; a partner may read only the purge jobs it owns this way. When
the job has succeeded, its result reports what the verification pass found:
A purge that ends with
verified: false is still a succeeded job: the
report says what is left, and repeating the DELETE runs the purge again. A
purge already queued or running is returned as it is. Once a purge has
verified clean, the external_ref no longer resolves: repeating the call
answers 404 tenant_not_found, and a later PUT creates a new, empty
tenant.
Usage across tenants
With the partner key and noX-NDI-Tenant, GET /v1/usage?group_by=tenant
returns one bucket per tenant, keyed by its external_ref, over the same
period_start/period_end window as any usage report. Disabled tenants are
included, since their usage is still owed. Only your own tenants are
counted.
One tenant’s usage is the ordinary GET /v1/usage with X-NDI-Tenant.
group_by=tenant with X-NDI-Tenant, a workspace_id, or a key that is not
a partner’s answers 422 invalid_request. Any other grouping from the
partner key without X-NDI-Tenant, and any request with
X-NDI-External-Account, answers 400 tenant_required.