Sendblue API
Overview
Sendblue is a REST API that sends iMessage (blue bubbles), SMS, and RCS from a provisioned phone number. Everything is plain JSON over HTTPS — no SDK is required. The API covers outbound 1:1 and group sends, iMessage effects, reactions, typing indicators, status callbacks, and inbound webhooks.
When to Use This Skill
- Use when writing application code (server, worker, function) that sends Sendblue messages as part of a long-running service.
- Use when receiving inbound messages via webhooks.
- Use when you need features the CLI does not expose: send styles, reactions, group messages, typing indicators, status callbacks, media uploads, or the contacts API beyond basic CRUD.
- Reach for [[sendblue-cli]] instead for shell-context outbound: one-shot scripts, cron jobs, agent hooks, "ping me when X" workflows.
How It Works
Step 1: Authenticate
Every request needs two headers:
sb-api-key-id: <YOUR_API_KEY_ID>
sb-api-secret-key: <YOUR_API_SECRET>
Content-Type: application/json
Keep both values server-side — never ship them to a browser or mobile client.
Step 2: Send a message
bash
curl -X POST https://api.sendblue.com/api/send-message \
-H "sb-api-key-id: $KEY_ID" \
-H "sb-api-secret-key: $SECRET" \
-H 'Content-Type: application/json' \
-d '{
"number": "+15551234567",
"from_number": "+1YOUR_SENDBLUE_NUMBER",
"content": "Hello from the API!"
}'
Phone numbers must be E.164.
must be a line you own — list yours with
.
Step 3: Track delivery
The synchronous response includes a
(Apple GUID — persist this; you need it for reactions and replies) and a
from
,
,
,
,
,
,
,
. Only
means it landed. Use
instead of polling
.
Step 4: Receive inbound
Configure webhook URLs in the dashboard or via
POST /api/account/webhooks
. Sendblue POSTs JSON to your endpoint. Respond with 2xx promptly — non-2xx triggers retries and duplicate deliveries. Event types:
,
,
,
,
,
,
.
Core Endpoints
| Method | Path | Purpose |
|---|
| POST | | Send a 1:1 message (text and/or media) |
| POST | | Send to multiple recipients |
| POST | | Create a named group thread |
| POST | | Send a tapback (love/like/dislike/laugh/emphasize/question) |
| POST | /api/send-typing-indicator
| Show "typing…" in the recipient's thread |
| POST | | Send a read receipt |
| POST | / | Upload media (direct or from URL) |
| GET | | Poll a message's delivery status |
| GET | | Check whether a number is on iMessage |
| GET | / | Read message history |
| GET / POST / PUT / DELETE | | Manage contacts |
| GET | | List your Sendblue phone numbers |
| POST | | CRUD webhook subscriptions |
Examples
Example 1: Send with media, effects, and a status callback
json
POST /api/send-message
{
"number": "+15551234567",
"from_number": "+1YOUR_SENDBLUE_NUMBER",
"content": "Optional text",
"media_url": "https://example.com/img.jpg",
"send_style": "celebration",
"status_callback": "https://yourapp.com/sendblue/status"
}
and/or
is required.
is iMessage-only — valid values:
,
,
,
,
,
,
,
,
,
,
,
,
. Ignored on SMS. Text up to 18,996 chars; media up to 100 MB on iMessage, 5 MB on SMS.
Example 2: Group message
json
POST /api/send-group-message
{
"numbers": ["+15551234567", "+15557654321"],
"from_number": "+1YOUR_SENDBLUE_NUMBER",
"content": "Hey team"
}
The response returns a
— persist it to send follow-ups into the same thread instead of creating a new one each time.
Example 3: React to a message
json
POST /api/send-reaction
{
"from_number": "+1YOUR_SENDBLUE_NUMBER",
"message_handle": "<message_handle from prior send>",
"reaction": "love"
}
Reactions only work on iMessage and need the original message's
. Valid values:
,
,
,
,
,
.
Example 4: Inbound webhook payload ()
json
{
"accountEmail": "you@example.com",
"content": "Reply text",
"media_url": "https://...",
"is_outbound": false,
"number": "+15551234567",
"from_number": "+1YOUR_SENDBLUE_NUMBER",
"service": "iMessage",
"group_id": "...",
"date_sent": "2024-01-01T12:00:00Z"
}
Status callback payloads (
) mirror the send-message response and update as the message moves through
→
(or
).
Best Practices
- ✅ Persist on every send. You need it for reactions, replies, and correlating status callbacks.
- ✅ Use over polling. It's lower-cost and more accurate than .
- ✅ Return 2xx fast from your webhook, then process async. Non-2xx triggers duplicate deliveries.
- ✅ Check service with before relying on iMessage-only features for a recipient.
- ✅ Rehost inbound media on receipt — media URLs expire in ~30 days.
- ❌ Don't ship / to a client. They are server-side credentials.
- ❌ Don't treat a 200 on as delivery. It only means "accepted".
Limitations
- Synchronous send responses only report acceptance, not delivery. Final state arrives via or .
- silently no-ops on SMS (green-bubble recipients).
- Inbound media URLs expire in ~30 days.
- Per-line rate limits apply; bursting many sends from one number can trip Apple's spam heuristics — pace them or split across lines.
- Reactions and effects are iMessage-only.
Security & Safety Notes
- Keep and server-side. They are not safe in browser, mobile, or CI logs.
- Webhook endpoints should be on HTTPS and idempotent — same may arrive more than once.
- Sensitive data in message content is visible in lock-screen previews on the recipient's device. Don't embed secrets, tokens, or full PII — link to an authenticated dashboard or shortened payload instead.
- Rotate API keys from the Sendblue dashboard if either value is exposed; the old pair is invalidated on rotation.
Common Pitfalls
- E.164 only. or will fail — always send .
- must be one of your lines. A spoofed or unprovisioned number returns an error.
- silently no-ops on SMS. If the recipient is green-bubble, effects don't render — check service first with if it matters.
- Store . You need it for reactions, replies, and correlating status callbacks back to your records.
- Media URLs expire in ~30 days. If you need durable media from inbound webhooks, download and re-host on receipt.
- Status is async. A 200 on means accepted, not delivered. Use rather than blocking on the synchronous response.
- Webhook retries on non-2xx. Return 200 even when you've decided to ignore the event; otherwise expect duplicate deliveries.
- Rate limits apply per line. Bursting many sends from one number trips Apple's spam heuristics — pace them or split across lines.
Related Skills
- — Shell wrapper for shell-context outbound (scripts, cron, agent hooks). Use it when you don't need a full HTTP integration.
- — Patterns and copy rules for outbound "text me when X is done" notifications layered on top of the API or CLI.
Links
- Full reference: https://docs.sendblue.com/
- Sendblue: https://sendblue.com
- Useful undocumented-here features: carousels (), FaceTime/contact-card sharing, advanced webhook filtering, contacts API beyond basic CRUD — see the docs site.