Direct send: one-off messages, batch or single
Some sends are not campaigns. A support follow-up to one customer, a one-time notification to a finite list — no named audience, no schedule, no per-variant analytics to justify a campaign object. Outbound → Direct send is the entry point for those sends. It is a chooser page with two paths:- Send to a list (CSV) — the batch SMS wizard at Messages → Batch SMS: upload a recipient list, render a template per row, review cost, and send everything in one batch.
- Send to one contact — a picker that searches your contacts, shows every channel the contact is reachable on, and opens that channel’s composer with the recipient prefilled.
When direct send instead of a campaign
If a recurring weekly CSV run or per-variant measurement appears, the send has outgrown direct send — move it to a campaign and follow Send a campaign end-to-end.
The chooser page
Open Outbound → Direct send. Two cards lead:- Send to a list (CSV) links straight to the batch wizard — the next section covers it.
- Send to one contact opens the contact picker.
Single contact: pick a contact, choose a channel
The Send to one contact card opens a picker:- Search your contacts by name, phone, or email.
- Select a contact. The picker lists every identifier on the contact — a contact with both a phone number and an email shows both — and offers every channel it can route to: SMS for a phone number, Email for an email address.
- Choose the channel and continue. The picker routes to that channel’s composer with the recipient prefilled:
/messages/sms?to=<phone>&contactId=<id>or/messages/email?to=<email>&contactId=<id>. Thetoparameter prefills the To field;contactIdrecords which contact row you came from.
Batch: CSV to a finished send
The Send to a list (CSV) card opens Messages → Batch SMS, a three-step wizard:- Upload — drop a
.csv(or paste numbers directly), or load recipients from an existing contact list. - Preview — review the per-row rendered message, segment counts, and the cost breakdown resolved per destination.
- Send — the wizard submits the whole batch as a single
POST /messages/batchrequest and reports each recipient’s outcome.
CSV rules for batch sends
The wizard’s Upload step understands three recipient sources — CSV, pasted numbers, or a saved contact list — and only one source is active at a time: choosing a second source replaces the first rather than combining both. The CSV contract:- One phone column is required. The header row is auto-detected. Recognized phone-column headers include
phone,phone_number,to,number,mobile,telephone, andtel. Recipients are E.164 numbers; whitespace, dashes, and parentheses are stripped before validation. - Per-row message column switches to per-row mode. If the CSV has a
message,body,text,content,sms, orsms_bodyheader, every row carries its own body and the shared compose step is skipped. Otherwise the wizard applies one shared template with{{variable}}placeholders, and your extra CSV columns (for examplename) bind those variables per row. - Invalid and duplicate rows are excluded, not fatal. A partial number like
+123is flagged and dropped; duplicates are merged with a count. Excluded rows are never priced and never sent — the review footnote discloses exactly how many were skipped. - Rejections stay per-row. A post-upload rejection (validation, quota, sender-validation, country gate set in your compliance controls) flips only that row to
failed; the rest of the batch still sends.
Retries: idempotency and remapping
The batch is submitted as onePOST /messages/batch call; failures come back as per-row outcomes, never as a silent whole-batch loss:
- Every recipient is persisted before it is attempted. Each recipient becomes a message row first — a rejected row is visible in the failed-recipients table immediately with its reason, not dropped. The response is
200when every recipient succeeded and207 (Multi-Status)when at least one failed alongside at least one success. - Retry failed rows only. The failed-recipients table lists each row with a remapped, friendly reason and the raw machine-readable
error_codeas a badge. For carrier-side or transient failures, the messaging retry policy applies server-side — retry the failed recipients; already-sent rows are not re-sent when you re-submit the batch envelope with the same idempotency behaviour. - Batch envelope rate limit. One batch is one request, capped at 30 batch envelopes per minute per tenant (
X-RateLimit-Bucket: messages-batchon the response headers tells your SDK when to back off). The per-recipient cost — carrier throughput, frequency caps, quota — is enforced inside the send pipeline, not by this limit.
Permissions and limits per channel
Direct send is a send, so it is gated like every other send in the workspace:- Role. Sending — from the batch wizard, the single-contact composer, or the API — requires an owner, admin, or developer role. Members with a read-only (viewer / light-seat) role cannot fire a direct send.
- API key scope. API-driven sends need a key minted with the
messages:writescope; a read-only key is rejected with 403. - Per-channel limits.
POST /messages/batchaccepts up to 10,000 recipients per call (resolved per tenant) acrosssms,whatsapp,email,rcs,viber,instagram,messenger,line, andtelegram. The dashboard batch wizard drives SMS; the same route handles the other channels over the API. - Sender and channel setup. SMS needs a sender — an owned number, an alphanumeric sender ID, or a sender pool. Email needs a verified sending address. WhatsApp needs a connected WABA sender. A contact with no reachable identifier for the channel (for example an SMS-only contact sent to the Email composer) has nothing to address — the composer starts empty.
- Wallet and attestation. The batch wizard’s confirm step is gated on a wallet check and a compliance attestation that recipients are authorized and opt-outs honored.
How direct send relates to campaigns
Both surfaces end at the same send pipeline. What a campaign adds is everything around the send:
Guardrails do not relax because a send is one-off. Direct sends pass through the same tenant controls as campaign sends:
- Suppression lists and channel-level opt-outs are checked per recipient — a suppressed or opted-out recipient is held back either way (see Opt-out lists and suppression).
- Frequency caps count a direct send toward the recipient’s budget (see Frequency caps).
- Quiet hours and send gating defer or block sends inside a recipient-local quiet window, direct send or campaign alike (see Quiet hours configuration).
See also
- Batch SMS: send a one-off message to many recipients — the wizard’s review, pricing, and failure-retry mechanics in full
- Send and receive messages — the per-channel composer the contact picker opens
- Send a campaign end-to-end — when the send has outgrown direct send
- Outbound goals, approvals, and direct send — the approval gate and goal attribution a campaign adds on top
- Message scheduling — one-off
scheduled_atsemantics on batches