SendKuy API

Verify

One-time codes with channel fallback.

Verify sends a one-time code and checks it for you. You never generate, store or compare codes yourself.

Two calls

Start a verification for the person who is signing in:

curl https://app.sendkuy.com/api/v1/verifications \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": "+6281234567890", "brand": "Toko Andi"}'

Then check the code they type:

curl https://app.sendkuy.com/api/v1/verifications/vrf_7hTq.../check \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"code": "123456"}'

A match answers 200 with status: approved, and the code is used up. A wrong code answers verification_code_invalid; five wrong codes fail the verification. A code past its ttl (600 seconds by default) answers verification_expired.

Starting a new verification for the same to or email cancels the one still pending, so only the newest code works. A channel your plan does not include is refused up front with channel_not_in_plan.

Once a verification is approved, failed, cancelled or expired, any of its messages that have not gone out yet are cancelled, so nobody receives a code that no longer works.

Channels and fallback

channels is the order we try, ["whatsapp", "sms"] by default. We move to the next channel when:

  • nothing on the channel can send for you — no sender, or no credit left today (the attempt says skipped);
  • the send fails on every sender you have on that channel (failed) — a sender that cannot send, such as a disconnected device or a phone without signal, is first swapped for your next live one, carrying the same code;
  • a WhatsApp device sent it but no delivery receipt arrived within 30 seconds (undelivered).

SMS and email count as done once they are handed over, because neither reports delivery. The same code goes out on every channel. The first send happens inside your request, so the response already says how it went. When that sender failed and the code moved to another of yours, the attempt already reads sent; if the next sender fails too, it turns failed and the next channel follows. That step and the 30-second fallback run in the background and are on time only when your SendKuy server runs its workers under supervisor.

WhatsApp Cloud API

When you own a Cloud API number, Verify sends through Meta's Authentication template instead of a plain message:

  1. Create a template with the Authentication category in Meta Business Manager, with a copy-code button.
  2. Sync templates in SendKuy once Meta approves it.

We pick the one whose language matches locale, or any Authentication template when none does. Templates that share a name keep only one language after a sync, so give each language its own name.

What the person receives

The text is fixed so Verify cannot be used to send anything else. Only brand changes:

  • id: "123456 adalah kode verifikasi Toko Andi. Berlaku 10 menit. Jangan berikan kode ini kepada siapa pun."
  • en: "123456 is your Toko Andi verification code. It expires in 10 minutes. Do not share it with anyone."

The code never appears in GET /messages, in webhook payloads or in your dashboard: the stored message holds {{verification_code}} instead.

Credits, contacts and opt-outs

  • Each message spends one credit of its own channel. A fallback from WhatsApp to SMS spends both when both were sent. A skipped channel spends nothing.
  • The number or email becomes a contact on your account, as with POST /messages, and fires contact.created.
  • Someone who opted out of your promotions still gets their code. Addresses that bounced, complained or were blocked by SendKuy do not, and Verify moves to the next channel.

Limits

Five verifications per destination every ten minutes, and five code checks per verification. See Rate limits.