---
title: "Create a user."
method: POST
path: "/api/users"
tags: ["Users"]
---

# Create a user.

`POST /api/users`

## Request

- Base URL: `/` (relative, and the document was published on a file host, not at the API’s origin)
- URL: `/api/users`
- Auth: HTTP bearer

Creates a user with a default policy and context. The role is user unless admin is given. A password is optional; without one the user can only use API keys, created with POST /api/users/{username}/api-keys. A user created with a password must change it at next sign-in, and setting it is audited as user_password_set. Requires an administrator as well as the scope. Recorded as a user_created audit event naming the calling administrator as the principal and the calling API key in the details. Requires the `users:write` scope.

## Headers

- `Authorization` string, required

## Request body

- CreateUserRequest
  - `email` string
  - `password` string: Optional. At least 16 characters and at most 72 bytes in UTF-8. The user must change it at next sign-in. Without one, the user can only use API keys.
  - `role` string: user (the default) or admin.
  - `username` string

## Response `201`

The user was created.

- CreatedUserResponse
  - `id` string
  - `role` string
  - `username` string

## Other responses

- `400`: The username is missing, is reserved, or is not usable in a request path (it cannot contain /, \, ;, %, or control characters, and cannot be . or ..), the role is not user or admin, or the password is shorter than 16 characters or longer than 72 bytes in UTF-8, or the email address is not valid.
- `401`: The Authorization header is absent or the API key is not recognized.
- `403`: The key does not hold users:write, or the caller is not an administrator.
- `404`: Not Found
- `406`: No representation matches Accept.
- `409`: A user with that username already exists, active or deactivated.
- `413`: Content Too Large
- `415`: Unsupported Media Type
- `500`: Internal Server Error
- `503`: Service Unavailable

## Changes

- **2026-10-10** `c4f85daa9208`: 17 info
  - added the non-success response with the status `404`
  - added the optional property `field` to the response with the `400` status
  - added the optional property `field` to the response with the `401` status
  - added the optional property `field` to the response with the `403` status
  - …13 more
- **2026-10-10** `99428fb4cd2d`: 1 info
  - added the optional property `id` to the response with the `201` status
- **2026-10-05** `4082c17721d8`: 6 breaking, 6 info
  - removed the media type `*/*` for the response with the status `400`
  - removed the media type `*/*` for the response with the status `401`
  - removed the media type `*/*` for the response with the status `413`
  - removed the media type `*/*` for the response with the status `415`
  - …8 more
- **2026-10-05** `4fa43795fff9`: 1 info
  - added the new optional request property `password`
- **2026-10-05** `ca52c57b5c4c`: 1 warning, 4 info
  - removed the request property `password`
  - api tag `Users` added
  - api tag `Provisioning` removed
  - added the new optional request property `role`
  - …1 more

[Operation history](https://skmtc.dev/philterd/apis/philter-api/changes/api/users/post.md)

---

[API](https://skmtc.dev/philterd/apis/philter-api.md) - [All operations](https://skmtc.dev/philterd/apis/philter-api/llms.txt) - [OpenAPI document](https://skmtc.dev/philterd/apis/philter-api/revisions/aa3d7ad1aab4?raw)
