YASend API

Sending OTPs safely

WhatsApp is a great channel for login and verification codes when you send them carefully. A banned number sends nothing at all.

The recipe

curl -X POST "https://api.yasend.dev/v1/messages?async=true" \
  -H "Authorization: Bearer $YASEND_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: otp-$OTP_REQUEST_ID" \
  -d '{
    "sessionId": "'$SESSION_ID'",
    "to": "963912345678",
    "text": "Your Acme code is 482913. It expires in 5 minutes. Don'\''t share it.",
    "templateKey": "otp_login",
    "expiresInSeconds": 300
  }'
Setting Why
?async=true Your login screen doesn't wait 3–10 seconds; the user sees "code sent" at once
templateKey Tells YASend this is a templated message, so its near-identical texts aren't refused as duplicate spam. Keep one key per template (otp_login, otp_reset…)
expiresInSeconds A code that arrives after it expired is useless. If the number is reconnecting, the message is dropped at expiry and you get message.failed / EXPIRED, so you can offer SMS or "resend"
Idempotency-Key If your request times out and you retry, the user still receives one code, not two

Listen for the message.failed webhook, or poll GET /v1/messages/{id}, to fall back quickly.

Write codes that look like codes

  • Put the code in plain digits, early in the message, and name your app.
  • Don't include links in OTP messages. Link-only and link-heavy messages are a common ban trigger.
  • Keep the wording the same each time and change only the code.

Use a warmed-up number

A freshly linked number is limited for its first weeks: 10 messages a day for the first two days, then a gradual increase up to 200 a day after a month. It also needs a profile name, a profile photo and at least one real conversation before automation unlocks. See Safety & warm-up.

For OTPs:

  • link the number well before launch;
  • use it like a normal account for a few days;
  • on the Advanced plan, add a second number as a backup.

Protect your own endpoint

Rate-limit "send me a code" per user and per IP on your side. Otherwise anyone can make your number send hundreds of codes, which burns your quota and your number's reputation.

If the number gets into trouble

YASend watches each number's health.

  • At risk: if delivery failures pile up or WhatsApp starts refusing messages, sends are stopped with SESSION_AT_RISK to protect the number.
  • Recovery: check GET /v1/sessions/{id}/health, and slow down until it recovers.
  • Fallback: keep an SMS fallback in your own code for codes that must arrive.