Developer API · v1
Build on CAAC Go
Send WhatsApp messages and generate AI replies from your own apps. The API is REST over HTTPS, JSON in and out, authenticated with a workspace API key.
Base URL & authentication
All requests go to the base URL below. Pass your key (created under Settings → API keys) in the Authorization header. Keep it secret — it grants access to your workspace.
Base URL https://caacgo.cresclab.com
Header Authorization: Bearer cwa_your_keyEndpoints
/api/v1/meVerify a key and return the workspace it belongs to.
curl https://caacgo.cresclab.com/api/v1/me \
-H "Authorization: Bearer cwa_your_key"Response
{ "ok": true, "workspace": { "id": "…", "name": "Glow Skin Clinic", "plan": "free" } }/api/v1/messagesSend a WhatsApp text message. Subject to WhatsApp's 24-hour customer-care window and template rules for proactive sends.
curl -X POST https://caacgo.cresclab.com/api/v1/messages \
-H "Authorization: Bearer cwa_your_key" \
-H "Content-Type: application/json" \
-d '{"to":"+5511988887777","text":"Hi! Thanks for reaching out 👋"}'Response
{ "ok": true }/api/v1/ai/replyGenerate an AI reply from your business content. Pass url to read answers from a website, or context with raw text.
curl -X POST https://caacgo.cresclab.com/api/v1/ai/reply \
-H "Authorization: Bearer cwa_your_key" \
-H "Content-Type: application/json" \
-d '{"message":"How much is a haircut?","url":"https://your-site.com"}'Response
{ "reply": "A men's haircut is $30 and takes about 30 minutes — want me to book you in?" }Webhooks
Get notified when things happen in your workspace. Add an endpoint in Settings → Webhooks and we’ll POST a signed JSON body to it when these events fire:
message.received— A visitor sent a message to your agent.conversation.escalated— The AI flagged a conversation for a human to follow up.contact.created— A new contact / lead was captured.lead.captured— The AI saved a visitor as a lead (the money event).appointment.requested— The AI recorded a booking request for your team to confirm.
Delivery
POST https://yourapp.com/webhooks/caac
Content-Type: application/json
X-CAAC-Event: message.received
X-CAAC-Signature: <hex HMAC-SHA256 of the raw body, keyed with your signing secret>
{
"id": "5f1c…",
"event": "message.received",
"createdAt": "2026-06-23T08:00:00.000Z",
"data": {
"conversationId": "…", "contactId": "…",
"channelType": "web", "body": "Hi! Do you ship overseas?",
"contact": { "name": null, "phone": null, "externalId": "…" }
}
}More payloads
// conversation.escalated — AI handed off; open a ticket in your helpdesk.
// Carries the requester identity + recent transcript so you can create the
// ticket straight from this event (contact is null if the visitor gave none).
// contact.metadata holds attributes you passed via the widget identify() API
// (see below) — e.g. the logged-in user's plan / your member id — so you can
// reverse-look-up your own DB on handoff.
{ "event": "conversation.escalated", "data": {
"conversationId": "…", "contactId": "…",
"question": "Can I get a refund on order #1234?",
"contact": {
"name": "Alex Tan", "email": "alex@example.com", "phone": "+6591234567",
"metadata": { "plan": "growth", "userId": "u_123" }
},
"transcript": [
{ "role": "visitor", "text": "Can I get a refund on order #1234?" },
{ "role": "agent", "text": "Let me connect you with the team." }
]
} }
// lead.captured — the money event
{ "event": "lead.captured", "data": {
"conversationId": "…", "contactId": "…",
"name": "Alex Tan", "email": "alex@example.com",
"phone": "+6591234567", "interest": "pricing"
} }
// appointment.requested
{ "event": "appointment.requested", "data": {
"conversationId": "…", "contactId": "…",
"service": "Consultation", "preferredTime": "Fri 3pm",
"name": "Alex Tan", "phone": "+6591234567"
} }Verify the signature (Node)
import crypto from "node:crypto";
const signature = req.headers["x-caac-signature"];
const expected = crypto.createHmac("sha256", WEBHOOK_SIGNING_SECRET)
.update(rawBody) // the exact raw request body string
.digest("hex");
const ok = signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));Respond 2xx to acknowledge. The last delivery status is shown next to each endpoint, and you can send a test event from the Webhooks page.
Pass visitor identity & context
Call caacgo("identify", …) with whatever you know about the visitor. email & name populate the contact; every other field lands in contact.metadata and — this is the powerful part — the AI sees these attributes when it answers. Combine with your agent's custom instructions to adapt by segment: “if plan is trial, mention the upgrade; if cart_items is set, help them check out.” The same fields also arrive on the conversation.escalated webhook, so on handoff you can reverse-look-up your own member DB. Values are asserted by your page — the AI uses them for tailoring only, and you should verify them against your own records before granting anything (signed identity verification is on the roadmap).
<script src="https://caacgo.cresclab.com/widget.js" data-key="wk_xxx"></script>
<script>
// call with anything you know — logged-in identity, funnel stage, cart state:
caacgo("identify", {
email: user.email, // -> contact.email
name: user.fullName, // -> contact.name
plan: user.plan, // -> contact.metadata.plan (visible to the AI)
stage: "trial", // -> contact.metadata.stage (visible to the AI)
userId: user.id // -> contact.metadata.userId
});
</script>Errors
Errors return the matching HTTP status with a JSON body: { "error": "…" }. Each endpoint is rate-limited per key (/me 120, /messages 60, /ai/reply 20 requests per minute) — back off and retry on 429.
| Status | Meaning |
|---|---|
| 400 | Invalid or missing parameters. |
| 401 | Missing or invalid API key. |
| 422 | Could not read the provided URL. |
| 429 | Rate limit exceeded — slow down and retry. |
| 502 | Upstream WhatsApp or AI call failed. |
OpenAPI spec
Browse the full API in the interactive reference, or import the machine-readable spec into Postman, Insomnia or Swagger UI:
Ready to start? Create your API key →