overblast
v0.1.0
Published
Overblast SDK + CLI — manage workspaces, social posts, DMs, webchat, email, phone calls, todos, contact memory, and webhooks.
Maintainers
Readme
overblast
A unified SDK + CLI for the Overblast platform: workspaces, social posts/DMs, webchat, email, phone calls, conversation memory, todos, and webhooks.
Works as a Node.js CLI or as an ESM library you import from your own code.
npm install overblastQuick start
Use it as a Node.js library
import { Overblast } from 'overblast';
const ob = new Overblast({ apiKey: process.env.OVERBLAST_API_KEY! });
// List all conversations across a workspace's social inbox
const { conversations } = await ob.conversations.list(profileSetId);
// Reply to a webchat conversation
await ob.webchat.reply(computerId, {
conversationId: 'webchat_abc123',
content: 'Hi! Yes, we are open until 6pm today.',
});
// Place a call
const { callId } = await ob.calls.create({
computerId,
phoneE164: '+15551234567',
fromPhoneE164: '+15557654321',
goal: 'Confirm Tuesday\'s 3pm appointment.',
});
// Subscribe to incoming messages in real time
await ob.webhooks.create(computerId, {
eventType: 'message.received',
url: 'https://my-app.example.com/inbound',
});Use it as a CLI
export OVERBLAST_API_KEY=ob_live_...
overblast profile-sets list
overblast conv list <profileSetId>
overblast webchat reply <computerId> webchat_abc123 "Yes, we're open until 6pm."
overblast email send <computerId> [email protected] "Re: your enquiry" "Thanks for…" --domain 0-0.chat
overblast call <computerId> +15551234567 "Confirm Tuesday's 3pm" --from +15557654321
overblast webhook create <computerId> --event message.received --url https://my-app.example.com/inboundoverblast --help prints the full command reference.
Authentication
The SDK and CLI both authenticate with a workspace API key. Pass it three ways (in priority order):
--api-key ob_live_...flag (CLI only)OVERBLAST_API_KEYenvironment variablenew Overblast({ apiKey: '...' })constructor (library)
API keys are scoped to a single computer (workspace). Mint and rotate keys with:
overblast api-keys list
overblast api-keys create --name "claude-code" --computer <cid> \
--scopes dm:send,todo:read,todo:create
overblast api-keys revoke <keyId>The default base URL is https://brain.deployd.network/social. Override via
--base-url (CLI) or baseUrl (library) when targeting staging/preview.
What you can do
The SDK exposes every conversational channel the platform serves, plus the admin and bookkeeping primitives around them.
| Channel | Read messages | Send / reply | Real-time | Notes |
|---|---|---|---|---|
| Social DMs (Twitter, IG, FB, etc.) | conversations.list / conversations.messages | conversations.sendDm | message.received webhook | Per profile set |
| Webchat (website widget) | webchat.info (settings) | webchat.reply | message.received webhook | Conversation IDs are webchat_<deviceId> |
| Email (ticketed threads) | n/a — surfaced via webhooks | email.createThread / email.reply | message.received webhook | Inbound goes to {cid}.agent@{domain} |
| Phone calls (Twilio + voice agent) | calls.list / calls.conversation / calls.transcriptPdfUrl / calls.recordingUrl | calls.create | call.started / call.ended webhooks | LiveKit-powered voice agent runs the call |
| Comments / reviews | passthrough.call (raw Zernio routes) | same | comment.received webhook | Listed under "raw API" below |
Cross-cutting:
| Capability | Method |
|---|---|
| Workspace todo list (active by default) | todos.list(cid) |
| Conversation-scoped todos | todos.list(cid, { conversationId }) |
| Archived/all todos | todos.list(cid, { status: 'all' }) |
| Contact memory (markdown) | contacts.memory(profileSetId, contactId) |
| Bundled conversation context | context.forConversation(...) |
| Real-time event push | webhooks.create / list / delete |
Library reference
Constructor
new Overblast({
apiKey: string, // required
baseUrl?: string, // default https://brain.deployd.network/social
})All methods return parsed JSON. Errors throw OverblastError with
status/body for inspection:
import { OverblastError } from 'overblast';
try {
await ob.calls.create({ … });
} catch (e) {
if (e instanceof OverblastError && e.status === 402) {
console.warn('Out of credits:', e.body);
} else throw e;
}conversations — social inbox (DMs across platforms)
| Method | Endpoint |
|---|---|
| conversations.list(profileSetId, { limit?, cursor?, archived? }) | GET /z/:psid/conversations |
| conversations.messages(profileSetId, conversationId, { limit?, before? }) | GET /z/:psid/conversations/:id/messages |
| conversations.sendDm(profileSetId, conversationId, { text, attachmentUrl?, attachmentType?, tmpKey? }) | POST /z/:psid/dm/:id |
| conversations.start(profileSetId, body) | POST /z/:psid/conversations |
| conversations.update(profileSetId, conversationId, body) | PUT /z/:psid/conversations/:id |
| conversations.deleteMessage(profileSetId, conversationId, messageId) | DELETE /z/:psid/dm/:id/messages/:mid |
| conversations.editMessage(profileSetId, conversationId, messageId, { text }) | PATCH /z/:psid/dm/:id/messages/:mid |
webchat — live website chat
| Method | Endpoint |
|---|---|
| webchat.info(computerId) | GET /webchat/:cid/info |
| webchat.reply(computerId, { conversationId, content?, attachmentUrl?, attachmentType?, tmpKey? }) | POST /webchat/:cid/reply |
| webchat.getSettings(computerId) / webchat.updateSettings(cid, settings) | GET / PUT /webchat/settings/:cid |
| webchat.createInviteToken(computerId) | POST /webchat/settings/:cid/token |
conversationId is always webchat_<deviceId>.
email — ticketed email threads
| Method | Endpoint |
|---|---|
| email.createThread({ computerId?, toAddr, toName?, receivedOnDomain, subject, body, attachments?, tmpKey? }) | POST /email/threads |
| email.reply(threadId, { body, attachments?, tmpKey? }) | POST /email/threads/:id/reply |
| email.quota(computerId?) | GET /email/quota |
receivedOnDomain is one of '0-0.chat' | 'deploydstudio.com' | 'overblast.com'
— the From address on outbound is {computerId}.agent@{receivedOnDomain}.
Attachment items reference R2-stored objects:
{ key: 'kb://my-folder/spec.pdf', filename: 'spec.pdf', contentType: 'application/pdf' }Inbound mail is delivered by Cloudflare Email Routing to the agent address and
fired as a message.received webhook event — there is no polling read API.
calls — phone calls + voice agent
| Method | Endpoint |
|---|---|
| calls.create({ computerId?, phoneE164, fromPhoneE164, goal, scheduleAt?, contactName?, taskInstructions?, taskTemplateIds?, voice?, language?, skillId? }) | POST /calls/ |
| calls.list({ computerId?, status?, direction?, limit?, offset? }) | GET /calls/ |
| calls.listConversations({ computerId?, limit? }) | GET /calls/conversations |
| calls.conversation(conversationId) | GET /calls/conversations/:id |
| calls.get(callId) | GET /calls/:id |
| calls.recordingUrl(callId) | GET /calls/:id/recording-url |
| calls.transcriptPdfUrl(callId) | GET /calls/:id/transcript-pdf |
| calls.reschedule(callId, scheduleAt) | PATCH /calls/:id/schedule |
| calls.setGoal(callId, goal) | PATCH /calls/:id/goal |
| calls.cancel(callId) | POST /calls/:id/cancel |
| calls.sharedNumbers() | GET /calls/shared-numbers |
Notes:
fromPhoneE164must be one of the workspace'sshared-numbers.- The platform refuses calls when balance <
CALL_MIN_CHARGE_CENTS. CatchOverblastErrorwithstatus === 402to surface this. goalis the system prompt the agent runs with.taskInstructionsadds free-form "how to do it" guidance separate from the goal.
todos — workspace + per-conversation tasks
| Method | Endpoint |
|---|---|
| todos.list(computerId, opts) | GET /todos |
| todos.create(computerId, opts) | POST /todos |
| todos.update(computerId, todoId, patch) | PATCH /todos/:id |
| todos.delete(computerId, todoId) | DELETE /todos/:id |
| todos.recordPayment(computerId, todoId, { deltaAmount, currency, note?, source? }) | POST /todos/:id/payments |
todos.list defaults to active only (status: 'open'). Useful filters:
// All workspace open todos
await ob.todos.list(cid);
// Including archived/completed
await ob.todos.list(cid, { status: 'all' });
// Open todos linked to a specific conversation
await ob.todos.list(cid, { conversationId });
// All todos (incl. archived) for a contact across threads
await ob.todos.list(cid, { contactId, status: 'all' });contacts — directory + per-contact memory
| Method | Endpoint |
|---|---|
| contacts.list(profileSetId, { limit?, page?, q? }) | GET /z/:psid/contacts |
| contacts.memory(profileSetId, contactId) | GET /z/:psid/contacts/:cid/memory |
contacts.memory returns { content: string } — a markdown document the
auto-reply agent maintains about the contact (preferences, prior asks, etc.).
context — bundled conversation context
const ctx = await ob.context.forConversation({
computerId,
conversationId,
contactId, // optional — needed for memory + cross-thread todos
profileSetId, // optional — needed for memory + recent messages
kind: 'social', // 'social' | 'webchat' | 'call' | 'email'
includeArchived: false,
});
// → { conversationId, contactId, memory, todos, recentMessages?, recentCalls? }Convenience wrapper that parallel-fetches contact memory + active todos + the most recent messages or calls. Use this to give an LLM a single payload to reason about a thread.
webhooks — real-time event push
| Method | Endpoint |
|---|---|
| webhooks.list(computerId) | GET /webhooks/computers/:cid |
| webhooks.create(computerId, { eventType, url }) | POST /webhooks/computers/:cid |
| webhooks.delete(computerId, webhookId) | DELETE /webhooks/computers/:cid/:id |
Supported event types:
| Event | When it fires | Key payload fields |
|---|---|---|
| message.received | Inbound DM, webchat message, or email | conversationId, platform, content, contactId, contactName |
| comment.received | New comment on a published post | postId, commentId, commentText, authorName |
| dm.sent | Outbound DM completes upstream | conversationId, response (raw upstream body) |
| post.published | Scheduled post publishes | postId, platforms, content |
| call.started / call.ended | Call lifecycle | callId, direction, phoneE164, summary?, disposition? |
| todo.{created,updated,deleted} | Todo lifecycle | todoId, title, status |
| task_template.{created,updated,deleted} | Template CRUD | templateId, fields |
Use eventType: '*' to subscribe to everything.
The worker signs payloads with the webhook_secret returned at creation time;
verify by HMAC-SHA256 over the raw body before trusting the event.
posts / dm / profileSets / addons / apiKeys
The original surface from version 0.1.0 is preserved unchanged:
ob.profileSets.{ list, get, create, update, delete, connectAccount, disconnectAccount }
ob.posts.{ create, raw }
ob.dm.send // legacy one-shot DM (prefer conversations.sendDm)
ob.addons.{ list, get, create, cancel }
ob.apiKeys.{ list, create, revoke }
ob.passthrough.call // raw social-API passthrough by computer idCLI reference
Every library method has a CLI command. Run overblast --help for the
authoritative list. Highlights:
# Conversations & messages
overblast conv list <profileSetId>
overblast conv messages <profileSetId> <convId> --limit 100
overblast conv send <profileSetId> <convId> "Got it — see you Tuesday."
# Webchat
overblast webchat reply <computerId> webchat_abc123 "We open at 9am."
overblast webchat token <computerId>
# Email
overblast email quota --computer <cid>
overblast email send <cid> [email protected] "Quote follow-up" "Hi Jane…" --domain 0-0.chat
overblast email reply <threadId> "Quick clarification on item 2…"
# Calls
overblast call <cid> +15551234567 "Confirm Tuesday's 3pm" --from +15557654321
overblast call list --computer <cid> --status completed
overblast call recording <callId>
overblast call transcript <callId>
# Todos
overblast todos list <cid> # active only
overblast todos list <cid> --status all # incl. archived
overblast todos list <cid> --conversation <convId> # per-conversation
overblast todos create <cid> --title "Send invoice" --conversation <convId>
# Conversation context (memory + todos + recent activity)
overblast context <cid> <convId> --kind social --profile-set <psid> --contact <contactId>
# Webhooks
overblast webhook list <cid>
overblast webhook create <cid> --event message.received --url https://app.example.com/in
overblast webhook delete <cid> <webhookId>Error handling
Every method throws OverblastError on non-2xx:
catch (e) {
if (e instanceof OverblastError) {
e.status // HTTP status
e.message // server-provided "error" string
e.body // full parsed response body (for codes/conflicts/etc.)
}
}Common cases worth special-casing:
| Status | Meaning | Typical body |
|---|---|---|
| 400 | Bad input (e.g. missing computerId, malformed E.164) | { error } |
| 401 | Bad / missing API key | { error } |
| 402 | Out of credits (calls + media gen) | { error, balanceCents, minRequiredCents } |
| 403 | Subscription not active for the workspace | { error } |
| 422 | Destination blocked / too expensive (calls) | { error, reason, twilioUsdPerMin } |
| 429 | Daily email limit exceeded | { error, threadId, ticket } |
| 503 | Backend not configured | { error } |
Wiring it into Claude Code (or any AI agent)
The natural recipe for an agent that needs to talk to external people:
- Subscribe to
message.received(andcall.endedif calling) viawebhooks.create. Verify the signature, hand the payload to the agent. - Read context with
context.forConversation(...)so the agent has contact memory + open todos + recent messages. - Reply through the right channel:
conversations.sendDmfor social DMswebchat.replyfor website chatemail.reply(oremail.createThreadto start one)calls.createto place a call
- Track follow-up with
todos.create({ ..., conversationId })so the work survives across conversations.
A minimal Node webhook receiver:
import { Overblast } from 'overblast';
import express from 'express';
const ob = new Overblast({ apiKey: process.env.OVERBLAST_API_KEY! });
const app = express();
app.post('/inbound', express.json(), async (req, res) => {
const { event, payload } = req.body;
if (event !== 'message.received') return res.json({ ok: true });
const { conversationId, platform, content, contactId, contactName } = payload;
const ctx = await ob.context.forConversation({
computerId: payload.computerId,
conversationId,
contactId,
profileSetId: payload.profileSetId,
kind: platform === 'website' ? 'webchat' : 'social',
});
const reply = await yourAgent({ ctx, incoming: content, contactName });
if (platform === 'website') {
await ob.webchat.reply(payload.computerId, { conversationId, content: reply });
} else {
await ob.conversations.sendDm(payload.profileSetId, conversationId, { text: reply });
}
res.json({ ok: true });
});
app.listen(8080);Claude Code skill
The package ships a self-contained skill at skill/SKILL.md. Install it into
your Claude Code config so the agent picks the right tool for the task:
overblast install-skill # → ~/.claude/skills/overblast/SKILL.md
overblast install-skill --project # → ./.claude/skills/overblast/SKILL.md
overblast install-skill --dest <path> # → <path>/overblast/SKILL.md
overblast install-skill --name custom-name # rename the skill folder
overblast install-skill --force # overwrite existingThe skill file teaches Claude when to reach for the SDK/CLI, lists the decision matrix (which method handles which conversational channel), and encodes the platform's hard rules (E.164 only, no PII in prompts, etc.).
If you publish a derivative package, you can also vendor skill/SKILL.md
directly into your repo — it has no runtime dependencies.
Building from source
cd packages/overblast
npm install
npm run build # tsup → dist/{index,cli}.{js,d.ts}
npm run dev # watch mode
npm run typecheck # tsc --noEmitThe package ships ESM only. The compiled CLI is dist/cli.js and the bin
entry overblast points at it.
Testing
Tests hit the real Overblast backend — no mocks. A flag prevents real side-effecting operations (placing actual calls, sending real emails, creating webhooks) from running unless you opt in.
# Read-only suite — never sends a real message, places a real call, etc.
OVERBLAST_API_KEY=ob_test_... npm test
# Full suite — opts into side-effecting tests. Each side-effecting op is
# individually gated on the env vars it needs.
OVERBLAST_API_KEY=ob_test_... \
OVERBLAST_TEST_ALLOW_SIDE_EFFECTS=1 \
OVERBLAST_TEST_FROM_PHONE=+15551110000 \
OVERBLAST_TEST_TO_PHONE=+15551112222 \
[email protected] \
OVERBLAST_TEST_WEBHOOK_URL=https://webhook.site/your-uuid \
npm testWithout OVERBLAST_API_KEY, the suite skips itself cleanly so CI without
secrets stays green.
Recognized test env vars:
| Variable | Effect |
|---|---|
| OVERBLAST_API_KEY | Required to run any test. |
| OVERBLAST_BASE_URL | Override base URL (default: production). |
| OVERBLAST_TEST_COMPUTER_ID | Workspace under test (auto-detected if omitted). |
| OVERBLAST_TEST_PROFILE_SET_ID | Profile set used by conversation/contact tests (auto-detected if omitted). |
| OVERBLAST_TEST_ALLOW_SIDE_EFFECTS=1 | Master switch for write tests. Default OFF. |
| OVERBLAST_TEST_FROM_PHONE / OVERBLAST_TEST_TO_PHONE | Caller-id + destination for the call test. |
| OVERBLAST_TEST_TO_EMAIL / OVERBLAST_TEST_DOMAIN | Destination + agent domain for the email test. |
| OVERBLAST_TEST_WEBHOOK_URL | HTTPS endpoint for the webhook round-trip test. |
CI
.github/workflows/overblast.yml runs build + typecheck on every push
and PR (no creds needed), and the read-only test suite when the
OVERBLAST_API_KEY secret is configured. Side-effecting tests do not run
in CI — they require an explicit OVERBLAST_TEST_ALLOW_SIDE_EFFECTS=1
which the workflow does not set.
License
MIT.
