Skip to content
WACRM.AI
Works today

The WACRM Core API for developers and agents

The WACRM Core API lets a developer or an AI agent read and write contacts, conversations, templates and WhatsApp messages for a WACRM project, call the metered AI endpoints, and check the token wallet. Every request authenticates with a scoped API key, and a send carries its own Idempotency-Key so a retry never happens twice.

By the WACRM team Updated

Production base URL https://api.wacrm.ai/v1 — sandbox https://api-sandbox.wacrm.ai/v1 for testing

Authenticate with an API key (Authorization: Bearer) or a Workspace session (Basic/JWT); scopes are granted per key at mint time

POST /v1/messages, POST /v1/agent-actions and POST .../tasks all require an Idempotency-Key header

Every error is a JSON object: {"error": {"code", "message"}} — never a bare string or a stack trace

A full endpoint reference below is rendered straight from docs/api/openapi-v1.yaml at build time

No interactive console on this page — keys are created and used only from your own Workspace

Auth, scopes and idempotency

Every v1 route checks the credential's scopes before it checks anything else: a key minted without contacts:write, for example, gets 403 insufficient_scope on POST /v1/contacts regardless of which plan the project is on. Most scopes are opt-in at mint time — only a handful of defaults (like templates:read for a store key) are granted automatically, so a key only ever carries the access it was actually given.

A write that should never run twice — sending a message, proposing an agent action, creating a task from a conversation — requires a caller-supplied Idempotency-Key header. Retrying the exact same request with the same key replays the first response verbatim instead of sending or creating anything a second time, which is what lets a flaky network connection retry safely. For POST /v1/messages that replay window is 24 hours; for proposing an agent action or creating a task, the key is unique per project with no expiry.

Huy Nguyen (David), Founder and CEO of Netbase JSC

Talk to an expert

Huy Nguyen (David), Founder & CEO

Ask which endpoint fits your integration, or how scopes and idempotency work.

Endpoint reference

Generated at build time from the same openapi-v1.yaml spec the Core API itself is contract-tested against — every path, method and required scope below comes straight from that file, grouped by its OpenAPI tag.

OpenAPI version: 1.0.0

ServersURL
Productionhttps://api.wacrm.ai/v1
Sandbox (test API keys only, no wallet charges)https://api-sandbox.wacrm.ai/v1

Projects

MethodPathSummaryScope(s)
GET /health Liveness/readiness check (public, no auth, no DB write) none (public)
GET /crm-projects List projects owned by the authenticated account projects:read
GET /crm-projects/current Resolve the project for the current credential (store API key, Wix app instance, etc.) projects:read
GET /crm-projects/{project} Get a project by id projects:read
GET /crm-projects/{project}/plan Current plan, the full plan catalog, and seat/contact usage for a project (screen 21 "Plans & Upgrade") projects:read
GET /crm-projects/{project}/storage-usage Storage quota usage for a project (job m5-storage-backup, M5 R-STO-02) projects:read
GET /crm-projects/{project}/ai-pause Read the project's AI pause switch and auto-send opt-in projects:read
PUT /crm-projects/{project}/ai-pause Pause/resume AI auto-reply and set the auto-send opt-in agent:approve
GET /crm-projects/{project}/export Export this project's own data as NDJSON export:read
POST /crm-projects/{project}/plan/checkout Start a PayPal recurring-subscription checkout for a WACRM plan (SANDBOX ONLY) billing:write
GET /crm-projects/{project}/meta-pages List this project's connected Messenger/Instagram Pages meta_dm:read
POST /crm-projects/{project}/meta-pages Connect a Facebook Page (Messenger) or linked Instagram Professional account meta_dm:write
DELETE /crm-projects/{project}/meta-pages/{metaPage} Disconnect a Messenger/Instagram Page meta_dm:write
GET /crm-projects/{project}/contacts/{contact}/billing-history A contact's payment/billing history, for the Inbox contact panel (R-WRK-04) projects:read
GET /crm-projects/{project}/cost-report Meta WhatsApp cost report (by number/campaign/date range) and a 30-day forecast (job m5-cost-reports, R-WA-09) cost_reports:read
GET /crm-projects/{project}/contacts/{contact}/quotes A contact's quotes ("Deal"/"Quote draft"), for the Sales B2B Chrome edition (job m8-chrome-sales-b2b) quotations:read
GET /crm-projects/{project}/social-comments List this project's Facebook Page / Instagram comments meta_comments:read
POST /crm-projects/{project}/social-comments/{comment}/replies Propose a public reply to a comment (ALWAYS needs human approval) meta_comments:write
POST /crm-projects/{project}/social-comments/{comment}/private-reply Send a one-time private reply to a comment meta_comments:write
POST /crm-projects/{project}/social-comments/{comment}/hide Hide a comment (direct human action) meta_comments:write
DELETE /crm-projects/{project}/social-comments/{comment} Delete a comment (direct human action) meta_comments:write

