Changelog
Récemment livré.
feature
Email Metrics gets an Inbound tab
The email Metrics page (Email → Metrics) now splits into an Outbound tab, everything you send, and a new Inbound tab covering what your workspace receives. Inbound shows a Messages received count for the selected range plus a volume-over-time chart, once you've set up a forward address or your own domain for receiving. See email metrics.
Also in this release:
- New guide: SMS character limits lays out GSM-7 versus UCS-2 encoding, which characters (curly quotes, emoji, the euro sign and other extension-table characters) push a message into the pricier alphabet or eat two character slots, and the 12-segment cap on a single send.
feature
Contacts: import a list from a CSV or Excel file
Getting a list into Bird no longer needs a developer. Import on the Contacts page now takes a CSV, TSV or Excel file of up to 50,000 contacts, reads the header row to work out which column is the email address and which is the phone number, and shows you the first rows as the contacts they will become before anything is written.
Until now the dashboard took contacts pasted one per line as email, first name, last name, so anything that was not already in that exact shape meant editing a spreadsheet by hand first, and anything with custom fields meant calling the API. Most lists arrive as an export from another tool, with the columns that tool happened to name.
What's new
- The columns are matched for you. "Email Address", "E-Mail", "Correo electrónico" and "email_address" all land on the email field, and a single column holding a whole name is split into a first and a last. Where two columns could fill the same field, the one whose values back up its name wins. Every match is a dropdown you can change.
- You see the contacts, not the file. The preview shows the first ten rows as the contacts they will become, so a name column splitting the wrong way or a date reading as text is something you catch before you commit rather than after.
- Rows that cannot be imported say why, and where. Each one is listed with the line number to open in your own file and what is wrong with it, both on the preview and again when the run finishes. Nothing is skipped silently.
- Custom properties and audiences come along. Any column can map to one of your typed contact properties, and everyone in the file can be added to one or more audiences as part of the same import.
- Re-importing is safe. Each row is matched against the identifiers it carries and updated, so importing a corrected file updates the contacts rather than duplicating them.
Importing and syncing contacts covers the flow. To sync from your own database instead, POST /v1/contacts/batch still upserts up to 1,000 contacts a call and now accepts 30 calls a minute.
feature
Receive SMS replies on your numbers
Bird SMS used to be outbound only. Now, when someone texts one of your numbers, Bird stores the message beside your sends and pushes it to your endpoint as sms.received, so you can answer a reply without polling for it.
What's new
- The
sms.receivedwebhook. Subscribe from the API, the SDKs,bird webhooks create, or the MCP server. The payload carries the body, the segment breakdown, both numbers, and the sending operator where the carrier reports one, so you can act on a reply without a second request. - Inbound messages in the API and the log.
GET /v1/sms/messages?direction=inboundreturns what you received, and each message opens in the SMS log with its body and timeline. - Received-message metrics. The SMS Metrics page shows received volume with its period-over-period change, and a Received messages page breaks it down by number, country and sending operator, so you can see which of your numbers is taking the traffic.
Replies are yours to act on
Bird records a reply and passes it to you; it does not interpret it. A STOP arrives as an ordinary sms.received, and suppressing future sends to that number is your integration's job for now. We will say so clearly here when that changes.
One change to existing webhooks
carrier and mcc_mnc are now omitted from sms.sent, sms.delivered and sms.received payloads when the carrier does not report them, rather than arriving as null. That matches the way the message resource has always reported these fields. If you branch on null for either, check for absence instead. sms.accepted now also carries segments, the count your send is billed on.
feature
PHP SDK: install messagebird/sdk from Composer
Bird has an official PHP SDK. composer require messagebird/sdk gives you a typed client over the same curated surface the Go, TypeScript, and Python SDKs cover, so a PHP service no longer has to hand-roll HTTP calls against the API.
It targets PHP 8.2+ and is synchronous. Requests go through any PSR-18 client you already have, Guzzle or Symfony HttpClient included, discovered automatically. Nothing pins you to a transport, and per-request timeouts stay where you already configure them.
What you get
- The curated surface, method for method with the other SDKs: email (send, batch, get, list, cancel, stats, mailboxes, threads), SMS and its templates, WhatsApp, Verify, contacts, contact properties, audiences, domains, and realtime.
- A one-argument client. Only the API key is required. The region comes from the key's
bk_{region}_prefix, so abk_eu1_…key routes to EU with no extra configuration. - Retries and idempotency you don't write. Transient failures retry with jittered backoff and honor
Retry-After, and every mutation,DELETEincluded, carries an idempotency key generated once and reused across attempts. A retry cannot act twice. - Errors as exceptions. A failed call raises
ApiExceptioncarrying the HTTP status plus the API's own errortypeand code, so you branch on a stable value instead of parsing a message. - Webhook verification.
$bird->webhooks->unwrap()checks a Standard Webhooks signature against your signing secret and hands back the verified payload. - An escape hatch for the long tail.
get,post,put,patch, anddeleteon the client reach any endpoint directly, so a newly shipped API operation never waits on an SDK release.
Not in this release
Framework packages. The quickstart is a plain PHP script, and there is no Laravel or Symfony integration yet. The client itself works inside either framework today; what is missing is the idiomatic wrapper, which is on the roadmap.
To send something, start with the PHP email quickstart. For the client's configuration, retry, and error model, see the PHP SDK reference.
feature
Verify: send the passcode on another channel when it never arrives
When a user tells your app the passcode never arrived, you can now move them to another channel on demand. POST /v1/verify/verifications/next-channel advances a live verification to the next channel in its plan and sends a fresh code there, without waiting out the resend cooldown a second create would honour.
Until now the only way onto the next channel was to let Verify get there itself, after a send failed or a delivery report came back terminal. Neither helps the common case: the message was accepted, nothing came back to say otherwise, and the user is still staring at an empty inbox. This is the endpoint behind an "I didn't receive my code" button.
What's new
- One call, keyed by the recipient. Pass the same
toyou created the verification with, exactly as you do for a check. There is still no verification id to store. - No cooldown, no lost codes. A deliberate channel switch sends immediately, and every code already sent stays valid, so a message that turns up late still verifies.
- The response tells you where it went. You get the verification back with
last_channelnaming the channel the new passcode was sent on. - On every surface. The SDKs expose it as
Verify.Verifications.NextChannel(Go),verify.verifications.nextChannel(TypeScript), andverify.verifications.next_channel(Python), the CLI asbird verify verifications next-channel, and the MCP server as theverify_verifications_next_channeltool.
A verification whose channel plan has no further channel answers 422 with NoNextChannel; fall back to calling create again to resend on the current channel. Send the code on another channel covers the flow and the rest of the error cases.