Send & Receive Messages
This guide takes you from an API key to a working two-way message flow: send an outbound message, track its delivery, and receive the reply on your own server. SMS is used as the running example — the same three-step pattern (send → track → receive) applies to WhatsApp, RCS, Viber, and Email, each on its own endpoint. You will:Prerequisites
- An API key from Settings → API Keys. Use a sandbox key (
dv_test_sk_…) while you build — sandbox sends are free and simulated, and return deterministic delivery receipts so you can exercise both the success and failure paths. Swap in a live key (dv_live_sk_…) for production. - A sender number that can send on the channel you’re using. For SMS that’s an SMS-capable number you own (search and buy one via the Numbers API, or from Dashboard → Numbers). Omit
fromand Orbit picks an eligible sender for the destination. - A public HTTPS URL for the receive step. Any tunneling tool works while developing.
X-API-Key header.
1. Send a message
Send an SMS withPOST /messages/sms. Only to and body are required; from is optional.
202 Accepted — the message is persisted and queued for delivery, not yet handed to the carrier. Fields live under data; meta carries the request_id you should log for support.
id (msg_ followed by 32 hex characters) is the handle for every follow-up call — status lookups, delivery webhooks, and the message trace all key off it. Sandbox responses add "test_mode": true to meta.
Always send an
Idempotency-Key on sends. Replaying the same key and body within 24 hours returns the original response instead of sending a duplicate; replaying it with a different body returns 409 IDEMPOTENCY_KEY_REUSED.Other channels
Each channel has its own endpoint under the/messages prefix with a body shape suited to that channel. There is no single channel-polymorphic route — pick the endpoint that matches your channel:
2. Track delivery
A queued message moves through a status lifecycle before it reaches the recipient:id and new status:
message.sent— accepted by the carriermessage.delivered— confirmed delivered to the handsetmessage.failed— terminal failure (the payload’sstatusdistinguishesfailed,undelivered,expired, andsubmitted_no_receipt;error_code/error_messagecarry the provider reason when present)
X-Orbit-Signature header before trusting any payload, and deduplicate on the event id — delivery is at-least-once. See Webhooks security for the verification snippet.
3. Receive inbound messages
When someone replies to your number (or messages it first), Orbit records an inbound message and — if you subscribed tomessage.received in the step above — POSTs it to your webhook URL:
direction=inbound filter:
Inbound routing is automatic for numbers you own on Orbit — a reply to any of your sender numbers is captured and, with a
message.received subscription, delivered to your webhook. No per-number inbound URL wiring is required.4. Reply to an inbound message
Replying is just another send, addressed back to the inboundfrom. Swap to and from and call POST /messages/sms again:
conversation_id filter on GET /messages once the thread exists.
Common errors
Every error uses the same shape — match onerror.code (an UPPERCASE constant), and log meta.request_id:
Full list: Error Codes.
Next steps
- Messaging API reference — every message endpoint and field
- Message status lifecycle — the full status set per channel
- Webhooks overview — retries, delivery guarantees, and the event catalog
- API Integration — sandbox, idempotency, pagination, and SDKs across every channel
- Rate Limits — per-channel limits and retry headers