---
title: "Start MFA enrollment."
method: POST
path: "/api/users/me/mfa"
tags: ["Users"]
---

# Start MFA enrollment.

`POST /api/users/me/mfa`

## Request

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

Generates a TOTP secret for the calling key's own user and returns it, with an otpauth:// URI to show as a QR code. The secret is returned only here and is encrypted at rest. Enrollment takes effect only once POST /api/users/me/mfa/confirm sees a valid code; starting again replaces an unconfirmed secret. Takes the user's current password, so a stolen key cannot enroll an authenticator of its own; a wrong password counts toward the sign-in lockout. Requires the mfaAvailable setting, and the scope but not an administrator. Requires the `users:write` scope.

## Headers

- `Authorization` string, required

## Request body

- StartMfaEnrollmentRequest
  - `password` string

## Response `200`

The secret to set up an authenticator app with.

- MfaEnrollmentResponse
  - `otpauthUri` string: The otpauth:// URI to show as a QR code for an authenticator app to scan.
  - `secret` string: The setup key, Base32, for entering by hand. Returned only here.

## Other responses

- `400`: The password is missing.
- `401`: The Authorization header is absent or the API key is not recognized.
- `403`: The key does not hold users:write, or the password is not correct (reason wrong_password).
- `404`: Not Found
- `406`: No representation matches Accept.
- `409`: MFA is not available on this deployment, the user is already enrolled, or the user has no password.
- `413`: Content Too Large
- `415`: Unsupported Media Type
- `429`: The user's sign-in is locked after repeated failures; reason is locked.
- `500`: Internal Server Error
- `503`: Service Unavailable

## Changes

- **2026-10-17** `40f39dc6cf17`: 1 breaking
  - request body became required
- **2026-10-17** `efb892fa7bba`: 2 info
  - added optional request body
  - added the non-success response with the status `429`
- **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-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** `2cd7275cfcb5`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/philterd/apis/philter-api/changes/api/users/me/mfa/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)
