Contents

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.

NumberWhat happens
+15550000001sent → delivered → read within 3 s
+15550000002sent → delivered, never read
+15550000003failed 131026 RECIPIENT_UNREACHABLE
+15550000004131049 RECIPIENT_MARKETING_CAP (deferred)
+15550000005131047 SERVICE_WINDOW_CLOSED for free-form
+15550000006pair-rate: every message deferred 6 s (queued / pair_rate)
+15550000007provider timeout after accept → HELD → resolves by late sent after 2 min
+15550000008held_for_quality_assessment then released after 60 s
+15550000009held_for_quality_assessment then failed 132015 (template paused)
+15550000010user_preferences opt-out after first delivery → RECIPIENT_OPTED_OUT on the next marketing send
+15550000011sent only; then warning, then deleted
+15550000012inbound reply "hello" 5 s after delivery (opens the service window)
+15550000013inbound reply with referral (CTWA)
+15550000014BSUID-only recipient: status carries recipient_user_id, no recipient_id
+15550000015sender throughput 131057 for 30 s then accepted
+15550000016131064 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
+15550000018runs the status ladder past `read` to `played`, the voice-note terminal (§26)
+15550000429provider error 130429 (rate limit hit)
+15550000500provider error 1 (unknown / 500-class)
+15550000503provider error 2 (service unavailable / 503-class)
+15550000020customer 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 withReview 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:

message.received (abridged)
{
  "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.