Auth

MethodPathSummaryScope(s)
POST /auth/extension/sessions Start a device-code login session for the Chrome extension none (public)
GET /auth/extension/sessions/{session_id} Poll a device-code login session none (public)
POST /auth/extension/sessions/{session_id}/approve Approve a pending extension session (called from the logged-in Workspace tab) none (public)

Wallet

MethodPathSummaryScope(s)
GET /token-balance Current token balance and this cycle's usage wallet:read

AI

MethodPathSummaryScope(s)
GET /account/ai-usage Per-AI-action call count and net tokens deducted ai:read
POST /ai/translate Translate text ai:write
POST /ai/detect-language Detect the language of a text ai:read
POST /ai/summarize Summarize a contact's conversation ai:write
POST /ai/suggest-reply Suggest reply drafts for a conversation (never sent automatically) ai:write
POST /ai/product-answer Draft a grounded answer to a product question (never an invented price) ai:write, products:read
POST /ai/classify-message Classify a message's intent and sentiment (job P27-ai-services-batch-a) ai:write
POST /ai/extract-entities Extract structured entities for a kind (order/address/booking/invoice) (job P27-ai-services-batch-a) ai:write
POST /ai/score-lead Score how sales-qualified a contact is, with a suggested next step (job P27-ai-services-batch-b) ai:write
POST /ai/triage-alert Group and rank the priority of a batch of Care alerts (job P27-ai-services-batch-b) ai:write
POST /ai/suggest-next-action Suggest the next best action for a B2B sales deal (job P27-ai-services-batch-b) ai:write
POST /ai/booking-faq Answer a booking FAQ (never an invented price or opening hour) (job m4-booking-ai-receptionist) ai:write
POST /ai/booking-actions Propose a book/reschedule/cancel action (job m4-booking-ai-receptionist) ai:write, bookings:write
POST /ai/booking-actions/{action}/approve Approve a proposed booking action, executing it through the booking core (job m4-booking-ai-receptionist) ai:write, bookings:write
GET /glossary-terms List this project's translation glossary terms (ordered by target_lang, term) ai:read
POST /glossary-terms Add a forced replacement applied to `POST /ai/translate` for a language pair ai:write
DELETE /glossary-terms/{term} Delete a glossary term ai:write
POST /ai/transcribe-voice Transcribe an existing voice-note attachment of this project (job P27-ai-services-batch-c) ai:write
POST /ai/ocr-image Extract text from an existing image attachment of this project (job P27-ai-services-batch-c) ai:write
POST /ai/draft-template Draft a WhatsApp template body from a freeform instruction (job P27-ai-services-template-tools) ai:write
POST /ai/check-template-policy Check draft template content against the brand-safety lint rules (job P27-ai-services-template-tools) ai:read

Products

MethodPathSummaryScope(s)
GET /commerce/products List products (search by name or SKU) products:read
GET /commerce/products/{product} Get a product, with its SKU/price/currency/stock and variants products:read

Orders

MethodPathSummaryScope(s)
GET /commerce/orders List orders (filter by contact phone/email, status, date) orders:read
GET /commerce/orders/{order} Get an order, with its lines (quantity, resolved product, sku, price) orders:read
GET /commerce/orders/{order}/confirmation Order-confirmation and COD two-way confirmation state for one order orders:read
GET /commerce/order-automation Read the project's order-automation settings (new order -> WhatsApp utility template, COD confirm) orders:read
PUT /commerce/order-automation Update the project's order-automation settings orders:write

Contacts

