> ## Documentation Index
> Fetch the complete documentation index at: https://docs.otp.id/llms.txt
> Use this file to discover all available pages before exploring further.

# OTP Delivery Channels: WhatsApp, SMS, Email & More

> OTP.ID supports five delivery channels: WhatsApp, SMS, Email, Missed Call, and WhatsApp Inbound. Learn when to use each and what restrictions apply.

OTP.ID can deliver one-time passwords through five distinct channels, each suited to different user environments and trust requirements. When you create an OTP transaction with `POST /v3/request` or `POST /v3/send`, you select a channel by setting the `channel` field in your request body. This page explains how each channel works, what field values to use, and what behaviours or restrictions apply.

## Channel Summary

The table below gives a quick overview of all five channels before you dive into the details.

| Channel          | `channel` value    | Delivery method           | Works with `/v3/send`? | `number` required?       |
| ---------------- | ------------------ | ------------------------- | ---------------------- | ------------------------ |
| WhatsApp         | `whatsapp`         | Outbound WhatsApp message | ✅ Yes                  | ✅ Yes                    |
| SMS              | `sms`              | Outbound SMS              | ✅ Yes                  | ✅ Yes                    |
| Email            | `email`            | Outbound email            | ✅ Yes                  | ✅ Yes (or `email` field) |
| Missed Call      | `misscall`         | Inbound missed call       | ✅ Yes                  | ✅ Yes                    |
| WhatsApp Inbound | `whatsapp_inbound` | User-initiated WhatsApp   | ❌ No                   | ⬜ Optional               |

<Note>
  `whatsapp_inbound` is the **only channel** that cannot be used with `POST /v3/send`. It is exclusively available through `POST /v3/request`.
</Note>

***

## Channel Details

