<Intro>

<EndpointHeader />

<Description>

Creates a verification for a recipient and sends them a one-time passcode. Provide the recipient in `to`: an email address (verified over email), a phone number (verified over SMS), or both. With both, the passcode is sent over one channel at a time and delivery falls over to the other channel if the first fails; it is never sent to both at once.

Calling this again for the same recipient resumes the verification in progress rather than starting a second one: within the resend cooldown the request returns the current state without sending, and after it a fresh passcode is sent. Use the same call to send and to resend.

The `200` response is the verification's current state; the passcode itself is never returned. Submit the passcode the recipient enters with POST /v1/verify/verifications/check before the verification's `expires_at`. An invalid recipient returns `422`, and requesting passcodes for the same recipient too often returns `429`.

</Description>

</Intro>

<Payload kind="request">

<Field name="to" type="object" required>

<Description>

The recipient to verify. Provide an `email_address`, a `phone_number`, or both; at least one is required. The addresses also identify the verification: a check must supply exactly the set used on the create call, so a verification created with both addresses is not found by either one alone.

</Description>

<FieldChildren kind="request">

<Field name="email_address" type="string" prefix="to.">

<Description>

The recipient's email address. Case does not matter; the address is lowercased before use.

</Description>

</Field>

<Field name="phone_number" type="string" prefix="to.">

<Description>

The recipient's phone number in E.164 format, with the leading `+` and country code (for example `+15551234567`). A number in any other format is rejected as an invalid recipient (`422`).

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="options" type="object">

<Description>

Per-request overrides applied to this verification only.

</Description>

<FieldChildren kind="request">

<Field name="code_length" type="integer" prefix="options.">

<Description>

Passcode length for this verification. Omit to use the configured length.

</Description>

</Field>

<Field name="channels" type="array of string" prefix="options.">

<Description>

Reorder or narrow the delivery channels for this request. List channel names in the order to try them; a channel you omit is not used for this request, and a channel not already enabled for the recipient is ignored. A list that leaves no usable channel fails the request with `422`. Omit the field to use the configured order.

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="metadata" type="object">

<Description>

Optional key/value pairs to attach to the verification, for example a correlation id. Returned on the verification.

</Description>

</Field>

</Payload>

<Payload kind="response">

<Field name="id" type="string" required />

<Field name="status" type="string" required>

<Description>

The verification's current state: `pending` (the initial state, awaiting a correct passcode), `verified` (a correct passcode was submitted), `failed` (too many incorrect attempts), `expired` (the time window elapsed before a correct passcode), `canceled` (the verification was canceled before completing), or `blocked` (it was stopped by a fraud or abuse control).

</Description>

<Description>

Possible values: `pending`, `verified`, `failed`, `expired`, `canceled`, `blocked`

</Description>

</Field>

<Field name="reason" type="nullable string">

<Description>

Why the verification reached its final state: `attempts_exhausted` (too many incorrect passcodes) or `ttl_elapsed` (the time window elapsed before a correct passcode). Null while `pending` and once `verified`. Open enum; treat any unrecognized value as a future reason.

</Description>

<Description>

Possible values (may grow over time): `attempts_exhausted`, `ttl_elapsed`

</Description>

</Field>

<Field name="to" type="object" required>

<Description>

The recipient to verify. Provide an `email_address`, a `phone_number`, or both; at least one is required. The addresses also identify the verification: a check must supply exactly the set used on the create call, so a verification created with both addresses is not found by either one alone.

</Description>

<FieldChildren kind="response">

<Field name="email_address" type="string" prefix="to.">

<Description>

The recipient's email address. Case does not matter; the address is lowercased before use.

</Description>

</Field>

<Field name="phone_number" type="string" prefix="to.">

<Description>

The recipient's phone number in E.164 format, with the leading `+` and country code (for example `+15551234567`). A number in any other format is rejected as an invalid recipient (`422`).

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="channels" type="array of object" required>

<Description>

The channels this verification uses to deliver the passcode, in attempt order: the first entry is tried first and later entries are fallbacks. An email recipient is verified over email; a phone recipient is verified over SMS.

</Description>

<FieldChildren kind="response">

<Field name="channel" type="string" prefix="channels." required>

<Description>

The channel a passcode is delivered over. Open enum — new channels may be added over time, so treat any unrecognized value as a future channel rather than an error.

</Description>

<Description>

Possible values (may grow over time): `email`, `sms`, `whatsapp`

</Description>

</Field>

</FieldChildren>

</Field>

<Field name="last_channel" type="nullable string">

<Description>

The channel the most recent passcode was sent on, or null before the first send. Open enum; new channels may be added over time, so treat any unrecognized value as a future channel rather than an error.

</Description>

<Description>

Possible values (may grow over time): `email`, `sms`, `whatsapp`

</Description>

</Field>

<Field name="metadata" type="object">

<Description>

The key/value pairs attached when the verification was created.

</Description>

</Field>

<Field name="expires_at" type="string" required>

<Description>

When the verification expires if no correct passcode is submitted first. After this time its status reports `expired`.

</Description>

</Field>

<Field name="verified_at" type="nullable string">

<Description>

When the verification was completed, or null if it is not yet verified.

</Description>

</Field>

<Field name="created_at" type="string" required />

<Field name="updated_at" type="string" required />

</Payload>