MethodPathSummaryScope(s)
GET /contacts List contacts contacts:read
POST /contacts Create a contact contacts:write
GET /contacts/{contact} Get a contact contacts:read
PATCH /contacts/{contact} Update a contact contacts:write
DELETE /contacts/{contact} Erase a contact on request (hard delete) contacts:write

Audit

MethodPathSummaryScope(s)
GET /audit-logs List this project's activity/audit log (newest first) audit:read

Labels

MethodPathSummaryScope(s)
POST /contacts/{contact}/labels Attach a label to a contact labels:write
DELETE /contacts/{contact}/labels/{label} Remove a label from a contact labels:write
GET /labels List labels labels:read
POST /labels Create a label labels:write
DELETE /labels/{label} Delete a label labels:write

Notes

MethodPathSummaryScope(s)
GET /contacts/{contact}/notes List notes on a contact notes:read
POST /contacts/{contact}/notes Add a note to a contact notes:write

Tickets

MethodPathSummaryScope(s)
GET /contacts/{contact}/tickets List tickets on a contact tickets:read
POST /contacts/{contact}/tickets Create a ticket on a contact tickets:write
PATCH /tickets/{ticket} Update a ticket (e.g. change status) tickets:write

Templates

MethodPathSummaryScope(s)
GET /message-templates List quick replies / WhatsApp message templates templates:read
POST /message-templates Create a template templates:write
PATCH /message-templates/{template} Update a template templates:write

Messages

MethodPathSummaryScope(s)
GET /contacts/{contact}/messages Read a contact's WhatsApp conversation (watermark pagination) contacts:read
POST /messages Send a WhatsApp message (text or template) messages:send

Conversations

MethodPathSummaryScope(s)
GET /conversations List conversations (Workspace Inbox) contacts:read

MCP

MethodPathSummaryScope(s)
POST /mcp/actions/authorize Authorize one MCP tool call before `apps/mcp` invokes the tool's own endpoint (job P27-mcp-metering) none (public)

Channels

MethodPathSummaryScope(s)
POST /channels/whatsapp/connect-sessions Start a WhatsApp Embedded Signup connect session channels:write
POST /channels/whatsapp/connect-sessions/{session}/complete Complete a connect session (code -> token, debug_token-verified before trusting waba_id/phone_number_id) channels:write
POST /channels/{channel}/activate Activate a connected number (subscribed_apps) — connected -> active channels:write
GET /channels List this project's connected channels channels:read

Export

MethodPathSummaryScope(s)
GET /export/conversations WorkChat-compat alias of GET /conversations (read-only, same scope and shape) contacts:read
GET /export/contacts WorkChat-compat alias of GET /contacts (read-only, same scope and shape) contacts:read
GET /export/messages WorkChat-compat alias of GET /contacts/{contact}/messages (contact_id moved to query — see docs/api/README.md) contacts:read

Webhooks

MethodPathSummaryScope(s)
GET /webhook-endpoints List this project's outbound webhook endpoints (secret never included) wa_webhooks:read
POST /webhook-endpoints Create a webhook endpoint — the secret is returned once, in this response only wa_webhooks:write
DELETE /webhook-endpoints/{endpoint} Delete a webhook endpoint wa_webhooks:write

Broadcasts

MethodPathSummaryScope(s)
GET /segments List this project's saved audience segments broadcasts:read
POST /segments Create a saved audience segment broadcasts:write
GET /contacts/{contact}/consent Read a contact's current WhatsApp consent status contacts:read
POST /contacts/{contact}/consent Record a contact's WhatsApp consent decision (upserts the current row) consent:write
POST /broadcasts Create a draft broadcast (template + segment, not started) broadcasts:write
GET /broadcasts/{broadcast} Read a broadcast's status and counts broadcasts:read
POST /broadcasts/{broadcast}/start Start (or continue pumping) a broadcast — draft/paused/running -> running broadcasts:write
POST /broadcasts/{broadcast}/pause Pause a running broadcast broadcasts:write

Work

MethodPathSummaryScope(s)
POST /conversations/{conversation}/tasks Create a task from a conversation work:write
GET /conversations/{conversation}/tasks List tasks created from a conversation work:read
POST /work/callbacks Inbound task status update from the Work side none (public)

