Testing senders & reply routing

Exercise sender selection and per-number reply routing end-to-end in test mode — no carrier traffic, real signatures.

This guide shows how to verify two things end-to-end without sending real SMS: which number a message goes out on (from), and where a reply to that number is routed (per-number reply destinations). It builds on test keys & magic numbers — issue a test key first.

In test mode nothing reaches a carrier and nothing is billed, but your status-callback and reply-destination integrations fire for real, with genuine signatures.

Testing sender selection (from)

Pass from (an E.164 number in your workspace) on the send. The ack echoes the resolved sending number as phone_number_id:

curl -X POST https://api.beepmessaging.com/api/v1/messages \
  -H "Authorization: Bearer beep_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+1XXXXXXXXXX",
    "messages": [{ "to": "+15005550101", "body": "Hello from a specific number" }]
  }'
# -> { "data": { "id": "...", "status": "queued", "phone_number_id": "...", "mode": "test" } }

With a test key, from is used as the simulated sender and is not required to be provisioned. With a live key, an unknown from returns 400 validation_error.

Testing per-number reply routing

This is the flow to verify that replies to a given number land in that number's reply destination.

  1. Configure the number. Provision the number you want to test (number X), and in Settings → SMS set its Reply destination to a webhook destination Y (created in Settings → Webhooks).

  2. Send a test message from X to the reply-triggering magic number. +15005550106 simulates a successful delivery followed by an inbound reply:

    curl -X POST https://api.beepmessaging.com/api/v1/messages \
      -H "Authorization: Bearer beep_test_..." \
      -H "Content-Type: application/json" \
      -d '{ "from": "<X in E.164>", "messages": [{ "to": "+15005550106", "body": "ping" }] }'
  3. Observe the routed reply. Beep simulates a reply arriving at X, runs it through the real resolver, and delivers a signed message.received POST to Y — exactly as production would. Verify the signature the same way as a status callback.

Resolution order (what you're exercising)

For each inbound reply, Beep resolves the destination in this order:

  1. The conversation's own destination (set when an outbound carried a reply_destination_id).
  2. The per-number default on the number the reply arrived at (step you're testing).
  3. The workspace default.

So if you omit from (or send from a number with no per-number destination), the simulated reply uses the synthetic sender and falls through to the workspace default — that's the basic smoke-test path. To exercise per-number routing specifically, send from the configured number X.

Validating per-number routing with zero provisioned numbers

You don't need a provisioned carrier number to exercise per-number routing — you can create a test number and assign destinations to it. Test numbers are synthetic (no carrier, no cost), usable only with a test key, and they participate fully in per-number reply and status-callback resolution. This lets you validate both routing paths end-to-end before any number is provisioned.

  1. Create a test number. With a test key, POST /api/v1/phone-numbers. Test numbers come from the reserved range +15005550200–+15005550299:

    curl -X POST https://api.beepmessaging.com/api/v1/phone-numbers \
      -H "Authorization: Bearer beep_test_..." \
      -H "Content-Type: application/json" \
      -d '{ "e164": "+15005550200" }'
    # -> { "data": { "id": "<number-id>", "e164": "+15005550200", "is_test_only": true } }

    (You can also add one from the dashboard: Settings → SMS → Add test number, available even before SMS provisioning.)

  2. Assign destinations to the number. Use the returned id with PATCH /api/v1/phone-numbers/{id} to set a reply destination, a status-callback destination, or both:

    curl -X PATCH https://api.beepmessaging.com/api/v1/phone-numbers/<number-id> \
      -H "Authorization: Bearer beep_test_..." \
      -H "Content-Type: application/json" \
      -d '{
        "reply_destination_id": "<reply-dest-id>",
        "status_callback_destination_id": "<status-callback-dest-id>"
      }'
  3. Send from the test number to the reply-triggering magic number. +15005550106 simulates a successful delivery followed by an inbound reply:

    curl -X POST https://api.beepmessaging.com/api/v1/messages \
      -H "Authorization: Bearer beep_test_..." \
      -H "Content-Type: application/json" \
      -d '{ "from": "+15005550200", "messages": [{ "to": "+15005550106", "body": "ping" }] }'

    Beep simulates the message lifecycle from the test number, so your status-callback destination receives signed message.<event> events resolved via the number's per-number default. It then simulates an inbound reply arriving at the test number, which resolves to the number's reply destination and receives a signed message.received POST. Both arrive with genuine signatures — verify them exactly as in production.

GET /api/v1/phone-numbers lists all workspace numbers (test and live) so you can confirm assignments. Test numbers never reach a carrier, are never billed, and are excluded from analytics and the inbox sender selector.

Notes

  • Test sends carry test_mode: true and are excluded from analytics and campaign aggregations.
  • Cold inbound (a first-contact text to X with no prior outbound) resolves the same way — step 2 catches it via the number it arrived at.

Related


Did this page help you?