Sendblue
iMessage, SMS, and RCS adapter for Chat SDK, built and maintained by Sendblue. Tapbacks, typing indicators, delivery status callbacks, and number lookup.
The Sendblue adapter connects Chat SDK bots to iMessage, SMS, and RCS. Use it when you want one bot implementation to handle Sendblue conversations alongside Slack, Teams, Discord, Telegram, email, or other Chat SDK adapters.
Sendblue maintains this adapter as Chat SDK and the Sendblue API evolve. For account, delivery, or credential help, contact Sendblue support.
Install
pnpm add chat-adapter-sendblue chat @chat-adapter/state-memoryThe adapter uses the official Sendblue TypeScript SDK under the hood. For production, use a persistent state adapter such as @chat-adapter/state-redis instead of in-memory state.
Quick start
import { Chat } from "chat";
import { createSendblueAdapter } from "chat-adapter-sendblue";
import { createMemoryState } from "@chat-adapter/state-memory";
const chat = new Chat({
userName: "imessage-bot",
adapters: {
sendblue: createSendblueAdapter(),
},
state: createMemoryState(),
});
chat.onDirectMessage(async (thread, message) => {
await thread.post(`Got it: ${message.text}`);
});createSendblueAdapter() reads credentials from environment variables by default:
| Variable | Required | Description |
|---|---|---|
SENDBLUE_API_KEY | Yes | Your Sendblue API key ID |
SENDBLUE_API_SECRET | Yes | Your Sendblue API secret key |
SENDBLUE_FROM_NUMBER | Yes | Your Sendblue number in E.164 format |
SENDBLUE_WEBHOOK_SECRET | No | Shared secret for webhook verification |
SENDBLUE_STATUS_CALLBACK_URL | No | Status callback URL for outbound message delivery events |
Find API credentials and assigned numbers in the Sendblue dashboard, or with the CLI:
npm install -g @sendblue/cli
sendblue setup
sendblue show-keys
sendblue linesOr pass credentials explicitly:
createSendblueAdapter({
apiKey: process.env.SENDBLUE_API_KEY,
apiSecret: process.env.SENDBLUE_API_SECRET,
defaultFromNumber: "+15551234567",
webhookSecret: process.env.SENDBLUE_WEBHOOK_SECRET,
});Webhooks
Create a webhook route and forward incoming Sendblue requests to Chat SDK:
import { chat } from "@/lib/bot";
export async function POST(request: Request) {
await chat.initialize();
return chat.webhooks.sendblue(request);
}Configure your Sendblue receive webhook to point at that endpoint, for example:
https://your-app.com/api/webhooks/sendblueWebhook verification
If you set SENDBLUE_WEBHOOK_SECRET, Sendblue should send the same secret with webhook requests. The adapter verifies the sb-signing-secret header by default. Override the header name if needed:
createSendblueAdapter({
webhookSecret: process.env.SENDBLUE_WEBHOOK_SECRET,
webhookSecretHeader: "x-custom-header",
});Sending messages
Use normal Chat SDK thread methods. Outbound messages go through Sendblue with iMessage-first delivery and automatic SMS/RCS fallback where available. Markdown is stripped to plain text because iMessage does not render it.
await thread.post("Hello from Sendblue via Chat SDK.");Attachments
Inbound media URLs from Sendblue are parsed into Chat SDK attachment objects. To send media, use Sendblue's media_url parameter through the underlying SDK:
import type { SendblueAdapter } from "chat-adapter-sendblue";
const adapter = chat.getAdapter("sendblue") as SendblueAdapter;
const sdk = adapter.getSdk();
await sdk.messages.send({
number: "+15551234567",
from_number: process.env.SENDBLUE_FROM_NUMBER!,
content: "Here is a photo.",
media_url: "https://example.com/photo.jpg",
});Reactions (tapbacks)
iMessage tapbacks are supported via addReaction. The adapter maps common emoji names to Sendblue's six tapback types:
| Tapback | Aliases |
|---|---|
love | heart |
like | thumbs_up, thumbsup, +1 |
dislike | thumbs_down, thumbsdown, -1 |
laugh | haha |
emphasize | exclamation, !! |
question | ? |
Tapbacks can be added but not removed via the Sendblue API.
Typing indicators
startTyping() sends the animated typing bubble to the recipient. Supported for 1:1 conversations only, not group chats.
Message history
fetchMessages() retrieves conversation history from the Sendblue API with cursor-based pagination.
Number lookup
Check whether a phone number supports iMessage, SMS, or RCS:
const adapter = chat.getAdapter("sendblue") as SendblueAdapter;
const result = await adapter.evaluateService("+15551234567");
// { number: "+15551234567", service: "iMessage" }Before high-volume sends, you can also use Sendblue's Lookup API to confirm iMessage support for a recipient.
Direct SDK access
For Sendblue APIs outside the standard Chat SDK adapter interface (media, contacts, webhooks, groups, and newer API features), use the underlying Sendblue SDK:
const adapter = chat.getAdapter("sendblue") as SendblueAdapter;
const sdk = adapter.getSdk();
await sdk.contacts.list();
await sdk.groups.sendMessage({ /* ... */ });
await sdk.webhooks.list();Service filtering
By default, the adapter processes only inbound iMessage traffic. To also accept SMS and RCS:
createSendblueAdapter({
allowedServices: ["iMessage", "SMS", "RCS"],
});Thread ID format
Thread IDs encode the Sendblue line number and contact (or group) so conversations stay tied to a specific phone line:
sendblue:<from_base64url>:<contact_base64url> # 1:1
sendblue:<from_base64url>:g:<group_id_base64url> # groupUse encodeThreadId / decodeThreadId to work with them programmatically.
Production notes
- Use a persistent Chat SDK state adapter in production so subscribed threads and conversation state survive deploys.
- Store Sendblue API keys in environment variables or your host's secret manager.
- Persist inbound media URLs if you need long-term access — Sendblue media URLs can expire.
- Keep your
from_numberstable per contact so end users always see the same Sendblue line.
Limitations
- No message editing — iMessage does not support editing sent messages via API.
editMessagethrows. - No recipient-side unsend —
deleteMessagedoes not remove messages already delivered to recipients. - No reaction removal — tapbacks can be added but not removed via the API.
- Typing indicators — 1:1 chats only, not group conversations.
Links
Feature support
Messaging
| Feature | Supported |
|---|---|
| Post message | |
| Edit message | |
| Delete message | |
| File uploads | Inbound + via SDK |
| Streaming | |
| Scheduled messages |
Rich content
| Feature | Supported |
|---|---|
| Card format | |
| Buttons | |
| Link buttons | |
| Select menus | |
| Tables | |
| Fields | |
| Images in cards | |
| Modals |
Conversations
| Feature | Supported |
|---|---|
| Slash commands | |
| Mentions | |
| Add reactions | Tapbacks |
| Remove reactions | |
| Typing indicator | 1:1 only |
| DMs | |
| Ephemeral messages | |
| User lookup | evaluateService |
| Parent subject | |
| Native client | |
| Custom API endpoint |
Message history
| Feature | Supported |
|---|---|
| Fetch messages | |
| Fetch single message | |
| Fetch thread info | |
| Fetch channel messages | |
| List threads | |
| Fetch channel info | |
| Post channel message |