Migrating from your current system
Bulk-import your existing organizations, users, roles, and applications with a validate-then-commit flow, so you never half-apply a bad file.
Where it lands
Every payload targets exactly one of two places, via one field:
rootParentOrgId(an existing org's id) — imports under it. NeedsORG_MANAGEplus subtree reach over that org. This is also how you onboard a white-labelled branch's data: point it at the branch you just created, using the reach you have as its creator.rootTenant({ orgName, slug }), withrootParentOrgIdomitted — provisions a brand-new tenant. NeedsPLATFORM_ADMIN; this is a platform-level act, not a tenant-admin one.
The flow
- Validate (dry run) —
POST /api/import/validatewith your payload. Nothing is written. You get back a report: what would be created, plus any errors (bad references, duplicate identifiers, an import that would exceed your plan's application-set cap). - Commit — if the report has no errors,
POST /api/import/commitwith the same payload applies it. - Track —
GET /api/import/jobslists past import jobs and their status.
const report = await mgmt.import.validate(payload);
if (report.errors.length === 0) {
await mgmt.import.commit(payload);
}
Payload shape
The payload carries organizations, users, roles, and applications, each keyed by
a stable externalId you assign. References between entities (a user's org,
a role's permissions) use those external ids, so the graph resolves in one pass
regardless of order. External ids are also how a re-run stays idempotent — an
entity already imported is skipped, not duplicated.
Tips
- Run validate as many times as you like; it's side-effect-free.
- Fix every reported error before committing — a commit applies the whole file.
- Importing is capped by your plan just like manual registration; the dry run tells you before you commit.
Each SDK's README has a language-specific migration walkthrough with a full example payload.