1. Get the application and run the offline test
npm install is needed for this application. SQLite may print
an experimental API warning. The test starts local HTTP servers and a temporary
database; no credentials or live SMS sends are needed. Read or download the
complete application and README.
The test exercises a lost acceptance response, database restart, duplicate and
out-of-order events, stale signatures, secret-version checks, rejected business
and event IDs, failed storage and a worker retry. A local API stub proves the
application’s recovery paths; it does not establish live delivery or charging.
2. Prepare approved Sandbox access
Complete the Quickstart. You need a Sandbox access token, business ID, authorized sender and permitted test recipient. Use the same business throughout this tutorial, with access to send SMS, retrieve message status and configure webhooks. If these features are unavailable for your business, contact Support before continuing. In each terminal used below, set the same environment variables:3. Register and start the receiver
Prepare an HTTPS URL routed tohttp://127.0.0.1:8080/hooks/1funnel by your trusted
reverse proxy or development tunnel. Preserve the request bytes and webhook
headers; expose only this path. Follow
Configure endpoints and
Create a webhook endpoint
to register that HTTPS URL with these event types:
201, the accepted subscriptions and any warnings before proceeding.
Save the returned endpoint ID and securely retain the signing secret. Use the
original secret version 1 until an operator coordinates a rotation.
Create private keys.json:
204; duplicates also receive 204. Storage failure returns
503 so delivery can retry. Verification failure returns 401.
4. Submit one SMS and save its ID
In a second terminal in the same directory, createrequest.json. Replace the
sender and recipient with your approved values:
202, then saves the returned id and status. Acceptance is not
delivery confirmation. The actual response supplies the ID; do not copy one from
an example.
If the connection fails, run the exact same command with the unchanged file and
database. The application reuses the saved key. Once a message ID is saved,
repeating the command returns that saved result without another POST. A changed
payload under the same application operation ID is rejected. Review HTTP errors
before retrying; do not change the key to bypass them.
The idempotency replay window and recovery rules
apply. If acceptance remains uncertain after seven days, investigate the original
request instead of inventing a new key or deleting local state.
5. Process notifications and inspect the saved status
In a third terminal, with the same environment and database:work processes up to 50 pending inbox entries and exits. Repeat it periodically;
run only one worker at a time. For each known message ID it calls
Retrieve an individual SMS,
requires HTTP 200, then commits the snapshot and processed marker together.
inspect shows message_id, status, checked_at and inbox processed_at.
A status of delivered records the observed delivery outcome; sent alone does
not confirm handset delivery.
A failed GET leaves the event pending for another worker attempt. Respect rate
limits and Retry-After when scheduling retries. An event that arrives before the
acceptance response stays pending until the saved send has a message ID. The
worker reads current REST state instead of treating a late sent event as newer
than a delivered event. See the
published delivered event
for its actual envelope and fields.
6. Recover a missing notification
Before using this design in production
The application deliberately has one worker, no external business side effects and a local SQLite database. Add supervised execution, retry backoff, monitoring for pending and unknown-message events, storage limits, retention and tested backups before operating it. Monitorchecked_at: a saved snapshot is not a
promise that status will never change. Keep the receiver clock synchronized.
Scaling workers requires coordinated claims; adding business effects requires
an idempotent transaction or outbox design. See the application README for the
single-machine boundaries and durable receipt patterns.