API Reference
A simple REST API to read your CRM and conversations, inject messages from any source, pull metrics, and draft AI replies from your knowledge base. JSON in, JSON out.
OpenAPI 3.1 spec — import into Postman / Insomnia →Authentication
Every request is authenticated with your workspace API key as a Bearer token. Find it in Dashboard → Contacts → Connect your app. Keep it secret — it grants full access to your workspace data.
Authorization: Bearer od_sk_your_workspace_key
Content-Type: application/json
Base URL: https://onebubbles.com/api/v1JavaScript SDK
A tiny wrapper for the browser and Node 18+. Or just call the REST endpoints below directly.
<script src="https://onebubbles.com/onebubbles.js"></script>
<script>
const ob = Onebubbles.createClient("od_sk_...");
await ob.contacts.upsert({ email: "jane@acme.com", name: "Jane" });
await ob.messages.send({ externalId: "u-1", message: "Hi there" });
const { conversations } = await ob.conversations.list({ email: "jane@acme.com" });
const { reply } = await ob.ai.reply("What are your hours?");
const stats = await ob.stats();
</script>
// Node 18+ / bundlers:
const Onebubbles = require("onebubbles.com/onebubbles.js"); // or a copy
const ob = Onebubbles.createClient(process.env.ONEBUBBLES_KEY);Endpoints
/api/v1/contactsCreate or update a contact
Upsert a CRM contact by email. Returns the contact id and whether it was newly created.
email- — required — the contact's email (unique key)
name- — optional — display name
phone- — optional
tags- — optional — array of strings
curl -X POST https://onebubbles.com/api/v1/contacts \
-H "Authorization: Bearer od_sk_..." \
-H "Content-Type: application/json" \
-d '{
"email": "jane@acme.com",
"name": "Jane Doe",
"tags": ["lead"]
}'{
"ok": true,
"contactId": "e3a7…",
"created": true
}/api/v1/contactsList contacts
List contacts (newest first), or fetch one by email. Filter by tag or lifecycle stage.
email- — optional — return the matching contact
tag- — optional — filter by a tag
lifecycle- — optional — lead | active | customer | churned
limit- — optional — 1–200 (default 50)
curl "https://onebubbles.com/api/v1/contacts?lifecycle=customer&limit=50" \
-H "Authorization: Bearer od_sk_..."{
"contacts": [{
"id": "e3a7…",
"name": "Jane Doe",
"email": "jane@acme.com",
"tags": ["vip"],
"lifecycleStage": "customer",
"company": "Acme",
"blocked": false,
"lastSeenAt": "2026-07-15T…"
}]
}/api/v1/messagesSend an inbound message
Inject a message from any custom source into the inbox as the “api” channel. Runs the full pipeline: contact upsert, auto-assignment, AI auto-tagging, agent push, and webhooks.
message- — required — the message text
externalId- — required (or email) — a stable per-user id in your system
name- — optional
email- — optional
phone- — optional
curl -X POST https://onebubbles.com/api/v1/messages \
-H "Authorization: Bearer od_sk_..." \
-H "Content-Type: application/json" \
-d '{
"externalId": "user-123",
"name": "Jane",
"email": "jane@acme.com",
"message": "My order hasn't arrived"
}'{
"ok": true,
"conversationId": "97…",
"contactId": "e3…",
"messageId": "6e…"
}/api/v1/conversationsRead conversations
List conversations (newest first), optionally by contact — or pass conversationId to get a single conversation with its full message transcript.
conversationId- — optional — return one conversation + transcript
email- — optional — filter to a contact
contactId- — optional — filter to a contact
status- — optional — open | pending | closed
priority- — optional — high | normal
limit- — optional — 1–100 (default 20)
curl "https://onebubbles.com/api/v1/conversations?email=jane@acme.com" \
-H "Authorization: Bearer od_sk_..."{
"conversations": [{
"id": "97…",
"status": "open",
"channel": "web",
"tags": ["refund","billing"],
"priority": "high",
"language": "en",
"lastMessagePreview": "Thanks!",
"rating": null,
"contact": { "name": "Jane", "email": "jane@acme.com" }
}]
}/api/v1/statsWorkspace metrics
Summary metrics for building dashboards: conversation counts by status, new conversations in the last 30 days, contact total, and CSAT.
curl https://onebubbles.com/api/v1/stats \
-H "Authorization: Bearer od_sk_..."{
"conversations": {
"total": 128, "open": 7, "pending": 1,
"closed": 118, "snoozed": 2, "urgent": 3, "last30d": 40
},
"contacts": { "total": 96 },
"csat": { "average": 4.3, "responseRate": 62, "count": 51 }
}/api/v1/ai/replyDraft an AI reply
Given a customer message, returns an AI-drafted reply grounded in your knowledge base, plus an escalate flag when a human should step in. Consumes one AI credit.
message- — required — the customer's message
curl -X POST https://onebubbles.com/api/v1/ai/reply \
-H "Authorization: Bearer od_sk_..." \
-H "Content-Type: application/json" \
-d '{ "message": "What are your opening hours?" }'{
"reply": "We're open Mon–Fri, 9am–6pm…",
"escalate": false
}Webhooks
Subscribe to events in Dashboard → Settings → Webhooks. We POST a signed JSON payload to your URL for each event you pick.
conversation.createdA new conversation started
conversation.assignedA conversation got an owner
conversation.resolvedA conversation was closed
conversation.ratedA visitor submitted a CSAT rating
contact.createdA new contact was added
message.receivedAn inbound message arrived
Verifying signatures
Each delivery includes an X-Onebubbles-Signature header: sha256=<hex>, an HMAC-SHA256 of the raw request body using your webhook's signing secret. Recompute it and compare to reject spoofed requests.
// Node.js
import crypto from "crypto";
function verify(rawBody, header, secret) {
const expected =
"sha256=" + crypto.createHmac("sha256", secret)
.update(rawBody).digest("hex");
return header === expected;
}