POST https://app.alaaqat.com/api/broadcasts/{id}/send-otp
Where id is the approved authentication template you would like to send. Templates of any other
category are rejected — use Send Template for those.
Conversely, an authentication template can only be sent through this endpoint, /send and the send
screens in the app both refuse it.
The token must carry the broadcast-send-otp ability, and this endpoint is not callable from a
session (first party) context.
Whether you supply code decides who owns the one time password.
Relay mode (code given) |
Managed mode (code omitted) |
|
|---|---|---|
| Who mints the code | You | We do — 6 digits |
| What we store | Nothing | A hashed code, its expiry and an attempt counter |
| Response | { data: Message } |
{ data: Message, verification_id, expires_at } |
| Verification | Yours to do | Verify WhatsApp OTP |
The plaintext code is never returned in either mode. In relay mode you already have it; in managed mode it exists only inside the delivered WhatsApp message and as a hash in our database. There is no way to read a managed code back — if you need to check it, call the verify endpoint.
Relay mode is unverifiable by us: a verification_id is never issued for it, so calling
/verifications/{id}/verify after a relay send has nothing to verify against.
{
"Accept": "application/json"
}
{
contact_id?: string,
to?: string,
code?: string,
}
| Field | Required | Validation | Description |
|---|---|---|---|
| contact_id | Required without to |
string, must belong to your account | The contact that receives the code. Mutually exclusive with to. |
| to | Required without contact_id |
6 to 20 digits, an optional leading + |
A raw WhatsApp number. The matching contact is found by its WhatsApp number, or created if there is none. |
| code | Optional | 4 to 15 characters, letters and digits only | Your own code. Supply it to relay, omit it to have us generate, deliver and store one. |
contact_id and to are mutually exclusive — sending both is a validation error rather than one
silently winning.
•••••• is your verification code., so the code is never readable from the inbox, by you or by our
support. This is deliberate.failed, so only one code is ever live per
recipient per template.429.to writes data. A number with no matching contact creates one on your account, sourced as
whatsapp / api. A typo therefore creates a junk contact and the send then fails at WhatsApp.Returns the Message object under data. In managed mode verification_id and expires_at sit beside
it at the top level.
{
"data": {
"id": "wamidf91071ec-29ef-353c-9f34-dc2c47452e6f",
"contact_channel_id": "962790000000",
"platform_type": "Modules\Conversations\Inbox\Models\WabaNumber",
"platform_third_party_id": "651663395",
"sender_third_party_id": "651663395",
"receiver_third_party_id": "962790000000",
"status": "sent",
"broadcast_id": 53,
"attachments": [],
"updated_at": "2026-08-15T18:35:46.668000Z",
"created_at": "2026-08-15T18:35:46.668000Z",
"_id": "66faef8227545300c4059c84",
"is_sent_by_the_business": true
},
"verification_id": "66faef8227545300c4059c85",
"expires_at": "2026-08-15T18:40:46+00:00"
}
expires_at follows the template's own code_expiration_minutes — the customer is literally told
"This code expires in N minutes", so anything else would contradict the delivered message. Templates
without that footer fall back to 5 minutes.
| Status | Meaning |
|---|---|
| 402 | The account is over its monthly message limit. |
| 403 | Not an approved authentication template, the token lacks broadcast-send-otp, or the request is not from an API token. |
| 404 | The template does not exist on your account. |
| 422 | Validation — no recipient, both recipients, a contact_id that is not one of your contacts, a malformed to, or a code with punctuation. |
| 429 | A code was already sent to this recipient within the cooldown. |