Migrate SMS from Bird Connectivity Platform
This page maps the Bird Connectivity Platform API at rest.messagebird.com, the one you may still know as the MessageBird API, to Bird. Follow the main migration guide in order and use these mappings for steps 3, 4, and 5.
Both platforms are Bird's, and the API is the part that changes. Three differences affect every call. Requests go to your regional host, https://us1.platform.bird.com or https://eu1.platform.bird.com, rather than one global host. Authentication is a bearer API key (Authorization: Bearer bk_us1_…) rather than Authorization: AccessKey. And the send is asynchronous: POST /v1/sms/messages returns 202 Accepted with the message queued, where the Connectivity Platform returned the message object with a per-recipient status already attached.
Map the send call
| What it does | Connectivity Platform | Bird |
|---|---|---|
| Recipient | recipients (up to 50) | to, one per request |
| Sender | originator | from |
| Body | body | text |
| Intent | (none) | category, required on free text |
| Encoding | datacoding | detected automatically |
| Transliteration | (none) | options.smart_encoding (default false) |
| Client reference | reference | metadata, or tags when you filter on it |
| Status reports | reportUrl | a workspace webhook subscribed to sms.* |
| Safe retries | (none) | Idempotency-Key header |
| Scheduling | scheduledDatetime | no equivalent: scheduled_at is rejected |
| Validity | validity | no equivalent: validity_period is rejected |
| Route selection | gateway | Bird selects the route |
| Message class | mclass | no equivalent |
| Binary and flash | type, typeDetails | text only |
Both rejected fields are reserved and answer 422 SMSUnsupportedFeature.
Porting notes:
- The recipients array becomes one call per recipient. A Connectivity Platform call with 50 recipients becomes 50 sends, or one batch of independent messages. The batch is not a fan-out of one body: each entry carries its own recipient, sender, and text.
- datacoding has no equivalent, and that is deliberate. Bird detects the encoding from the body and reports the segment count on the message. If you set datacoding: auto to keep messages inside GSM-7, the closest behavior is options.smart_encoding, which replaces characters outside the GSM-7 alphabet with their nearest equivalent before sending.
- reference splits into two fields. Put an internal identifier in metadata, which is echoed on every webhook event, and use tags for the low-cardinality labels you want to filter and slice analytics by.
- Flash messages, binary payloads, and UDH concatenation do not port. If you rely on mclass or typeDetails today, raise it with support before you plan the cutover rather than after.
- Also on the Connectivity Platform Verify API? The port is a separate job with its own guide: see Migrate Verify from another provider.
Carry over opt-outs
The Connectivity Platform left stop-keyword handling to you, whether you built it in Flows or in your own application against inbound messages. Bird does that job itself: it recognizes stop, start, and help keywords on your numbers in supported countries, records the suppression, and enforces it on every send. That code retires with the migration.
What does not retire is the list. Export whatever you keep today, as pairs of subscriber number and the originator they stopped, and import it through the suppression loop before your first production send. If you only ever kept a global list of subscribers who opted out, import each subscriber once per originator you still send from.
Translate status reports
| Outcome | Connectivity Platform | Bird |
|---|---|---|
| Accepted by the API | (synchronous) | sms.accepted |
| Handed to the carrier | sent, buffered | sms.sent |
| Carrier confirmed delivery | delivered | sms.delivered |
| Delivery failed | delivery_failed | sms.failed |
| Validity window elapsed | expired | sms.expired |
| Refused before sending | (request error) | sms.rejected |
| Waiting to be sent | scheduled | no equivalent yet |
The delivery mechanism changes more than the vocabulary:
- Signed JSON posts replace reportUrl GET callbacks. Status reports arrived as GET requests with the outcome in the query string (status, statusReason, statusErrorCode, mccmnc, price[amount]). Bird POSTs a JSON event to endpoints your workspace registers, signed per Standard Webhooks. The handler is a rewrite rather than a URL change.
- Correlation no longer depends on reference. A status report was only useful if you had set a reference; a Bird event always carries sms_id, both numbers, and your echoed metadata and tags.
- Retry semantics differ. The Connectivity Platform retried a failed report up to 10 times. Bird's deliveries are at-least-once and unordered, so deduplicate on the webhook-id header and sort by the payload timestamp.
- Price is not on the event. The Connectivity Platform report carried price[amount] and price[currency]. Read cost from the message itself with GET /v1/sms/messages/{id} or in aggregate from the Stats API.
Inbound messages work the same way: subscribe to sms.received once for the workspace instead of pointing each number at a URL.
Cut over
Destinations, senders, and the traffic ramp are provider-independent and covered in the main guide. The item to raise early is your originators: alphanumeric sender IDs are re-created and, where the country requires it, re-registered here, and numbers you hold on the Connectivity Platform move by a port that support arranges rather than a setting you flip.
Next steps
- Sending SMS: the payload you are porting to, in full
- Opt-outs and keywords: what Bird answers for you, and how to manage suppressions
- SMS events: the event vocabulary your status handler moves to
- Webhooks & events: endpoint setup and Standard Webhooks verification