Agent

MethodPathSummaryScope(s)
GET /agent-actions List this project's agent actions agent:propose
POST /agent-actions Propose an agent action (auto-executes when the policy engine decides low risk) agent:propose
POST /agent-actions/{action}/approve Approve a proposed action, executing it through the guarded services agent:approve
POST /agent-actions/{action}/reject Reject a proposed action — it is never executed agent:approve

Relay

MethodPathSummaryScope(s)
POST /webhooks/meta/relay Inbound WhatsApp traffic forwarded by the path-B relay (internal, not a customer-facing resource) none (public)

Bookings

MethodPathSummaryScope(s)
GET /crm-projects/{project}/booking-services List this project's bookable services bookings:read
POST /crm-projects/{project}/booking-services Create a bookable service bookings:write
PATCH /crm-projects/{project}/booking-services/{service} Update a bookable service bookings:write
GET /crm-projects/{project}/availability Derived free slots for a service on one calendar date bookings:read
GET /crm-projects/{project}/bookings List this project's bookings bookings:read
POST /crm-projects/{project}/bookings Book a slot bookings:write
PATCH /crm-projects/{project}/bookings/{booking} Reschedule a booking (moves it, never creates a second row) bookings:write
POST /crm-projects/{project}/bookings/{booking}/cancel Cancel a booking (sets status + cancelled_at, keeps the row) bookings:write
GET /public/store/{slug}/booking-services Public, token-free list of a project's bookable services (WACRM-hosted booking page) none (public)
GET /public/store/{slug}/availability Public, token-free derived free slots for one service/date (WACRM-hosted booking page) none (public)
POST /public/store/{slug}/bookings Public, token-free booking create (WACRM-hosted booking page) none (public)

Client portal

MethodPathSummaryScope(s)
POST /crm-projects/{project}/contacts/{contact}/client-portal-links Mint a client portal link for a contact client_portal:write
POST /crm-projects/{project}/client-portal-links/{link}/revoke Revoke a client portal link (one-way; mint a new one if needed) client_portal:write
GET /client-portal/{token} Public, token-guarded read of one contact's own tickets + bookings none (public)

Care

MethodPathSummaryScope(s)
POST /care/alerts Post a keyed Care alert, routed to the project's recipient care:alerts:write
GET /care/alerts/{alert}/ack/{token} Public, token-guarded ack of a Care alert — stops further escalation none (public)
POST /care/alerts/{alert}/ack/{token} Same handler as GET — ack a Care alert via an explicit POST none (public)

Error shape

Every non-2xx response is a JSON object with the same shape:

{ "error": { "code": "insufficient_scope", "message": "human-readable reason" } }
StatusMeaning
400Validation failed
401Missing or invalid credential
402Token wallet balance too low for an AI call, or a plan limit (contacts/channels/seats) is used up
403Credential valid but missing the required scope
404Not found, or not owned by this project — the two are never distinguished
409A conflicting state, e.g. a text send outside the 24h customer-service window
422Semantically invalid, e.g. a template that is not yet approved
429Rate limited

Frequently asked questions

Do I need a special plan to call the Core API?

Any WACRM project can mint an API key and call the endpoints its key's scopes allow. AI endpoints are metered against your project's token wallet, same as using AI assist in the Workspace inbox.

What happens if I retry a request?

Endpoints that change state the most (sending a message, proposing an agent action, creating a task from a conversation) require an Idempotency-Key header. A retry with the same key replays the original response instead of repeating the action — for sending a message that replay window is 24 hours; for an agent action or a task the key never expires.

Is there a sandbox I can test against?

Yes — api-sandbox.wacrm.ai/v1 is the sandbox base URL: try your calls there before pointing your integration at production.

Where do I create and manage API keys?

From your WACRM Workspace, under Developer / API & MCP. Each key is minted with only the scopes you choose — nothing is granted by default beyond what config/api_keys.php lists as a default scope for that key kind.

Can I call the API from an AI agent?

Yes — any scoped API key works the same way for a script, a backend integration, or an agent. See the wacrm-mcp page for a ready-made MCP server that wraps five of these calls as agent tools.

Start building on the WACRM Core API

Request early access to get a Workspace and mint your first API key.