# SMS

Use the **SMS** delivery method to send a one-time code in a text message. The user enters
the code in your application, and your application reports it to the Verification API.

---

## How it works

1. You start a verification with `delivery_method` set to `sms`.
2. The Verification API sends a text message containing a newly generated numeric code to the
   destination. The code length is set on the OTP application.
3. The user enters the code in your application.
4. Your application reports the `code` to the
   [report endpoint](../api-reference/report-verification.html#otp-verification-api-report).
5. If the code matches, the verification status becomes `verified`.

By default, the message is sent from a DIDWW sender ID. An OTP application can select its
account's own approved Sender IDs in the **SMS settings** section of the User Panel; a
verification then sends from one of those that covers the destination country, falling back
to the DIDWW sender ID otherwise.

## Starting an SMS verification

Set `delivery_method` to `sms`. Add optional SMS settings in an `sms` object inside
`data`. The API reads this object only when `delivery_method` is `sms`.

Use `languages` to select the preferred message-template languages. Use `app_hash` with
Android SMS Retriever so a compatible Android application can capture the incoming code
automatically.

The following example uses HTTP Basic authentication and requests the `en-US` message
template:

http

```
POST /api/v1/verifications HTTP/1.1
Host: verification.didww.com
Content-Type: application/json
Accept: application/json
Authorization: Basic eW91cl9hcHBfa2V5OnlvdXJfYXBwX3NlY3JldA==

{
  "data": {
    "destination": "+4915112345678",
    "delivery_method": "sms",
    "sms": {
      "languages": ["en-US"]
    }
  }
}
```

curl

```
curl -i -X POST https://verification.didww.com/api/v1/verifications -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"data": {"delivery_method": "sms", "destination": "+4915112345678", "sms": {"languages": ["en-US"]}}}' --user your_app_key:your_app_secret
```

response

```
HTTP/1.1 201 Created
Content-Type: application/json

{
  "data": {
    "id": "0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21",
    "destination": "4915112345678",
    "delivery_method": "sms",
    "fee": "0.06",
    "status": "pending",
    "error_code": null,
    "error_detail": null,
    "expires_at": "2026-07-15T10:05:00.000Z",
    "sms": {
      "template": "Your code is {{CODE}}",
      "language": "en-US",
      "interception_timeout": 300,
      "code_length": 6
    }
  }
}
```

This response shows an approved start with `status` `pending`. A `201 Created` response
can also contain `status` `denied` when a request callback rejects the verification.
Always inspect `status` and `error_code`.

A `pending` status means the verification was accepted for delivery. It does not confirm
that the text message reached the destination.

The response includes an `sms` object containing SMS-specific information:

- `template` contains the message template. `{{CODE}}` marks where the generated code
  appears.
- `language` is the language the API selected, which is not necessarily the first one
  requested. Compare it with the list you sent to detect a fallback to `en-US`.
- `interception_timeout` specifies, in seconds, how long an on-device SMS listener should
  remain active. It equals the verification lifetime set by the OTP application's **Code
  timeout**. It does not control verification expiry. Manual code entry remains available until
  `expires_at`.
- `code_length` is the number of digits in the code sent for this verification, from 4 to 8.
  Use it to size the code input field.
- `app_hash` is returned only when the supplied hash was accepted and stored for the
  verification.

## Supported languages

Pass `sms.languages` as BCP 47 tags, most preferred first. The first supported tag wins;
if none of them is supported, the message is sent in `en-US`.

Tags are matched **exactly**, so the region subtag is required: `pl` does not match
`pl-PL` and falls back to `en-US`. A tag that is not a well-formed BCP 47 tag is
rejected with [languages\_invalid](../api-reference/errors.html#otp-verification-api-errors) instead.

Read `sms.language` from the response to see which language was actually used.

The following language tags are supported:

| BCP 47 tag | Language |
| --- | --- |
| `bg-BG` | Bulgarian (Bulgaria) |
| `bs-BA` | Bosnian (Bosnia and Herzegovina) |
| `cs-CZ` | Czech (Czechia) |
| `da-DK` | Danish (Denmark) |
| `de-DE` | German (Germany) |
| `el-GR` | Greek (Greece) |
| `en-GB` | English (United Kingdom) |
| `en-US` | English (United States) |
| `es-419` | Spanish (Latin America) |
| `es-ES` | Spanish (Spain) |
| `et-EE` | Estonian (Estonia) |
| `fi-FI` | Finnish (Finland) |
| `fr-FR` | French (France) |
| `he-IL` | Hebrew (Israel) |
| `hr-HR` | Croatian (Croatia) |
| `hu-HU` | Hungarian (Hungary) |
| `is-IS` | Icelandic (Iceland) |
| `it-IT` | Italian (Italy) |
| `ja-JP` | Japanese (Japan) |
| `ka-GE` | Georgian (Georgia) |
| `lt-LT` | Lithuanian (Lithuania) |
| `lv-LV` | Latvian (Latvia) |
| `mk-MK` | Macedonian (North Macedonia) |
| `ms-MY` | Malay (Malaysia) |
| `mt-MT` | Maltese (Malta) |
| `nb-NO` | Norwegian Bokmål (Norway) |
| `nl-NL` | Dutch (Netherlands) |
| `pl-PL` | Polish (Poland) |
| `pt-BR` | Portuguese (Brazil) |
| `pt-PT` | Portuguese (Portugal) |
| `ro-RO` | Romanian (Romania) |
| `ru-RU` | Russian (Russia) |
| `sk-SK` | Slovak (Slovakia) |
| `sl-SI` | Slovenian (Slovenia) |
| `sq-AL` | Albanian (Albania) |
| `sr-RS` | Serbian (Serbia) |
| `sv-SE` | Swedish (Sweden) |
| `th-TH` | Thai (Thailand) |
| `uk-UA` | Ukrainian (Ukraine) |
| `zh-CN` | Chinese Simplified (China) |
| `zh-HK` | Chinese Traditional (Hong Kong) |

## Reporting the code

Submit the code the user received. The `delivery_method` must match the verification.
The following example reports a correct code and returns `status` `verified`:

http

```
PATCH /api/v1/verifications/0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21 HTTP/1.1
Host: verification.didww.com
Content-Type: application/json
Accept: application/json
Authorization: Basic eW91cl9hcHBfa2V5OnlvdXJfYXBwX3NlY3JldA==

{
  "data": {
    "delivery_method": "sms",
    "code": "123456"
  }
}
```

curl

```
curl -i -X PATCH https://verification.didww.com/api/v1/verifications/0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21 -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"data": {"code": "123456", "delivery_method": "sms"}}' --user your_app_key:your_app_secret
```

response

```
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "id": "0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21",
    "destination": "4915112345678",
    "delivery_method": "sms",
    "fee": "0.06",
    "status": "verified",
    "error_code": null,
    "error_detail": null,
    "expires_at": "2026-07-15T10:05:00.000Z",
    "sms": {
      "template": "Your code is {{CODE}}",
      "language": "en-US",
      "interception_timeout": 300,
      "code_length": 6
    }
  }
}
```

The response above shows a successful report. The API returns `200 OK` with `status`
`verified` when the submitted code matches.

If the submitted code is incorrect, the API returns the following response:

```
HTTP/1.1 422 Unprocessable Content
Content-Type: application/json

{
  "errors": [
    {
      "code": "code_invalid",
      "detail": "code is invalid"
    }
  ]
}
```

After an incorrect report, the verification remains `pending`, and the user can submit
another code until the attempt limit is reached. After three unsuccessful reports, the
verification becomes `failed` with `error_code` `too_many_attempts`.

## Next steps

- [Start a verification](../api-reference/start-verification.html#otp-verification-api-start): Review all start-request and response fields.
- [Report a verification](../api-reference/report-verification.html#otp-verification-api-report): Review all report-request and response fields.

On this page
