try · no install · nothing sent

run it here before you run it anywhere.

Self-hosting a gateway you have never called is a bad first date. So the whole contract runs in this page: two calls, every status code, every failure path an integration has to handle. No gateway, no account, no signup, and no message leaves your browser.

Every response below is produced by the same rules the reference documents, running in this browser tab. There is no gateway behind this page, no account, and nothing is sent. The project runs no hosted instance, so this is the closest thing to a live call that can honestly exist. The phone number and code are yours to invent.

whatsapp this month 42 / 500telegram unmetered

01 · send

channel

normalises to 919876543210 · 10 digits are read as india (+91)

request
curl -X POST "$WOTP_API/v1/otp/send" \
  -H "X-Api-Key: $WOTP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"9876543210","channel":"whatsapp"}'
responsenot sent yet
run the call to see the response

02 · verify

no active code for this number yet, send one first

a code dies the moment it verifies. run it twice: the second call returns code_expired, not verified.

request
curl -X POST "$WOTP_API/v1/otp/verify" \
  -H "X-Api-Key: $WOTP_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to":"9876543210","code":""}'
responsenot checked yet
run the call to see the response

03 · the paths you have to write code for

These are the four errors the reference tells an integrator to handle explicitly, plus the attempt budget. Each button drives the real engine into that state and runs a real call, so none of these bodies are typed in by hand.

Two more worth knowing, both from the reference: wrong_code returns attempts_left, and the third wrong entry burns the code and returns too_many_attempts. Type a wrong code twice above to watch the budget go.

Telegram bots can only message people who started a chat with them, so the first send to a new number bounces once on purpose. The retry is free: no code is stored, no quota is consumed, no throttle is applied.

  1. switch the channel to telegram in band 01 and send→ 409 user_not_linked + link_url
  2. → the phone is now linked
  3. send again on the same endpoint. no special call, no status check→ 200, the code arrives on telegram

There is no “check link status” endpoint: the 409 is the check, and retrying costs nothing.

seen enough? it runs on your own box in about ten minutes.

Docker Compose, one command, your own Meta and Telegram credentials. There is no hosted tier to upgrade to and nothing to pay this project. WhatsApp messages are billed by Meta to you, directly.