Product documentation
UserImport
Bulk user import — synchronous batches and asynchronous jobs, with pre-hashed passwords carried over so migrated users sign in without a reset (SSO-1992).
UserImport
Bulk user import — synchronous batches and asynchronous jobs, with pre-hashed passwords carried over so migrated users sign in without a reset (SSO-1992).
Base URL: https://api.stg.thoryn.org
Operations
| Method | Path | Summary | Scopes |
|---|---|---|---|
POST | /api/v1/users/import | Bulk-import users synchronously | tenant:users.import |
POST | /api/v1/users/import/auth0 | Bulk-import users from an Auth0 export synchronously | tenant:users.import |
POST | /api/v1/users/import/auth0/jobs | Submit an asynchronous Auth0-export import job | tenant:users.import |
POST | /api/v1/users/import/cognito | Bulk-import users from a Cognito export synchronously | tenant:users.import |
POST | /api/v1/users/import/cognito/jobs | Submit an asynchronous Cognito-export import job | tenant:users.import |
GET | /api/v1/users/import/jobs | List import jobs | tenant:users.import |
POST | /api/v1/users/import/jobs | Submit an asynchronous bulk-import job | tenant:users.import |
GET | /api/v1/users/import/jobs/{id} | Get an import job | tenant:users.import |
POST | /api/v1/users/import/jobs/{id}/cancel | Cancel an import job | tenant:users.import |
Operation details
POST /api/v1/users/import
Bulk-import users synchronously
Imports up to 500 users into the caller's tenant and returns the per-row outcome. Partial success is normal: one bad row never aborts the batch, and a user whose email already exists is skipped rather than overwritten. Rows may carry a pre-hashed password so migrated users sign in without a reset. For larger batches use POST /api/v1/users/import/jobs. Pass ?dryRun=true to validate the batch without writing any row — the response is the same shape, read as a prediction (CREATED = would-create, SKIPPED_DUPLICATE = would-skip, ERROR = would-fail with that reason).
- Operation ID:
userImportImportUsers - Required scopes:
tenant:users.import
Parameters:
| Name | In | Required | Type | Description |
|---|---|---|---|---|
dryRun | query | no | boolean | When true, validate the batch and return the predicted per-row outcome without writing any user. Same validation and same response shape as a real import; zero rows are created. Defaults to false (a real import). |
Request body (required): application/json → ImportUsersRequest
Responses:
| Status | Description | Body |
|---|---|---|
200 | OK | object |
401 | Unauthorized — bearer token missing, expired, signed by an untrusted issuer, or missing the tnt tenant claim. | Problem (problem+json) |
403 | Forbidden — token lacks a required tenant:* scope, or the tnt claim does not match the tenant addressed by the request path. | Problem (problem+json) |
POST /api/v1/users/import/auth0
Bulk-import users from an Auth0 export synchronously
Maps a standard Auth0 bulk user-export (a JSON array of user objects) into the platform's import model and imports up to 500 users into the caller's tenant, returning the per-row outcome. Auth0 bcrypt password hashes (custom_password_hash or passwordHash) are carried over verbatim so migrated users sign in without a reset. Partial success is normal. For larger exports use POST /api/v1/users/import/auth0/jobs. Pass ?dryRun=true to validate the whole export without writing any row — the response is the same shape, read as a prediction.
- Operation ID:
userImportImportAuth0Users - Required scopes:
tenant:users.import
Parameters:
| Name | In | Required | Type | Description |
|---|---|---|---|---|
dryRun | query | no | boolean | When true, validate the batch and return the predicted per-row outcome without writing any user. Same validation and same response shape as a real import; zero rows are created. Defaults to false (a real import). |
Request body (required): application/json → Auth0User[]
Responses:
| Status | Description | Body |
|---|---|---|
200 | OK | object |
401 | Unauthorized — bearer token missing, expired, signed by an untrusted issuer, or missing the tnt tenant claim. | Problem (problem+json) |
403 | Forbidden — token lacks a required tenant:* scope, or the tnt claim does not match the tenant addressed by the request path. | Problem (problem+json) |
POST /api/v1/users/import/auth0/jobs
Submit an asynchronous Auth0-export import job
Maps a standard Auth0 bulk user-export (a JSON array of user objects) into the platform's import model and submits it as an asynchronous job (up to 10 000 users). Each user's federation provider is resolved against the caller's configured federation members before the job is enqueued: a resolvable provider is normalised to its platform type and enqueued, an unresolvable one is rejected up front (unresolved_federation_provider) and never enqueued. Returns 202 with the enqueued job plus any up-front rejections ({job, rejected}); when every row is rejected the response is 200 with a null job. Poll, list and cancel the job through the shared /api/v1/users/import/jobs surface — this is the same job model, not a parallel one.
- Operation ID:
userImportCreateAuth0Job - Required scopes:
tenant:users.import
Request body (required): application/json → Auth0User[]
Responses:
| Status | Description | Body |
|---|---|---|
200 | OK | object |
401 | Unauthorized — bearer token missing, expired, signed by an untrusted issuer, or missing the tnt tenant claim. | Problem (problem+json) |
403 | Forbidden — token lacks a required tenant:* scope, or the tnt claim does not match the tenant addressed by the request path. | Problem (problem+json) |
POST /api/v1/users/import/cognito
Bulk-import users from a Cognito export synchronously
Maps an Amazon Cognito user-pool export (a JSON array of user objects, each with a Username and a Name/Value Attributes list) into the platform's import model and imports up to 500 users into the caller's tenant, returning the per-row outcome. Cognito does not export password hashes, so migrated users are created password-less and sign in via password reset or federation. Partial success is normal. For larger exports use POST /api/v1/users/import/cognito/jobs. Pass ?dryRun=true to validate the whole export without writing any row — the response is the same shape, read as a prediction.
- Operation ID:
userImportImportCognitoUsers - Required scopes:
tenant:users.import
Parameters:
| Name | In | Required | Type | Description |
|---|---|---|---|---|
dryRun | query | no | boolean | When true, validate the batch and return the predicted per-row outcome without writing any user. Same validation and same response shape as a real import; zero rows are created. Defaults to false (a real import). |
Request body (required): application/json → CognitoUser[]
Responses:
| Status | Description | Body |
|---|---|---|
200 | OK | object |
401 | Unauthorized — bearer token missing, expired, signed by an untrusted issuer, or missing the tnt tenant claim. | Problem (problem+json) |
403 | Forbidden — token lacks a required tenant:* scope, or the tnt claim does not match the tenant addressed by the request path. | Problem (problem+json) |
POST /api/v1/users/import/cognito/jobs
Submit an asynchronous Cognito-export import job
Maps an Amazon Cognito user-pool export (a JSON array of user objects) into the platform's import model and submits it as an asynchronous job (up to 10 000 users). Each user's federation provider is resolved against the caller's configured federation members before the job is enqueued: a resolvable provider is normalised to its platform type and enqueued, an unresolvable one is rejected up front (unresolved_federation_provider) and never enqueued. Returns 202 with the enqueued job plus any up-front rejections ({job, rejected}); when every row is rejected the response is 200 with a null job. Poll, list and cancel the job through the shared /api/v1/users/import/jobs surface — the same job model, not a parallel one. Cognito exports carry no password hashes, so migrated users sign in via reset or federation.
- Operation ID:
userImportCreateCognitoJob - Required scopes:
tenant:users.import
Request body (required): application/json → CognitoUser[]
Responses:
| Status | Description | Body |
|---|---|---|
200 | OK | object |
401 | Unauthorized — bearer token missing, expired, signed by an untrusted issuer, or missing the tnt tenant claim. | Problem (problem+json) |
403 | Forbidden — token lacks a required tenant:* scope, or the tnt claim does not match the tenant addressed by the request path. | Problem (problem+json) |
GET /api/v1/users/import/jobs
List import jobs
Cursor-paginated list of the caller's tenant's import jobs, newest first. limit defaults to 20, hard-capped at 100. The list view omits per-row error detail — poll GET /api/v1/users/import/jobs/{id} for that.
- Operation ID:
userImportList - Required scopes:
tenant:users.import
Parameters:
| Name | In | Required | Type | Description |
|---|---|---|---|---|
limit | query | no | integer | |
cursor | query | no | string |
Responses:
| Status | Description | Body |
|---|---|---|
200 | OK | object |
401 | Unauthorized — bearer token missing, expired, signed by an untrusted issuer, or missing the tnt tenant claim. | Problem (problem+json) |
403 | Forbidden — token lacks a required tenant:* scope, or the tnt claim does not match the tenant addressed by the request path. | Problem (problem+json) |
POST /api/v1/users/import/jobs
Submit an asynchronous bulk-import job
Accepts up to 10 000 users and returns 202 with the job resource. The batch is encrypted at rest and drained in the background; poll GET /api/v1/users/import/jobs/{id} for live counters. Same wire shape and same partial-failure semantics as the synchronous endpoint.
- Operation ID:
userImportCreateJob - Required scopes:
tenant:users.import
Request body (required): application/json → ImportUsersRequest
Responses:
| Status | Description | Body |
|---|---|---|
200 | OK | object |
401 | Unauthorized — bearer token missing, expired, signed by an untrusted issuer, or missing the tnt tenant claim. | Problem (problem+json) |
403 | Forbidden — token lacks a required tenant:* scope, or the tnt claim does not match the tenant addressed by the request path. | Problem (problem+json) |
GET /api/v1/users/import/jobs/{id}
Get an import job
Returns the job's status, live counters and per-row errors. A job belonging to another tenant is indistinguishable from one that does not exist — both are 404.
- Operation ID:
userImportGetJob - Required scopes:
tenant:users.import
Parameters:
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string |
Responses:
| Status | Description | Body |
|---|---|---|
200 | OK | object |
401 | Unauthorized — bearer token missing, expired, signed by an untrusted issuer, or missing the tnt tenant claim. | Problem (problem+json) |
403 | Forbidden — token lacks a required tenant:* scope, or the tnt claim does not match the tenant addressed by the request path. | Problem (problem+json) |
POST /api/v1/users/import/jobs/{id}/cancel
Cancel an import job
Stops a pending or in_progress job: the poller checks between chunks and the encrypted payload is wiped identically to the completed/failed terminal paths. A job already in a terminal state (including one already cancelled) is 409 job_not_cancellable.
- Operation ID:
userImportCancelJob - Required scopes:
tenant:users.import
Parameters:
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string |
Responses:
| Status | Description | Body |
|---|---|---|
200 | OK | object |
401 | Unauthorized — bearer token missing, expired, signed by an untrusted issuer, or missing the tnt tenant claim. | Problem (problem+json) |
403 | Forbidden — token lacks a required tenant:* scope, or the tnt claim does not match the tenant addressed by the request path. | Problem (problem+json) |