1. Docs
  2. API Reference
  3. Complete authenticator app enrollment

Complete authenticator app enrollment

POST/v1/auth/mfa/totp/enroll/verify

Completes authenticator-app enrollment by checking the 6-digit code against the secret sealed in enrollment_token and storing the factor under label. The administrator's first factor also returns a one-time batch of ten recovery codes, the only way back in without the device, and clears any running grace timer. Responds 400 when the token is missing, expired, sealed for another user, or the code does not match. Rate-limited to 10 requests per minute.

Authentication

Bearer TokenAuthorization

JWT access token. Never send alongside X-API-Key: a request carrying both is refused.

Request body

application/json

enrollment_tokenstring Required

The sealed enrollment_token returned by the `start` endpoint. Carries the provisional TOTP secret server-side.

codestring Required

6-digit code from the authenticator app.

labelstring Required

User-facing nickname for the factor ("iPhone 15", "Work Laptop"). Shown on the factor-management surface.

max length 80

Responses

application/json

  • dataMfaTotpEnrollVerifyResponseDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

application/json

  • errorApiErrorBodyDto*

Rate limit

10 requests per 1mPer caller: the signed-in user for a bearer token; for an API key, the key and the end user's address when a backend forwards it, otherwise the client address

Returned object

Request
curl -X POST "https://auth.canopy-io.com/v1/auth/mfa/totp/enroll/verify" \
  -H "Authorization: Bearer $CANOPY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enrollment_token": "string",
    "code": "123456",
    "label": "iPhone 15"
  }'
Response
{
  "data": {
    "factor": {
      "id": "00000000-0000-0000-0000-000000000000",
      "type": "totp",
      "label": "iPhone 15",
      "enrolled_at": "2026-04-20T12:00:00.000Z",
      "last_used_at": "2026-04-20T12:00:00.000Z",
      "webauthn_rp_id": "acme.com"
    },
    "recovery_codes": [
      "ABCD-EFGH-IJKL-MNOP",
      "QRST-UVWX-YZ23-4567",
      "..."
    ],
    "recovery_codes_generation": 0
  }
}
Related endpoints
GETList the caller's enrolled second factors
POSTBegin authenticator app enrollment
POSTBegin passkey enrollment
POSTComplete passkey enrollment
POSTProve a fresh second factor before a sensitive change
POSTBegin a passkey step-up
POSTComplete a passkey step-up
DELETERemove one of the caller's second factors
GETHow many recovery codes the caller has left
POSTRegenerate the caller's recovery codes
GETList the caller's remembered devices
DELETEForget every remembered device
DELETEForget one remembered device
Was this page helpful?

Tell us how we can improve this guide.