Email and SMS OTP

Map delivery fields and implement enrollment, challenge, resend, verification, status, and disable flows.

PrerequisitesAuth Apps overview

Auth Apps separates transport fields (populated on every send), message template variables, and connector meta (user-defined).

Delivery templates and message templates are configured in the Cliodot portal. At runtime you may override content per send with custom_subject and custom_body.

Standard delivery fields#

Email field SMS field Variable
To Phone {{delivery.to}} / {{delivery.phone}}
CC {{delivery.cc}}
BCC {{delivery.bcc}}
Subject {{delivery.subject}}
Message Message {{delivery.message}}
HTML {{delivery.body_html}}
Text Text {{delivery.body_text}}
Magic link URL Magic link URL {{delivery.magic_link_url}}
Attachments Attachments {{delivery.attachments}}

Flat aliases: {{to}}, {{subject}}, {{message}}, {{phone}}, {{html}}, {{text}}.

Message template variables#

{{code}}, {{magic_link_url}}, {{magic_link_expiration_minutes}}, {{user.display_name}}, {{user.email}}, {{user.external_user_id}}, {{app.name}}, {{expires_minutes}}, {{sender_name}}, {{sender_email}}

Content priority at send: runtime custom_subject / custom_body → app inline custom (portal) → message template slug (portal) → system default.

Connector meta#

Map connector-specific inputs with {{meta.your_key}}:

  • Static values: configured on the auth app in the portal (email_otp_delivery.meta_values, etc.)
  • Per-send override: { "meta": { "campaign_id": "login" } } in runtime request body


Provider path segment: email_otp. Shared request body fields for send endpoints (enroll, challenge, resend):

Field Type Description
email string Recipient email (or rely on upserted user)
custom_subject string Override message subject
custom_body string Override message body
cc string Email CC override
bcc string Email BCC override
attachments array Attachment overrides
meta object Connector meta overrides

Email OTP — Enroll

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/email_otp/enroll
Auth App credentials
Description Enroll email OTP and send first code via configured delivery template.

Sample success response 200

{
 "ok": true,
 "sent": true,
 "expires_at": "2026-07-09T12:10:00.000Z"
}

Queued send (resend_mode: queue during cooldown):

{
 "ok": true,
 "queued": true,
 "position": 2,
 "scheduled_at": "2026-07-09T12:02:00.000Z"
}

Common errors: 422 AUTH_DESTINATION_REQUIRED, 422 AUTH_METHOD_NOT_ENABLED, 429 AUTH_RESEND_COOLDOWN, 502 AUTH_DELIVERY_FAILED

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/enroll" \
 -H "Authorization: Bearer YOUR_APP_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{"email": "user@example.com", "custom_subject": "Your login code", "custom_body": "Enter {{code}} to sign in"}'

Email OTP — Challenge

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/email_otp/challenge
Auth App credentials
Description Request a new email OTP code (login challenge).

Request body: Same as enroll.

Sample success response 200

{
 "ok": true,
 "sent": true,
 "expires_at": "2026-07-09T12:10:00.000Z"
}

Common errors: 429 AUTH_RESEND_COOLDOWN, 429 AUTH_RESEND_QUEUE_FULL, 422 AUTH_DESTINATION_REQUIRED

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/challenge" \
 -H "Authorization: Bearer YOUR_APP_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{"email": "user@example.com"}'

Email OTP — Resend

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/email_otp/resend
Auth App credentials
Description Resend the current email OTP code.

Request body: Same as enroll.

Sample success response 200

{
 "ok": true,
 "sent": true,
 "expires_at": "2026-07-09T12:10:00.000Z"
}

Common errors: 429 AUTH_RESEND_COOLDOWN, 429 AUTH_RESEND_QUEUE_FULL

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/resend" \
 -H "Authorization: Bearer YOUR_APP_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{"email": "user@example.com"}'

Email OTP — Verify

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/email_otp/verify
Auth App credentials
Description Verify email OTP code. Failed verification returns { ok: true, verified: false } without leaking validity details.

Request body: code (string, required)

Sample success response 200

{
 "ok": true,
 "verified": true,
 "method": "email_otp",
 "enrollment_status": "active",
 "verified_at": "2026-07-09T11:30:00.000Z"
}

Common errors: 410 AUTH_OTP_EXPIRED, 423 AUTH_USER_LOCKED

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/verify" \
 -H "Authorization: Bearer YOUR_APP_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{"code": "123456"}'

