Sending
Two ways out, and most projects want the first. Hand the message over and Switchboard decides which number sends it, when, and how often to retry.
The send queue#
typescript
const { id } = await wa.outbound.send({ to: "+971500000001", message: { text: "hello" }, }) const { state } = await wa.outbound.status(id) // queued → sent → delivered → read
You name no number. Switchboard chooses one of yours when the message is actually due, paces it, retries it, and records what happened to it.
202, not 200
send() resolves when the message is accepted, not sent — the server answers 202 for exactly that reason. Use status(id) for what actually happened.| What it buys you | Instead of |
|---|---|
| A cap is not an error | daily_cap_reached used to be yours to handle. Now the message is queued until tomorrow. |
| You cannot burst | The queue decides when each message leaves, so a loop calling send() 500 times does not become 500 messages in a minute. |
| A ban doesn’t strand work | The number is chosen when the message is due, so one banned in the meantime is skipped. |
| Scheduling | sendAfter: new Date(...) — one field. |
Do not build your own send queue on top of this one
Pooling, pacing, retries, cap-awareness and scheduling are the queue’s job, and every one of them is subtle in a way that costs a SIM to learn. If you find yourself writing a worker that picks a number and sleeps between sends, you are rebuilding this — and your copy will diverge from the caps and warm-up state the service holds authoritatively.
When nothing is going out#
Ask the pool rather than reading individual errors.
typescript
const pool = await wa.outbound.pool() // pool.numbers[].reason — one of: // "daily cap reached" "pacing" "banned" // "restricted" "offline" "never paired"
Every number is reported, including the ones that cannot send, each with its own reason. No number is named as “next”: selection happens again when a message is actually due, so naming a winner would be a lie.
The direct path#
Still there, unchanged, for when you want one specific number and an immediate answer.
typescript
await wa.line(instanceToken).sendText("+971500000001", "hello")
Errors you can act on#
| Helper | Status | Means |
|---|---|---|
| isRateLimited | 429 | Your project’s rate limit, or a number’s daily cap. retryAfter is set for the first. |
| isUnavailable | 503 | A number is momentarily moving between replicas. The one error worth retrying. |
| isUnauthorized | 401 | Bad key — or a suspended project. Check before assuming. |
| isGone | 410 | A dead letter’s payload was redacted past its retention. Replay will never work. |