---
title: "Mfa Enroll"
method: POST
path: "/api/v1/auth/mfa/enroll"
tags: ["auth"]
---

# Mfa Enroll

`POST /api/v1/auth/mfa/enroll`

## Request

- Base URL: `https://api.accurecord.io` (the document declares no server; this is the origin it was published from)
- URL: `https://api.accurecord.io/api/v1/auth/mfa/enroll`
- Auth: none declared

Begin enrolment: mint a secret and return the provisioning URI.

This does NOT enable MFA. The secret is stored but `mfa_enabled` stays false until
/mfa/verify proves the user can actually generate a code — otherwise starting
enrolment and then losing the authenticator app would lock the account out.

The provisioning URI contains the shared secret, so it is returned exactly once here
and is never written to a log or an audit `detail`.

## Cookies

- `access_token` string, nullable

## Response `200`

Successful Response

- object

## Other responses

- `400`: Malformed or out-of-bounds request — a batch over 50 codes, a file over the upload limit, an unparseable identifier, or a surface that is switched off in this environment (the `cpt_*_disabled` gates are 400, not 403). ⚠ Not interchangeable with 422: 400 is raised BY the handler, 422 by request validation.
- `401`: Missing, malformed, revoked or expired credential. Send the key as `X-API-Key` or `Authorization: Bearer`. `detail` is a string, except the MFA challenge on `/auth/login`, which is `{code: 'mfa_required', message}`.
- `403`: Authenticated but not permitted: the tier does not include the feature, the role is insufficient, or the free tier is paused. Gate-specific bodies use the `{code, message}` shape (`tier_required`, `insufficient_role`). ⚠ The free-tier pause is the ONE error in the service that does not use `detail` at all — its body is `{error: 'free_tier_paused', message}` at the top level. ⚠ Preconditions the caller CAN satisfy (no org, no BAA, PHI mode off) are 412, not 403 — see below.
- `404`: Resource, code, or org-scoped record not found. Note that a record belonging to ANOTHER organization is also a 404, never a 403 — existence is not disclosed across tenants.
- `412`: A precondition on the calling principal is unmet and the caller can fix it: no organization linked to the key (`org_required`), no signed BAA (`baa_required`), PHI mode not activated (`phi_not_activated`), reviewer mode off (`review_mode_disabled`), or the session was never second-factored (`mfa_required`). All use the `{code, message}` shape.
- `422`: Request body or query failed validation. FastAPI's own failures are a LIST of `{loc, msg, type}`; semantic refusals raised by the service are an object (the risk-adjustment endpoints use `{status, ...}`).
- `429`: Rate limit, quota or concurrency cap exceeded. The tier limiter, the per-key chart-review job cap, the anonymous demo cap and the auth/signup limiters all land here; only the tier limiter sets the `X-RateLimit-*` headers.
- `500`: Unhandled server error. The body is `{detail: 'Internal server error', request_id: <id>}` and the same id is on the `X-Request-ID` response header.
- `503`: A dependency this request needed is unavailable — the database, an upstream model provider, or reference data that is present but not READY. Retry is reasonable, except for the risk-adjustment `blocked_pack_not_ready` refusals, which stay 503 until the coefficient pack is actually loaded.

---

[API](https://skmtc.dev/accurecord/apis/icd-10-coding-api.md) · [All operations](https://skmtc.dev/accurecord/apis/icd-10-coding-api/llms.txt) · [OpenAPI document](https://skmtc.dev/accurecord/apis/icd-10-coding-api/revisions/b1e12ce06ba5?raw)