Email OTP — Disable

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/email_otp/disable
Auth App credentials
Description Disable email OTP factor for a user.

Sample success response 200

{
 "ok": true,
 "disabled": true
}

Common errors: 404 AUTH_ENROLLMENT_NOT_FOUND, 404 AUTH_MFA_NOT_ENABLED

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/disable" \
 -H "Authorization: Bearer YOUR_APP_API_KEY"

Email OTP — Status

Method GET
Path /auth/apps/:appId/users/:externalUserId/providers/email_otp/status
Auth App credentials
Description Get email OTP factor enrollment status.

Sample success response 200

{
 "ok": true,
 "factor_type": "email_otp",
 "enrollment_status": "active",
 "mfa_enabled": true,
 "destination_masked": "u***@example.com"
}

cURL

curl "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/email_otp/status" \
 -H "Authorization: Bearer YOUR_APP_API_KEY"

SMS OTP#

Provider path segment: sms_otp. Shared request body fields for send endpoints:

Field Type Description
phone string Recipient phone number
phone_country_code string Country code (e.g. US)
custom_body string Override SMS body
meta object Connector meta overrides

SMS OTP — Enroll

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/sms_otp/enroll
Auth App credentials
Description Enroll SMS OTP and send first code via configured delivery template.

Sample success response 200

{
 "ok": true,
 "sent": true,
 "expires_at": "2026-07-09T12:05:00.000Z"
}

Common errors: 422 AUTH_DESTINATION_REQUIRED, 422 AUTH_METHOD_NOT_ENABLED, 429 AUTH_RESEND_COOLDOWN, 502 AUTH_DELIVERY_FAILED

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/enroll" \
 -H "Authorization: Bearer YOUR_APP_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{"phone": "4155550100", "phone_country_code": "US"}'

SMS OTP — Challenge

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/sms_otp/challenge
Auth App credentials
Description Request a new SMS OTP code (login challenge).

Request body: Same as enroll.

Sample success response 200

{
 "ok": true,
 "sent": true,
 "expires_at": "2026-07-09T12:05:00.000Z"
}

Common errors: 429 AUTH_RESEND_COOLDOWN, 422 AUTH_DESTINATION_REQUIRED

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/challenge" \
 -H "Authorization: Bearer YOUR_APP_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{"phone": "4155550100", "phone_country_code": "US"}'

SMS OTP — Resend

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/sms_otp/resend
Auth App credentials
Description Resend the current SMS OTP code.

Request body: Same as enroll.

Sample success response 200

{
 "ok": true,
 "sent": true,
 "expires_at": "2026-07-09T12:05:00.000Z"
}

Common errors: 429 AUTH_RESEND_COOLDOWN, 429 AUTH_RESEND_QUEUE_FULL

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/resend" \
 -H "Authorization: Bearer YOUR_APP_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{"phone": "4155550100"}'

SMS OTP — Verify

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/sms_otp/verify
Auth App credentials
Description Verify SMS OTP code.

Request body: code (string, required)

Sample success response 200

{
 "ok": true,
 "verified": true,
 "method": "sms_otp",
 "enrollment_status": "active",
 "verified_at": "2026-07-09T11:30:00.000Z"
}

Common errors: 410 AUTH_OTP_EXPIRED, 423 AUTH_USER_LOCKED

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/verify" \
 -H "Authorization: Bearer YOUR_APP_API_KEY" \
 -H "Content-Type: application/json" \
 -d '{"code": "123456"}'

SMS OTP — Disable

Method POST
Path /auth/apps/:appId/users/:externalUserId/providers/sms_otp/disable
Auth App credentials
Description Disable SMS OTP factor for a user.

Sample success response 200

{
 "ok": true,
 "disabled": true
}

Common errors: 404 AUTH_ENROLLMENT_NOT_FOUND

cURL

curl -X POST "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/disable" \
 -H "Authorization: Bearer YOUR_APP_API_KEY"

SMS OTP — Status

Method GET
Path /auth/apps/:appId/users/:externalUserId/providers/sms_otp/status
Auth App credentials
Description Get SMS OTP factor enrollment status.

Sample success response 200

{
 "ok": true,
 "factor_type": "sms_otp",
 "enrollment_status": "active",
 "mfa_enabled": true,
 "destination_masked": "***0100"
}

cURL

curl "https://api.example.com/auth/apps/auth_app_507f1f77bcf86cd799439011/users/user_123/providers/sms_otp/status" \
 -H "Authorization: Bearer YOUR_APP_API_KEY"