# Overview

**OTP Verification** confirms that a user actually controls a phone number. DIDWW delivers a
one-time code by SMS or voice. Your application confirms the user by reporting the code.

The service combines a hosted REST API with client [SDKs](sdks/index.html#otp-verification-sdks), so
you can drive verifications from your backend, your mobile app, or both. Use it wherever a
real, reachable phone number matters: securing sign-ups and logins, adding a second factor
to sensitive actions, confirming a number before you provision a service, or reducing fraud
and fake accounts.

---

## What OTP verification does

OTP Verification manages the verification attempt from start to finish. After you create an
OTP application and authenticate your request, your application starts a verification for a
destination number and chooses a supported delivery method. DIDWW delivers the challenge,
tracks the attempt, and lets your application report the result or retrieve the latest
status.

A verification has three main parts:

- **Destination**: the phone number you want to verify.
- **Delivery method**: the channel used to send the challenge.
- **Report**: the code that your application sends back to confirm the user.

The API keeps the verification state, returns the current status, and provides
machine-readable error information when the verification cannot be completed.

## Supported verification methods

Every verification delivers a challenge over one channel, chosen per request with the
`delivery_method` field. SMS and phone call both deliver a numeric **code** for the user to
report. The code has 4 to 8 digits (6 by default), as set by the **Code length** of the OTP
application.

| Method | API value | User reports | How the user is challenged |
| --- | --- | --- | --- |
| [SMS](verification-methods/sms.html#otp-verification-method-sms) | `sms` | `code` | A text message carrying the one-time code is sent to the number. The most familiar channel for end users. |
| [Phone Call](verification-methods/phone-call.html#otp-verification-method-phone-call) | `callout` | `code` | A call is placed and reads the one-time code aloud. Useful where SMS is unreliable or for landline numbers. |

Note

Supported mobile [SDKs](sdks/index.html#otp-verification-sdks) can streamline these flows on the
device, for example by automatically capturing SMS codes where supported. Over the REST
API, your application collects the code from the user and reports it.

## How a verification works

Every verification follows the same three-step lifecycle regardless of delivery method:

```
        %%{init: {
  "theme": "base",
  "themeVariables": {
    "actorBkg": "#e0f2fe",
    "actorBorder": "#38bdf8",
    "actorTextColor": "#1f2d3d",
    "signalColor": "#1f2d3d",
    "signalTextColor": "#1f2d3d",
    "activationBkgColor": "#fef3c7",
    "activationBorderColor": "#facc15",
    "labelBoxBkgColor": "#ccfbf1",
    "labelBoxBorderColor": "#2dd4bf",
    "labelTextColor": "#1f2d3d"
  }
}}%%

sequenceDiagram
    participant App as Your application
    participant API as Verification API
    participant User as End user

    App->>API: POST /api/v1/verifications (start)
    API->>User: Deliver code / place call
    API-->>App: 201 Created - verification id, status: pending
    User->>App: Enters code
    App->>API: PATCH /api/v1/verifications/{id} (report)
    API-->>App: 200 OK - status: verified / failed
    App->>API: GET /api/v1/verifications/{id} (status, optional)
    API-->>App: 200 OK - current status
```

1. **Start**: call [POST /api/v1/verifications](api-reference/start-verification.html#otp-verification-api-start) with the
   destination number and delivery method. DIDWW routes the request, delivers the challenge,
   and returns a verification `id` with status `pending`.
2. **Report**: when the user submits the code, call
   [PATCH /api/v1/verifications/{id}](api-reference/report-verification.html#otp-verification-api-report) with the `code`.
   The response carries the resulting status.
3. **Status**: at any time, call
   [GET /api/v1/verifications/{id}](api-reference/get-verification-status.html#otp-verification-api-status) to read the current
   status.

Each verification is short-lived: it expires after the **Code timeout** set on its OTP
application (60 to 600 seconds, 300 by default), counted from when it is created and returned
as `expires_at`. The value may be reported at most three times before the verification fails.

An OTP application cannot start a new verification for the same number within 30 seconds of
the previous one, unless the previous one was denied. Such a request is rejected with `429 Too Many Requests` and a
`Retry-After` header.
See [Errors and status codes](api-reference/errors.html#otp-verification-api-errors).

## Using the SDKs and the REST API

You can integrate at whichever layer fits your architecture:

- **Backend, server-to-server**: start and report verifications directly from your server
  with the REST API or a server [SDK](sdks/index.html#otp-verification-sdks), keeping your application
  secret private. This is the simplest setup.
- **Untrusted clients with a gate**: when a verification originates from a device or browser
  that only holds a public key, add a [request callback](callbacks.html#otp-verification-callbacks).
  DIDWW calls your backend before delivering anything, and your server approves or rejects
  the attempt in real time.

Whichever layer you choose, authenticate with the right
[auth mode](authentication.html#otp-verification-authentication) for the trust level of the caller, and
consider a request callback to keep control on your own server.

## Verification status

The `status` field on a verification is one of:

| Status | Meaning |
| --- | --- |
| `pending` | The verification has been started and is awaiting the user's report. |
| `verified` | The reported code matched, and the number is confirmed. |
| `failed` | The verification could not be completed because of a wrong code, too many attempts, delivery failure, or expiry before a correct report. |
| `expired` | The verification lifetime elapsed without a successful report. |
| `denied` | The verification was rejected before delivery, typically by your [request callback](callbacks.html#otp-verification-callbacks). |

When a verification is not successful, the `error_code` field carries a machine-readable
explanation and `error_detail` carries the matching human-readable text. See
[Errors and Status Codes](api-reference/errors.html#otp-verification-api-errors) for the full list of error codes
and HTTP status codes.

## Next steps

Start with [Getting Started](getting-started.html#otp-verification-getting-started) to create an OTP
application and prepare your credentials. Then review
[Authentication](authentication.html#otp-verification-authentication), choose the [Verification
Methods](verification-methods/index.html#otp-verification-methods) that fit your product flow, or pick an
[SDK](sdks/index.html#otp-verification-sdks) for your language.

If you use AI coding tools to build an integration, see [AI Best Practices](ai-best-practices.html#otp-verification-ai).

On this page
