# Migrate from Twilio Lookup to Bird

Move the phone-number checks your application actually uses, then verify the next action: ask for a corrected number, offer verification or continue a customer task. Start with a number you control and an API key with the Lookup scope.

Use the [Next.js lookup form](/docs/get-started/quickstarts/typescript/next-js/lookup) or [FastAPI lookup form](/docs/get-started/quickstarts/python/fastapi/lookup) to run the receiving application. Both preserve an attempt's request key and distinguish an unanswered score from zero.

## Map the integration

| Existing integration      | Bird migration action                                                                  |
| ------------------------- | -------------------------------------------------------------------------------------- |
| Basic-auth credentials    | Use a Bird API key on the server; the SDK selects its region from the key.             |
| Number in the request URL | Send `phone_number` in a POST body. Resolve national-format input before calling Bird. |
| Requested data packages   | Choose the optional properties needed by your application; see the mapping below.      |
| Line type and carrier     | Read `line_type` and identified networks, then update your application's enum checks.  |
| Missing or failed package | Preserve the individual property status and an unanswered value.                       |
| Risk threshold            | Recalibrate the decision for the particular signal; scores are not interchangeable.    |

Twilio's [v2 request](https://www.twilio.com/docs/lookup/v2-api) uses `Fields` to select packages and accepts national-format input with country context. Bird's [phone-number operation](/docs/api/reference/create-phone-number-lookup) takes an international number and a `type` array. A malformed number is an API error; a successful lookup is not proof that someone controls the number.

Map only the fields your application consumes:

- **Line type:** Twilio's [line-type vocabulary](https://www.twilio.com/docs/lookup/v2-api/line-type-intelligence) includes `landline`, `fixedVoip` and `nonFixedVoip`. Bird uses `fixed_line` and a single `voip` base category. Preserve an explicit unknown branch; a fixed-versus-non-fixed VoIP distinction needs a separate decision.
- **Carrier:** read `network_info` for the current network and `original_network_info` for the number range's original network. Either may be absent. Read each network's carrier name, MCC and MNC only when supplied.
- **SIM swap:** Twilio reports a date or a change within a period in its [SIM Swap package](https://www.twilio.com/docs/lookup/v2-api/sim-swap). Request Bird `sim_swap`, require `status: ok`, then evaluate the returned date or recency bounds. A band that crosses your policy threshold cannot support an exact yes/no conclusion.
- **Risk:** Twilio's [SMS Pumping Risk Score](https://www.twilio.com/docs/lookup/v2-api/sms-pumping-risk) rises with pumping risk. Bird's [credibility score](/docs/guides/lookup/phone-numbers#add-properties) rises with credibility. They measure different things. Neither copying the threshold nor subtracting one score from 100 establishes equivalent protection.
- **Other packages:** the phone-number request supports classification, porting, presence, roaming, SIM swap and score. Caller-name, identity-match, reassignment and call-forwarding dependencies need a separately verified replacement. Do not silently substitute `presence` or a credibility score for those answers.

## Build and test the receiving path

This server-side example requests presence, SIM-swap and score observations. Review [Lookup pricing](/products/lookup/pricing) before running it: the base lookup is billed, with additional charges for answered requested properties.

Install `@messagebird/sdk` and `tsx`. Set `BIRD_API_KEY`, `BIRD_TEST_PHONE` and `LOOKUP_REQUEST_ID` in your shell. Use one UUID as the request ID for this attempt and keep it with the unchanged phone number and property selection while recovering a failed response. Save as `lookup.mts`:

```typescript
import { BirdClient } from "@messagebird/sdk";

function required(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name}`);
  return value;
}

const bird = new BirdClient({ apiKey: required("BIRD_API_KEY") });
const result = await bird.lookup.phoneNumber(
  {
    phone_number: required("BIRD_TEST_PHONE"),
    type: ["presence", "sim_swap", "score"],
  },
  { idempotencyKey: required("LOOKUP_REQUEST_ID") },
);

console.log(
  JSON.stringify(
    {
      line_type: result.line_type,
      presence_status: result.presence?.status ?? "missing",
      reachable: result.presence?.status === "ok" ? result.presence.reachable : null,
      score_status: result.score?.status ?? "missing",
      credibility: result.score?.status === "ok" ? result.score.value : null,
      sim_swap: result.sim_swap ?? { status: "missing" },
    },
    null,
    2,
  ),
);
```

Run `npx tsx lookup.mts`. The output keeps status beside the observation. A conclusive `false` or zero remains a value; an unanswered observation remains `null`. SIM-swap dates and bounds remain intact for your application's policy. See [property interpretation](/docs/guides/lookup/phone-numbers#read-the-status-before-the-value) before using them.

Test these cases in the complete form with controlled responses where a live number cannot reproduce the condition:

1. A mobile, fixed-line and VoIP result choose the intended verification or channel path.
2. Missing carrier data does not crash the page or select an invented carrier.
3. An unanswered or unrecognized property status stays unknown; a conclusive zero score remains zero.
4. A SIM-swap date, a bounded result and an unavailable result each follow the policy you defined.
5. Invalid input produces a correction step. Authentication, balance and service failures remain operational errors.
6. A lost response is retried with the original body and key under the [idempotency rules](/docs/guides/idempotency). It does not trigger two customer actions.

The code reads observations; your application still owns verification, consent and the next business action. Follow [Verify](/verification-api) when the customer must demonstrate control of a destination.

## Switch traffic and reconcile

Record the requested properties, observation time, provider and resulting application decision for an authorized test cohort. Compare unanswered-result rates by destination as well as successful requests. Recalibrate any risk thresholds before allowing the new result to control customer traffic.

Choose one provider's result to drive each customer task during the transition. Comparative lookups may incur two charges; prevent the comparison from sending two verification challenges. Keep the previous integration available until its outstanding work is reconciled.

For rollback, route new tasks back to the previous integration and preserve unresolved Bird attempts with their original keys. Retrying an old attempt replays an observation; deliberately requesting fresh data is a new lookup. Apply your retention policy to stored number data and avoid placing API keys or full provider responses in browser logs.

## References and next steps

- [Next.js application](/docs/get-started/quickstarts/typescript/next-js/lookup) and [FastAPI application](/docs/get-started/quickstarts/python/fastapi/lookup)
- [Request and response reference](/docs/api/reference/create-phone-number-lookup)
- [Lookup troubleshooting](/docs/guides/lookup/troubleshooting)
- [Compare Bird and Twilio Lookup](/products/lookup/compare/bird-vs-twilio)
- [All migration guides](/docs/guides/lookup/migrate) and [Lookup resources](/lookup/resources)
- [Pricing](/products/lookup/pricing), [start now](/dashboard/signup?returnTo=%2Fdashboard%2Fw%2Flookup) or [talk to sales](/demo?product=lookup)

## Related resources

- [Phone number lookup: check a number before you send](/learn/lookup/phone-number-lookup-check-a-number-before-you-send) (video)
- [Lookup](/lookup) (product)
- [Lookup overview](/docs/guides/lookup/overview) (docs)

[Get an implementation brief](/learn/workspace?topic=lookup)
