Bulk import users from CSV
Use this when onboarding a new tenant with 50+ users, or migrating from a spreadsheet-based access list.
CSV format
A header row plus one row per user:
email,full_name,role,seat_type,groups
alice@example.com,Alice Tan,editor,builder,"Finance Leadership;Dataset Authors"
bob@example.com,Bob Wijaya,viewer,viewer,"Finance Leadership"
carol@example.com,Carol Susanto,admin,admin,
| Column | Required | Notes |
|---|---|---|
email | yes | Must be unique; existing users with this email are updated, not duplicated |
full_name | yes | First Last format; no other normalization |
role | yes | Legacy role string (admin, editor, viewer, management, cs_staff). See Permissions Reference for what each means. |
seat_type | yes | One of admin, builder, analyst, viewer — orthogonal to role |
groups | no | Semicolon-separated group names; empty means no group memberships beyond defaults |
Save as UTF-8. Comma-delimited. Quote any field that contains a comma or semicolon (the groups column usually does).
Dry run first
Always dry-run before applying:
# CLI
honeyframe users bulk-import users.csv --dry-run
# Or via the API
curl -X POST https://platform.hubstudio.id/api/users/bulk-import \
-H "Authorization: Bearer $TOKEN" \
-F file=@users.csv \
-F dry_run=true
The dry-run output reports:
- N users to be created
- N users to be updated
- N rows with validation errors (and which column)
- Groups that would be created vs. groups that exist
- Seat type changes that would consume additional seats
Read every line. Common errors:
seat_type=builder but org has no builder seats remaining— buy more seats or downgrade to analystrole=editor but seat_type=viewer— viewers can't have editor role; pick a more permissive seatgroup "Finance Leaership" not found and dry-run did not authorize creation— typo in the group name (noteLeaership)
Apply
Drop the --dry-run flag once dry-run is clean. Apply produces a summary identical to dry-run plus a per-row outcome (created | updated | failed with reason).
The operation is not atomic across rows — if row 47 fails because the email is malformed, rows 1-46 still succeeded. Re-run with the failed rows (or fix and re-upload the whole file; existing users are idempotently updated).
What the import doesn't do
- Send invitation emails — users are created with a flag indicating "needs onboarding"; trigger invitations separately via Admin → Users → Send invitations, or set
--send-invitationson the import command to do both. - Assign permissions to specific objects — bulk-import only sets seat_type and group memberships. Object-scoped permissions (e.g. "alice can edit dashboard 42") need a separate
bulk-import-permissionsworkflow or per-dashboardShareactions. - Set passwords — Honeyframe doesn't manage passwords directly; users authenticate via SSO/LDAP/email-link. If you're on a password-based deployment (rare), the import marks users as
password_pendingand they receive a reset link on first invitation.
See also
- Users & Groups — the conceptual model behind seat types vs. group permissions
- LDAP Configuration — alternative to CSV-import when the org already has a directory server