SMS OTP

Send a code by SMS. Check it by recipient.

Set up in:
Cursor

SMS verification sends a one-time code to a phone number and confirms the person typing it back holds the line. Bird generates the code, sends it, enforces per-recipient caps, and checks it by recipient, so there's no id to store and no resend endpoint to wire.

verify.ts
200 · pending
import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({
  apiKey: process.env.BIRD_API_KEY!,
});

// Send the code, then check it by recipient.
await bird.verify.verifications.create({
  to: { phone_number: "+15551234567" },
}).safe();

const { data } = await bird.verify.verifications.check({
  to:   { phone_number: "+15551234567" },
  code: userInput,
}).safe();

SMS OTP is one call to send and one to check.

SMS is a phone-family channel on the Bird Verify API: post a verification with a phone number and we send the code on a Bird-managed shared sender, Bird Verify by default or Authifly if you prefer it; check it by that same number. Re-posting the create is the resend (create-or-retry), and every code in the session stays valid until it verifies, expires, or runs out of attempts.

What you get on an SMS verification.

Built in, on every send.

  1. 01

    Addressed by phone number.

    Pass a single E.164 phone number. We normalize it and send over SMS on the sender resolved for its country.

  2. 02

    Server-generated, hashed codes.

    A 6-digit code by default (4–10 configurable), generated with a cryptographic random source and stored only as an HMAC. You never see the plaintext.

  3. 03

    Resend is the same call.

    Re-post the create to resend once the 60-second cooldown passes: same session, new code, both still valid. No separate resend endpoint.

  4. 04

    Per-recipient caps included.

    A per-recipient send cap bounds send volume and runaway spend, with a 429 and Retry-After.

  5. 05

    Reach that expands by country.

    SMS sends on a Bird-managed shared sender today, Bird Verify or Authifly, showing a branded sender ID where a country permits one and a short code or local number where one is required, with dedicated and registered senders extending reach as they land.

The whole flow, two calls.

Create-or-retry sends the code to the phone number; check confirms it by that number. There's no id to thread between the two: the recipient is the key.

sms-otp.ts
200
await bird.verify.verifications.create({
  to: { phone_number: "+15551234567" },
}).safe();

const { data } = await bird.verify.verifications.check({
  to:   { phone_number: "+15551234567" },
  code: userInput,
}).safe();

// data.result is true or false; data.reason elaborates ("expired", "already_verified", …)

The verification API with nothing to store.

SMS is one channel of Bird Verify: email and WhatsApp ship with it, and voice is rolling out, all on the same two endpoints.

Start with one channel.
Add the others when you're ready.

A test API key is yours immediately. Production unlocks when you add a payment method and verify a sender.

Using Claude Code, Cursor, or Codex? Copy a setup prompt and your agent installs the Bird CLI and skills for you. Pick yours:

Cursor