Both endpoints require a real user JWT — TOTP is a step-up factor attached to an already-authenticated user, not a standalone login. See TOTP for why, plus the real period/tolerance/replay-guard values.
POST /api/v1/totp/enroll
Authorization: Bearer <threshold1_jwt>
Content-Type: application/json
{}
Real response, captured live:
{
"success": true,
"otpauthUrl": "otpauth://totp/Docs%20Quickstart%20Test%20App:user%40example.com?secret=Z5RUW4BPQBRJI5QXGLFDJ5KQHN5NYOJS&issuer=Docs%20Quickstart%20Test%20App",
"qrCodeDataUrl": "data:image/png;base64,iVBORw0KG...",
"secret": "Z5RUW4BPQBRJI5QXGLFDJ5KQHN5NYOJS"
}
Show qrCodeDataUrl for scanning, or secret for manual entry into an authenticator app.
POST /api/v1/totp/verify
Authorization: Bearer <threshold1_jwt>
Content-Type: application/json
{ "code": "783458" }
Real response — verified with a code computed live from the real secret above (standard RFC 6238 TOTP, HMAC-SHA1, 30-second period):
{ "success": true, "enrolled": true }
The first successful call after /enroll completes enrollment. Every later call is an ordinary step-up check — same endpoint, same response shape.
A wrong or reused code returns invalid_code — see Error Reference. Unlike OTP, there's no rate limit on this endpoint at all — a real, verified fact, not a gap (see the Methods Reference page for why).