Sign inGet started

Migrate Verify from Prelude

This page maps Prelude's v2 verification API to Bird Verify. Follow the main migration guide in order and use these mappings for steps 1 and 3.
The shapes are close. Prelude's POST https://api.prelude.dev/v2/verification and POST /v2/verification/check are a bearer-authenticated create-and-check pair keyed by the target rather than by a verification ID, and so are POST /v1/verify/verifications and POST /v1/verify/verifications/check. Calling create again for a live recipient retries rather than starting a new verification on both platforms. What does not port is the risk layer: Prelude's signals, routing verdicts, and silent verification have no counterpart in the Bird Verify API.

Hand this to your agent

Paste this into Claude Code, Cursor, or Codex. The agent works through this page against your own repository, using whichever Bird surface it already has: the MCP server if one is connected, the CLI if it is installed and signed in.
代码示例
I am moving a phone verification integration from Prelude to Bird Verify. Route through it with me.
1. Check what you already have before setting anything up. If Bird's MCP server is connected, use its tools. If the Bird CLI is installed and signed in, use that. Either one is enough, and every step below is an action you take with whichever you have. Only if neither is present, follow https://bird.com/docs/ai/set-up-your-agent.md to set one up and sign me in. Every Bird docs page serves Markdown at its own URL with `.md` appended, so fetch that rather than the HTML.
2. Read https://bird.com/docs/guides/verify/migrate/prelude.md for the create, check and status mapping, and https://bird.com/docs/guides/verify/migrate.md for the order the steps go in.
3. Find and list my Prelude usage in this repository before you change anything: the /v2/verification and /v2/verification/check call sites, anywhere I read signals or a routing verdict, and anywhere I use dispatch_id for retry safety.
4. Tell me early which of these I depend on, because none of them carries over and I would rather know now than at the end. Bird Verify has no voice channel and no silent or network-based authentication. It generates the code itself and never returns it, so I cannot supply my own. It takes no per-request template, locale or message body, and Bird owns the sender identity, so the message my users see will change on cutover. Prelude's risk layer does not port either: its signals, its routing verdicts and its silent verification have no counterpart in Bird Verify, so tell me every decision my code makes on those.
5. Configure my channels and destinations following https://bird.com/docs/guides/verify/countries.md and https://bird.com/docs/guides/verify/senders.md. While you are there, disable every country I do not actually verify into. An enabled destination I never send to is not reach, it is exposure to SMS pumping, so ask me which countries I serve rather than leaving the defaults.
6. Port the create and check calls using the mapping tables on the provider page, and move my status handling to Bird's events: https://bird.com/docs/guides/verify/sending-verifications.md and https://bird.com/docs/guides/verify/events.md.
7. Cut over at the create call, not all at once, because a code issued by Prelude cannot be checked by Bird and a code issued by Bird cannot be checked by Prelude. From the moment I say go, send every NEW verification to Bird, and keep routing each check to whichever provider issued that verification. Keep both paths live for one full code lifetime plus margin, then retire the old one. Tell me how you will decide which provider issued a given verification before you write any of it.
8. Test before any real traffic. Bird Verify has no simulated recipients, so do not look for a sandbox: the thing worth testing is the code arriving. Run the integration against a phone number and a mailbox I control, on each channel I enabled, and show me what arrived on each one.
9. Stop and ask me wherever a step needs a decision. Do not start routing new verifications to Bird until I have seen those test results and replied with the words cut over to Bird. Retiring the Prelude path is a separate step: ask me again and wait for me to reply with the words retire the Prelude path, and do not retire it while any code it issued could still be checked. A reply that agrees without naming what it is authorising is not authorisation. Finish by telling me what is left that only a person can do.

Map the create call

What it doesPreludeBird
Recipienttarget.type + target.valueto.phone_number or to.email
Code lengthoptions.code_sizeoptions.code_length
Channel preferenceoptions.preferred_channel, options.channelsoptions.channels, else the country's configured order
Correlationmetadata.correlation_idmetadata
Safe retriesdispatch_idIdempotency-Key header
Delivery callbacksoptions.callback_urla workspace webhook subscribed to verify.*
Custom passcodeoptions.custom_codeno equivalent
Localizationoptions.localeno equivalent
Sender identityoptions.sender_idno equivalent: Bird sends under Bird Verify or Authifly
Message templateoptions.template_id, options.variablesno equivalent
Android autofilloptions.app_realmno equivalent
Risk signalssignals (IP, device, fingerprint)not accepted
Fallback controloptions.max_auto_fallbacks, options.force_challengethe country's channel plan
The channel sets overlap only partly. Bird delivers over email, SMS, WhatsApp, and Telegram; Prelude's RCS, Viber, Zalo, voice, and silent channels have no Bird equivalent today. A number that Prelude reached over Viber or Zalo falls back to SMS here, which is a delivery-rate question worth measuring in the pilot rather than discovering at full volume.

Map the check call

Both check endpoints take the recipient and the code with no verification ID, so this call ports almost as it stands. The response is where they differ:
Prelude statusBird
successsuccess: true
failuresuccess: false, reason: incorrect_code
expired_or_not_foundsuccess: false, reason: expired, or a 404
(no direct value)success: false, reason: attempts_exhausted
Prelude folds "wrong code" and "out of attempts" into failure; Bird separates them, and returns attempts_remaining alongside so you can show the user how many tries are left. A verification that has already resolved returns 404 rather than a status, so store the first definitive answer instead of re-checking.

What happens to the risk layer

Prelude's create response reports a routing verdict: a status of success, retry, challenged, blocked, or shadow_blocked, with a reason and risk_factors when it refuses, and a method naming the channel it chose. Bird's create response is the verification itself. There is no verdict to branch on, no signals object to send, and no equivalent of a shadow block, so an integration that gates sign-ups on Prelude's verdict needs its own decision before it calls Bird.
What Bird does carry from that space is narrower and mostly configuration: per-country enablement to shut off destinations you never serve, the platform send and check caps described in Abuse guardrails, and the channel plan itself. If pumping protection was the reason you chose Prelude, size that gap before scheduling the move.

Move the callbacks

Prelude posts delivery status to the callback_url you set per verification. Bird delivers to endpoints your workspace registers, each subscribed to the event types it wants, so the URL leaves the request body. Subscribe to verify.verification.* for the session and verify.attempt.* for each passcode send, and verify signatures per Standard Webhooks. The payloads are in Verify events.

Cut over

The cutover rule in the main guide applies unchanged: a code Prelude issued cannot be checked by Bird, so switch at the create call and route each check to whichever provider issued that verification until the last one expires. Because both APIs key on the recipient, the branch is a single conditional around your existing call sites rather than a rewrite.
Watch conversion during the pilot alongside delivery. Prelude routes per request across a wider channel set; Bird routes on the channel order you set per country. If a market's conversion drops, reorder that country's channels before concluding anything about the port.

Next steps