Platform

Does Bird have a sandbox, and what are magic numbers?

The word people expect is "sandbox", meaning a separate environment with its own credentials where nothing is real. Bird does not have one, and the thing it has instead is better in one way and worse in another, so it is worth knowing which before you write a test suite.

Is there a test environment?

No. There is no test mode to enable, no test API key, and no separate host. Your integration points at production and always did.

What exists instead is a set of magic destinations. You send through the normal endpoints with your normal key, and the recipient you chose determines the outcome. Everything else about the request is real: the same 202, the same processing, the same per-recipient events, the same signed webhook deliveries.

The advantage is that you are testing the path you will actually use, rather than a mock of it. The disadvantage is that nothing marks the send as a test, which the last section covers.

What are the magic email addresses?

Local parts on messagebird.dev. The address selects the outcome, and seven are documented:

AddressWhat it simulates
delivered@The receiving server accepts it, the happy path
bounce@ or hardbounce@A hard bounce, SMTP 550
softbounce@A soft bounce, SMTP 451
deferred@ or delay@A deferral, and the simulated one is terminal: no retry follows
complaint@ or spam@The recipient reports it as spam
suppressed@The recipient is treated as already suppressed, so it short-circuits with no processing or delivery events
reject@Rejected before any delivery attempt

Four rules about matching are worth reading once rather than debugging later. Detection is by local part only and only on messagebird.dev, so bounce@yourdomain.com is an ordinary address. Only the documented local parts are magic; anything else at that domain is a normal recipient. Matching is case-insensitive. And +label subaddressing is stripped before matching, so bounce+signup-flow@messagebird.dev still bounces.

Two behaviours make these reusable in a way real failures are not. A simulated bounce or complaint does not write to your suppression list and does not affect sending reputation, so the same address works every time. And a send can mix sandbox and real recipients, each getting its own lifecycle, which is how you rehearse a broadcast without mailing anyone.

What are the magic phone numbers?

Six US destinations, in the Twilio-style range so they will look familiar:

DestinationWhat your integration sees
+15005550001Rejected at submission with invalid_destination
+15005550002sms.sent, then sms.undelivered with unreachable
+15005550003sms.sent, then sms.failed with provider_unavailable
+15005550004sms.sent, then sms.failed with blocked_by_carrier
+15005550006sms.sent, then sms.delivered
+15005550009sms.sent, then sms.failed with recipient_opted_out

Two conditions catch people out on a fresh workspace, and both follow from these being real US sends. The United States has to be enabled under Destinations, and your from has to be a sender valid for the US, which an alphanumeric sender ID is not.

That +15005550004 row is worth noting if you have read our page on carrier filtering: blocked_by_carrier is a code the live pipeline does not produce, and this magic number is the one place you will see it.

What does a simulated send still cost?

More than people expect, and this is the part to design around.

An SMS to a magic number is billed at the destination's normal rate. Nothing reaches a handset, and the wallet charge is real, so a smoke test that loops has a bill attached.

A simulated email recipient counts against your send allowance. Rehearsing a broadcast against sandbox addresses exercises the same quota the real send would.

And sandbox traffic lands in your statistics. Simulated sends count toward your workspace's aggregate stats and its bounce and complaint rates, so heavy sandbox bouncing skews your dashboards even though it leaves your sending reputation alone. That pair is easy to get wrong in the reassuring direction: reputation is protected, the charts are not.

So size a test suite the way you would size production traffic, and prefer asserting on a handful of destinations over sweeping every outcome on every run.

How do I tell a test send from a real one?

Not from the payload, which is the honest answer and the one that shapes how you build.

A sandbox send returns the same 202, produces the same event shapes, and arrives on the same signed webhooks. There is no test flag. So your handler, your log and your metrics cannot distinguish a simulated bounce from a real one by looking at the event.

Two things help. On email, +label subaddressing survives into the events and webhooks even though it is stripped for matching, so bounce+ci-run-421@messagebird.dev tags a run in a way you can filter on afterwards. And the events land on the message timeline in the log and on the events API, so you can drive the sandbox and read the outcome back without running a webhook endpoint at all.

Test email delivery has every address with its exact SMTP codes and bounce classes, and migrating to Bird has the SMS numbers with a worked smoke test.

Build on the same network.

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

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