---
title: "Create users in bulk"
method: POST
path: "/users/bulk"
tags: ["Users"]
---

# Create users in bulk

`POST /users/bulk`

## Request

- Base URL: `https://api.modjo.ai/v2`
- URL: `https://api.modjo.ai/v2/users/bulk`
- Auth: HTTP bearer

Creates up to 100 users in one request. The body is an array of CreateUserRequest objects. Results follow input order and include an index for each user. Existing emails do not prevent other users from being created. When the users asking for a license outnumber the available licenses, the request fails with 409 and no user is created.

## Request body

- CreateUserRequest[]: 1 to 100 user objects matching CreateUserRequest. The entire request must pass validation before any user is created.
  - `email` string, email, required: User email address
  - `firstName` string, required: User first name
  - `lastName` string, required: User last name
  - `phoneNumber` string: User phone number
  - `jobTitle` string: User job title
  - `jobDepartment` string: User job department
  - `role` 'user' | 'manager' | 'admin': User role. Defaults to "user".
  - `timezone` string: IANA timezone identifier
  - `hasLicense` boolean: Assign a license from the workspace pool to the user. Defaults to false. The request fails with 409 when no license is available. In the rare case where a concurrent request takes the last license, the user is created without one and hasLicense is false in the response.

## Response `200`

Per-user creation results

- BulkCreateUsersResponse
  - `results` union[], required: One result per input user, in input order
    - union
      - object
        - `index` integer, required: Zero-based position of the input user
        - `status` 'created', required: The user was created
        - `user` object, required: Created user
          - `id` number, required: User ID
          - `email` string, required: User email address
          - `firstName` string, nullable, required: User first name
          - `lastName` string, nullable, required: User last name
          - `phoneNumber` string, nullable, required: User phone number
          - `jobTitle` string, nullable, required: User job title
          - `jobDepartment` string, nullable, required: User job department
          - `role` string, required: User role: user, manager, or admin
          - `timezone` string, nullable, required: IANA timezone identifier
          - `createdOn` string, nullable, required: Creation timestamp in ISO 8601 format
          - `modifiedOn` string, nullable, required: Last modification timestamp in ISO 8601 format
          - `hasLicense` boolean, required: Whether the user holds a license of the workspace
      - object
        - `index` integer, required: Zero-based position of the input user
        - `status` 'error', required: The user was not created
        - `error` object, required: Reason the user was not created
          - `code` 'validation_error' | 'internal_error' | 'missing_api_key' | 'invalid_api_key' | 'rate_limited' | 'not_found' | 'gone' | 'conflict' | 'forbidden' | 'feature_not_enabled' | 'not_ready' | 'upstream_error' | 'upstream_timeout', required: Machine-readable error code: validation_error, internal_error, missing_api_key, invalid_api_key, rate_limited, not_found, gone, conflict, forbidden, feature_not_enabled, not_ready, upstream_error, upstream_timeout
          - `message` string, required: Human-readable error message with details about the failure

## Other responses

- `400`: The request must contain 1 to 100 users
- `401`: Authentication failed. The API key is missing or invalid.
- `409`: Not enough licenses available
- `429`: Rate limit exceeded. Retry after the X-RateLimit-Reset interval.

## Changes

- **2026-10-19** `cd38cb80cde1`: 3 info
  - added the new optional request property `items/hasLicense`
  - added the non-success response with the status `409`
  - added the required property `results/items/oneOf[subschema #1]/user/allOf[#/components/schemas/User]/hasLicense` to the response with the `200` status
- **2026-10-14** `5aa3b3f47a13`: 1 warning
  - added the new `forbidden` enum value to the `results/items/oneOf[subschema #2]/error/code` response property for the response status `200`
- **2026-10-02** `1f66d3efa41a`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/modjo/apis/modjo-public-api/changes/users/bulk/post.md)

---

[API](https://skmtc.dev/modjo/apis/modjo-public-api.md) - [All operations](https://skmtc.dev/modjo/apis/modjo-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/modjo/apis/modjo-public-api/revisions/9d2a0a6a5a20?raw)
