> ## 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.

# How to Integrate WhatsApp Inbound OTP

> Use the whatsapp_inbound channel so the user sends a pre-filled WhatsApp message to OTP.ID and the server matches it automatically.

Use this guide when you want the user to start verification from WhatsApp instead of receiving a code. This channel uses the public alias `whatsapp_inbound`, and you create it with [`POST /v3/request`](/api-reference/request-otp) only. [`POST /v3/send`](/api-reference/send-otp) does not support this channel.

The flow is simple: you create a pending transaction, OTP.ID returns a WhatsApp number plus a pre-filled message, and the user taps the deep link or sends the message manually. OTP.ID matches the inbound message automatically and marks the transaction verified.

## How the flow works

<Steps>
  <Step title="Create the request">
    Call [`POST /v3/request`](/api-reference/request-otp) with `channel: "whatsapp_inbound"`. You can omit `number` for an unbound flow, or include it to bind verification to one sender number.
  </Step>

  <Step title="Show the WhatsApp action">
    Render `verification.wa_link` as the primary action, or show `verification.wa_number` and `verification.message` together if you want the user to copy the text manually.
  </Step>

  <Step title="Keep the prompt visible before expiry">
    Show the deep link and message until `verification.expires_at`. After that time, disable the action and ask the user to start a new request.
  </Step>

  <Step title="OTP.ID matches the inbound message">
    When the user sends the exact message to `verification.wa_number`, OTP.ID matches it automatically. If you bound the request with `number`, OTP.ID only accepts the matching sender number.
  </Step>

  <Step title="Update the UI state">
    Treat the transaction as pending, invalid, expired, or success based on the current status from [`GET /v3/otp/{otp_id}`](/api-reference/get-otp-status) or the [`otp.verified` webhook](/api-reference/webhook-otp-verified).
  </Step>
</Steps>

## What the response gives you

For `whatsapp_inbound`, the response includes a `verification` block with the data your UI needs:

* `verification.wa_number` — the OTP.ID WhatsApp number the user must message
* `verification.message` — the exact text the user must send
* `verification.wa_link` — a deep link that opens WhatsApp with the message pre-filled
* `verification.expires_at` — when the inbound verification link and message stop being valid

Show the deep link and message before `verification.expires_at`. If the user changes the text, sends from the wrong number on a bound request, or waits too long, the transaction stays unverified and your UI should move back to a fresh request.

## UI states to handle

| State   | What you should show                                                           |
| ------- | ------------------------------------------------------------------------------ |
| Pending | Show the WhatsApp button, the destination number, and the exact message.       |
| Invalid | Tell the user the message did not match and ask them to resend the exact text. |
| Expired | Hide or disable the action and prompt a new request.                           |
| Success | Confirm verification and continue the flow.                                    |

## Related pages

* [WhatsApp Inbound guide](/guides/channels/whatsapp-inbound)
* [POST /v3/request reference](/api-reference/request-otp)
* [GET /v3/otp/{otp_id} reference](/api-reference/get-otp-status)
* [otp.verified webhook](/api-reference/webhook-otp-verified)
