Blooio

Community Blooio adapter for Chat SDK. Send and receive iMessage, RCS, and SMS through Blooio's hosted gateway, with native tapback reactions, typing indicators, and capability checks.

Community adapter. Not maintained by Vercel or Chat SDK contributors. For feature requests, bug reports, and support, file an issue on the adapter's repo.

Install

pnpm add chat-adapter-blooio

Quick start

lib/bot.ts
import { Chat } from "chat";
import { createBlooioAdapter } from "chat-adapter-blooio";

const chat = new Chat({
  userName: "my-bot",
  adapters: {
    blooio: createBlooioAdapter(),
  },
});

createBlooioAdapter() reads credentials from environment variables by default:

VariableRequiredDescription
BLOOIO_API_KEYYesBlooio API key (Bearer token)
BLOOIO_FROM_NUMBERNoDefault sending phone number (E.164) for multi-number accounts
BLOOIO_WEBHOOK_SECRETNoWebhook signing secret for HMAC-SHA256 verification
BLOOIO_BASE_URLNoOverride the API base URL (default: https://backend.blooio.com/v2/api)

Or pass them explicitly:

createBlooioAdapter({
  apiKey: "your-api-key",
  defaultFromNumber: "+14155551234",
  webhookSecret: "whsec_...",
});

Webhooks

Point your Blooio webhook URL at your server. The adapter handles these event types:

  • message.received — incoming iMessage/RCS/SMS routed to your bot
  • message.sent / message.delivered / message.failed / message.read — delivery lifecycle
  • message.reaction — tapback reactions on messages
app/api/webhooks/blooio/route.ts
import { chat } from "@/lib/bot";

export async function POST(request: Request) {
  await chat.initialize();
  return chat.webhooks.blooio(request);
}

Signature verification

Blooio signs webhooks with HMAC-SHA256. The adapter verifies the X-Blooio-Signature header automatically when webhookSecret is configured. The signature format is:

X-Blooio-Signature: t=<unix_timestamp>,v1=<hmac_sha256_hex>

Stale timestamps are rejected with a default tolerance of 300 seconds. Customize with:

createBlooioAdapter({
  webhookSecret: "whsec_...",
  timestampToleranceSec: 600, // 10 minutes
});

Sending messages

Outbound messages flow through Chat SDK's standard postMessage interface. Markdown is automatically stripped to plain text since iMessage does not render it.

await chat.send("blooio", threadId, "Hello from the bot!");

Attachments

Send media via sendMediaMessage:

import type { BlooioAdapter } from "chat-adapter-blooio";

const adapter = chat.getAdapter("blooio") as BlooioAdapter;
await adapter.sendMediaMessage(
  threadId,
  "https://example.com/photo.jpg",
  "Check this out"
);

Inbound attachment URLs from Blooio webhooks are parsed into Chat SDK attachment objects with auto-detected MIME types.

Reactions (tapbacks)

iMessage tapbacks are supported via addReaction and removeReaction. The adapter maps common emoji names to Blooio's six tapback types:

TapbackAliases
loveheart
likethumbs_up, thumbsup, +1
dislikethumbs_down, thumbsdown, -1
laughhaha
emphasizeexclamation, !!
question?

Unlike some platforms, Blooio supports removing reactions too.

Typing indicators

startTyping() sends the animated "..." bubble to the recipient. Works for both 1:1 and group conversations.

Message history

fetchMessages() retrieves conversation history from the Blooio API with cursor-based pagination (backed by offset/limit).

Read receipts

Send read receipts for a conversation:

import type { BlooioAdapter } from "chat-adapter-blooio";

const adapter = chat.getAdapter("blooio") as BlooioAdapter;
await adapter.markRead(threadId);

Contact capabilities

Check whether a contact supports iMessage or SMS:

const adapter = chat.getAdapter("blooio") as BlooioAdapter;
const result = await adapter.checkCapabilities("+15551234567");
// { contact: "+15551234567", capabilities: { imessage: true, sms: true } }

Direct API access

Reach any Blooio v2 endpoint that isn't covered by the adapter interface:

const adapter = chat.getAdapter("blooio") as BlooioAdapter;
const client = adapter.getClient();

await client.request("GET", "/contacts", undefined, { limit: "50" });
await client.request("POST", "/groups", {
  name: "Team",
  members: ["+15551234567"],
});

Protocol filtering

By default the adapter processes inbound messages from all protocols (iMessage, RCS, SMS). To restrict:

createBlooioAdapter({
  allowedProtocols: ["imessage"],
});

Thread ID format

Thread IDs encode the Blooio device number and chat target so conversations are sticky to a specific phone line:

blooio:<internalId_base64url>:<chatId_base64url>          # 1:1
blooio:<internalId_base64url>:g:<groupId_base64url>       # group

Use encodeThreadId / decodeThreadId to work with them programmatically.

Limitations

  • No message editing — iMessage does not support editing sent messages via API. editMessage throws.
  • No unsenddeleteMessage is a no-op; iMessage messages cannot be unsent via API.
  • Inbound media — attachment URLs from webhooks may expire. Persist them if you need them long-term.

Feature support

Messaging

FeatureSupported
Post message
Edit message
Delete message
File uploads
Streaming
Scheduled messages

Rich content

FeatureSupported
Card format
Buttons
Link buttons
Select menus
Tables
Fields
Images in cards
Modals

Conversations

FeatureSupported
Slash commands
Mentions
Add reactionsTapbacks
Remove reactionsTapbacks
Typing indicator
DMs
Ephemeral messages
User lookupcheckCapabilities
Parent subject
Native client
Custom API endpointbaseUrl

Message history

FeatureSupported
Fetch messages
Fetch single message
Fetch thread info
Fetch channel messages
List threads
Fetch channel info
Post channel message