Get started
Sandbox and test numbers
The sandbox runs the real ShipMsg pipeline — validation, queues, statuses, webhooks — against a simulated WhatsApp. Use it to build and test every path, including the failures that are hard to cause on purpose in production.
How the sandbox differs from live
- Use an
sk_test_key. Every response carries"livemode": false. - Messages go to a WhatsApp simulator, never to a real phone, and nothing is billed.
- Templates you submit are reviewed by the simulator within seconds.
- Request rate limits are lower than live (10% of your plan); see rate limits.
Test recipient numbers
Send to these numbers to get a known outcome. Any other number is accepted and delivered normally through the simulator; nothing leaves the sandbox.
| Number | What happens |
|---|---|
+15550000001 | sent → delivered → read within 3 s |
+15550000002 | sent → delivered, never read |
+15550000003 | failed 131026 RECIPIENT_UNREACHABLE |
+15550000004 | 131049 RECIPIENT_MARKETING_CAP (deferred) |
+15550000005 | 131047 SERVICE_WINDOW_CLOSED for free-form |
+15550000006 | pair-rate: every message deferred 6 s (queued / pair_rate) |
+15550000007 | provider timeout after accept → HELD → resolves by late sent after 2 min |
+15550000008 | held_for_quality_assessment then released after 60 s |
+15550000009 | held_for_quality_assessment then failed 132015 (template paused) |
+15550000010 | user_preferences opt-out after first delivery → RECIPIENT_OPTED_OUT on the next marketing send |
+15550000011 | sent only; then warning, then deleted |
+15550000012 | inbound reply "hello" 5 s after delivery (opens the service window) |
+15550000013 | inbound reply with referral (CTWA) |
+15550000014 | BSUID-only recipient: status carries recipient_user_id, no recipient_id |
+15550000015 | sender throughput 131057 for 30 s then accepted |
+15550000016 | 131064 sender restriction for 10 min (affects the whole sandbox sender) |
+15550000017 | `message_status = paused` — Meta accepted but is delaying delivery (§18.4.7); a later `sent` webhook, or nothing, resolves it |
+15550000018 | runs the status ladder past `read` to `played`, the voice-note terminal (§26) |
+15550000429 | provider error 130429 (rate limit hit) |
+15550000500 | provider error 1 (unknown / 500-class) |
+15550000503 | provider error 2 (service unavailable / 503-class) |
+15550000020 | customer webhook: every delivery fails with timeout (exercise retries) |
Numbers in the outcomes (131026, 131047 …) are WhatsApp’s own error codes; ShipMsg maps them to its error codes and keeps Meta’s in providerCode.
Test template names
A template whose name starts with one of these prefixes gets a scripted review:
| Name starts with | Review outcome |
|---|---|
sandbox_reject_once_ | rejected on first submission and approved after a corrected resubmission |
sandbox_reject_ | REJECTED |
sandbox_pause_ | approved then paused after first send |
Any other template name is approved.
Testing inbound messages
Send any message to +15550000012. Five seconds after it is delivered, the test contact replies “hello”, which opens a 24-hour service window and arrives on your webhook as message.received:
{
"id": "EV6P8Y0RSKWN2F5EFPA5ZR23PT6R",
"type": "message.received",
"livemode": false,
"data": {
"object": "message",
"sid": "SMNY0Q31B9WJCP6SZ0X8XWFW1B5C",
"direction": "inbound",
"type": "text",
"text": { "body": "hello" },
"from": "WA…", // your sender that received it
"to": { "identifierType": "phone_e164", "value": "+15550000012", "contactSid": "CT…" },
"profileName": "Simulated User",
"serviceWindowExpiresAt": "2026-09-27T22:54:03.000Z",
…
}
}On inbound messages from is your own sender and the customer who wrote is in to (the message’s contact). See webhooks.