<Tabs>
  <Tab title="WhatsApp">
    ### WhatsApp (`whatsapp`)

    OTP.ID sends an outbound WhatsApp message containing the one-time password directly to your user's phone number. The message is delivered through OTP.ID's WhatsApp Business integration and appears in the user's WhatsApp inbox.

    **`channel` field value:** `whatsapp`

    **Compatible endpoints:** `POST /v3/request`, `POST /v3/send`

    **Required fields:**

    * `number` — The destination phone number in international format, digits only, minimum 10 characters (e.g. `6281234567890`).

    **Key behaviours:**

    * The OTP appears as a readable message in the user's WhatsApp chat.
    * Delivery depends on the user having an active WhatsApp account linked to the number.
    * If delivery fails (e.g. the number is not registered on WhatsApp), the transaction status is set to `failed` and your balance is not deducted.

    ```json theme={null}
    {
      "channel": "whatsapp",
      "number": "6281234567890"
    }
    ```
  </Tab>

  <Tab title="SMS">
    ### SMS (`sms`)

    OTP.ID delivers the one-time password as a standard SMS text message to the destination phone number. SMS works on virtually any mobile handset without requiring a data connection or a specific messaging application.

    **`channel` field value:** `sms`

    **Compatible endpoints:** `POST /v3/request`, `POST /v3/send`

    **Required fields:**

    * `number` — The destination phone number in international format, digits only, minimum 10 characters (e.g. `6281234567890`).

    **Key behaviours:**

    * SMS is the most universally supported channel — it reaches feature phones, smartphones, and numbers without internet access.
    * Delivery time depends on carrier routing and may be slower than WhatsApp in some regions.
    * If the carrier cannot deliver the message, the transaction status is set to `failed` and your balance is not deducted.

    ```json theme={null}
    {
      "channel": "sms",
      "number": "6281234567890"
    }
    ```
  </Tab>

  <Tab title="Email">
    ### Email (`email`)

    OTP.ID sends the one-time password to an email address. This channel is useful when your users authenticate by email rather than phone number, or when you want to support users who may not have a mobile number available.

    **`channel` field value:** `email`

    **Compatible endpoints:** `POST /v3/request`, `POST /v3/send`

    **Required fields:**

    * `number` **or** `email` — Provide the recipient's email address in either the `number` field or the dedicated `email` field.

    **Key behaviours:**

    * If you supply the email address in the `number` field, OTP.ID treats it as the delivery destination.
    * If you supply both `number` and `email`, the `email` field takes precedence.
    * Delivery depends on the email address being valid and the inbox being reachable (not full, not bouncing).
    * If delivery fails, the transaction status is set to `failed` and your balance is not deducted.

    ```json theme={null}
    {
      "channel": "email",
      "number": "user@example.com"
    }
    ```

    Or using the explicit `email` field:

    ```json theme={null}
    {
      "channel": "email",
      "email": "user@example.com"
    }
    ```
  </Tab>

  <Tab title="Missed Call">
    ### Missed Call (`misscall`)

    OTP.ID places a call to your user's phone number and immediately disconnects — no answer is required. The OTP is the **last N digits of the calling number**, where N equals your configured `otp_length`. The user reads the code from their missed-call log without needing to open any app or have internet access.

    **`channel` field value:** `misscall`

    **Compatible endpoints:** `POST /v3/request`, `POST /v3/send`

    **Required fields:**

    * `number` — The destination phone number in international format, digits only, minimum 10 characters (e.g. `6281234567890`).

    **Key behaviours:**

    * The user does not need to answer the call — OTP.ID disconnects intentionally.
    * The OTP is encoded in the caller ID itself, so there is no message to intercept.
    * Works on any phone that displays a missed-call notification, including feature phones with no data connection.
    * If the call cannot be placed (e.g. number unreachable), the transaction status is set to `failed` and your balance is not deducted.

    <Tip>
      Missed Call is especially effective in markets where SMS delivery is unreliable or where users are sensitive to message-interception risks, since the code never travels as a text payload.
    </Tip>

    ```json theme={null}
    {
      "channel": "misscall",
      "number": "6281234567890"
    }
    ```
  </Tab>

  <Tab title="WhatsApp Inbound">
    ### WhatsApp Inbound (`whatsapp_inbound`)

    WhatsApp Inbound reverses the usual flow: instead of OTP.ID sending a message to your user, **your user sends a WhatsApp message to OTP.ID's central number**. When you create a transaction with this channel, OTP.ID returns a token and pre-filled message template. Your application displays these to the user, who opens WhatsApp and sends the message. OTP.ID detects the incoming message, matches the token, and marks the transaction as verified.

    **`channel` field value:** `whatsapp_inbound`

    **Compatible endpoints:** `POST /v3/request` **only**

    **Required fields:**

    * `number` — **Optional.** If you provide a phone number, OTP.ID only accepts a reply from that specific number (binding mode). If you omit `number`, OTP.ID accepts the first reply containing the matching token from any number.

    **Response — `verification` block:**

    When you create a `whatsapp_inbound` transaction, the response includes a `verification` object with everything you need to guide your user:

    | Field        | Description                                                                |
    | ------------ | -------------------------------------------------------------------------- |
    | `wa_number`  | OTP.ID's central WhatsApp number the user must message                     |
    | `message`    | The exact message text the user must send                                  |
    | `wa_link`    | A deep-link URL that opens WhatsApp with the number and message pre-filled |
    | `expires_at` | The timestamp after which the token is no longer valid                     |

    Your application **must** display this information to the user before the token expires.

    ```json theme={null}
    {
      "channel": "whatsapp_inbound",
      "number": "6281234567890"
    }
    ```

    Example `verification` block in the response:

    ```json theme={null}
    {
      "verification": {
        "wa_number": "628999001234",
        "message": "OTP 6281234567890 ABC123",
        "wa_link": "https://wa.me/628999001234?text=OTP%206281234567890%20ABC123",
        "expires_at": "2026-08-07 10:05:00"
      }
    }
    ```

    <Note>
      `whatsapp_inbound` is the **only channel that cannot be used with `POST /v3/send`**. Attempting to use it with `/v3/send` will return a validation error.
    </Note>
  </Tab>
</Tabs>

***

## Choosing the Right Channel

<Tip>
  **Not sure which channel to pick?** Use this guidance:

  * **WhatsApp** — Best default for markets with high WhatsApp adoption (e.g. Indonesia, Brazil, India). Rich, readable messages.
  * **SMS** — Best fallback for users without WhatsApp or internet access. Maximum reach.
  * **Email** — Use when your authentication flow is email-first or your users don't provide a phone number.
  * **Missed Call** — Use when SMS delivery is unreliable, or when you want a zero-text, caller-ID-based flow that works on feature phones.
  * **WhatsApp Inbound** — Use when you want the user to initiate contact (e.g. opt-in flows, customer support contexts) or when outbound messaging templates are restricted.

  For maximum resilience, consider requesting WhatsApp first and falling back to SMS if the transaction status returns `failed`.
</Tip>
