Skip to main content
Every change to the public API contract is listed here: new endpoints and fields on the day they ship, and the rare in-place correction made before a field has real usage. Build your integration to ignore fields it does not know, and check this page when something changes.
Capacity limit
  • New 503 server_busy: when one key has too many requests running at once, or the API is at capacity, a request returns 503 with Retry-After: 1. It did not run and does not count against your rate limit; retry it. Sending up to 100 recipients per template send, instead of one call per recipient, avoids it. See rate limits.
Webhooks
  • conversation.assigned carries more: the teammate’s name and email (assignee), how it was assigned (strategy, assigned_by, self_assigned), and a url to the conversation, so a no-code tool can post a useful alert without calling the API. See the event catalog.
WhatsApp forms
  • New webhook event whatsapp_flow.completed: fires when a customer submits a WhatsApp form, with the answers and what Ciarem saved to the contact. See the event catalog.
Webhooks
Ciarem can now call your server when something changes, so you no longer have to poll. Start with the webhooks guide.
  • Webhook endpoints: register up to 10 HTTPS URLs per organization and choose which events each one receives (/v1/webhook-endpoints: list, create, read, update, delete). Also available to admins in the dashboard under Settings → Webhooks.
  • Ten event types: contact.created, contact.updated, contact.deleted, contact.merged, contact.funnel_stage.changed, contact.owner.changed, conversation.created, conversation.assigned, conversation.closed, and messages.inbound. Contact events carry the full contact. See the event catalog.
  • Signed requests: every request carries a Ciarem-Signature header, an HMAC-SHA256 made with the endpoint’s whsec_ signing secret. See Verify signatures.
  • Retries and a delivery log: a failed delivery is retried for up to 3 days, and every delivery of the last 30 days can be read with GET /v1/webhook-endpoints/{id}/deliveries and sent again with POST /v1/webhook-deliveries/{id}/redeliver. See Deliveries and retries.
  • Test events: POST /v1/webhook-endpoints/{id}/test sends one event right now and returns what your server answered. GET /v1/webhook-event-samples returns the sample body of every event type.
  • Included in the same plans as the API: Growth, Scale, and the free trial.
WhatsApp marketing opt-out
  • Contacts gain marketing_opt_out (boolean, read-only): true when the contact opted out of WhatsApp marketing. It cannot be set through the API. See WhatsApp marketing opt-out.
  • POST /v1/templates/{id}/send: a marketing template is not sent to a recipient whose marketing_opt_out is true. The request is still accepted and the other recipients are sent; the opted-out recipient is not sent and not charged. Utility and authentication templates are unaffected. Read marketing_opt_out on the contact to leave those recipients out up front.
The API comes to the Growth plan
  • The API is now included in the Growth plan, not only Scale. Growth gets every endpoint on a budget of 10 requests/second; Scale stays at 20 requests/second and the trial at 5 requests/second. Keys created during a trial that continued on Growth work again with no change.
  • Breaking: scale_plan_required is now plan_upgrade_required. The 403 detail for a live plan without the API (Solo) was renamed, since Scale is no longer the only plan that includes it. If your integration matches on the old string, update it. See Authentication.
Contact date filters take absolute dates
  • GET /v1/contacts: property_filter no longer accepts relative date presets. A DATE clause takes a YYYY-MM-DD date, for example custom_birthday:gte:2026-09-01. A preset: value such as preset:1w now returns 400 with invalid_property_filter. Presets were never documented: they resolve in the timezone of whoever is viewing the dashboard, which an integration cannot control. Compute the dates on your side instead.
  • tz is now documented on GET /v1/contacts: the IANA timezone created_from / created_to are read in. It defaults to the organization’s timezone, then UTC.
Free-trial access, per-second limits, and 403s that say what to do
  • The API is open during the free trial. A trial organization gets every endpoint, on a smaller budget, so an integration can be built and tested before paying.
  • Rate limits are now per second: 20 requests/second on Scale, 5 requests/second during the trial, shared across the organization’s keys. The X-RateLimit-* headers are unchanged; Retry-After on a 429 is now always 1.
  • GET /v1/me gains trial (boolean), which is true while the organization is on its free trial. plan now reports the real plan code rather than always "scale".
  • Clearer 403s. scale_plan_required now means only that the organization is on a live plan below Scale and needs to upgrade. Two new details cover the rest: trial_expired (the trial ended without a payment method) and subscription_required (canceled, or suspended for non-payment). See Authentication.
WhatsApp templates, sends, and broadcasts
The API can now send.
  • WhatsApp templates: list, read, create, delete (/v1/templates). Creating a template also submits it to Meta for approval in the same call, so it comes back PENDING; poll it until Meta flips it to APPROVED or REJECTED.
  • GET /v1/templates/{id}/send-requirements: what a template needs filled before it can be sent. It lists the variable tokens, which of them resolve from the contact on their own, catalog slots, dynamic URL buttons, media surfaces, and a reason when a template can never be sent at all. Read this before your first send rather than discovering it through 422s.
  • POST /v1/templates/{id}/send: up to 100 recipients in one call, each addressed by contact_id or phone and carrying its own variables, url_suffixes, coupon_code, lto_expiration and media. recipients takes a single object or an array, so sending to one person needs no wrapping. Media headers take a public URL (header_media_url / card_media_urls), fetched server-side. Returns 202 and the broadcast it created.
    • A phone that matches no contact creates one, so a send can grow your CRM.
    • Send Idempotency-Key and a retry is safe: the same key returns the original broadcast for 24 hours instead of sending again.
    • The request is refused whole (nothing queued, nothing charged) if a variable is missing, a key is one the template does not use, a media URL cannot be fetched, or the batch exceeds what is left of WhatsApp’s rolling 24-hour messaging limit.
  • Broadcasts: GET /v1/broadcasts and GET /v1/broadcasts/{id} for progress (sent / failed / pending always sum to requested), GET /v1/broadcasts/{id}/recipients for per-recipient outcomes, and POST /v1/broadcasts/{id}/cancel to abandon the un-sent remainder. Messages already accepted by WhatsApp cannot be recalled.
  • GET /v1/channels/whatsapp/phones: the connected numbers a send can go out from, so channel_id is discoverable. Optional when your WhatsApp account has exactly one number; required when it has more.
v1 launch
The first public surface of the Ciarem API:
  • Contacts: full CRUD (/v1/contacts).
  • CRM metadata: properties and funnel stages, full CRUD (/v1/properties, /v1/funnel-stages).
  • Conversations: read-only history (/v1/conversations), each message carrying a sender of contact, agent, ai, or system.
  • /v1/me: organization identity, plan, timezone, and language.
  • Organization-bound oak_ API keys, 60 requests/minute per organization.