The Dazza REST API
Read conversations and contacts, add Q&As, reply as the team and resolve conversations from your own systems.
The API lets your own code work with Dazza: sync conversations and contacts to your CRM, teach Dazza from your product catalogue, or reply and resolve from another tool. Everything is JSON over HTTPS.
https://app.dazza.io/api/v1
To hear about things as they happen instead of asking, use event webhooks.
Keys
Admins create keys in Settings → Developers → API keys. Make one for each system that uses the API, so you can revoke one without breaking the others.
- A key is shown once, when you create it. Dazza only keeps a fingerprint of it.
- Keys start with
dz_sk_. Keep them on your server, never in a web page or an app. - Revoke stops a key working straight away.
- A workspace can have up to 10 keys.
Send the key as a bearer token:
curl https://app.dazza.io/api/v1/conversations \
-H "Authorization: Bearer dz_sk_…"
Every request is limited to your own workspace. Preview chats from the Agent page are never included.
Limits
Each key can make 120 requests a minute. Every response says where you are:
x-ratelimit-limit: requests allowed a minutex-ratelimit-remaining: requests left this minutex-ratelimit-reset: when the minute starts again, in Unix seconds
Past the limit you get 429 with a retry-after header in seconds.
Errors
Errors use the HTTP status and a JSON body with a code you can check and a message you can show:
{ "error": { "code": "not_found", "message": "No conversation with that id in this workspace." } }
| Status | Means |
|---|---|
| 400 | Something in the request isn’t valid. The message says what. |
| 401 | The key is missing, wrong or revoked. |
| 404 | Nothing with that id in your workspace. |
| 422 | Dazza understood the request but couldn’t do it. |
| 429 | Too many requests this minute. |
| 502 | A reply was saved but the channel didn’t accept it. |
Pagination
Lists return the newest first, 20 at a time. Ask for up to 100 with limit. When there’s more, has_more is true and next_cursor fetches the next page:
{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "MjAyNi0xMC0y…" }
curl "https://app.dazza.io/api/v1/conversations?limit=50&cursor=MjAyNi0xMC0y…" \
-H "Authorization: Bearer dz_sk_…"
Conversations
List conversations
GET /conversations
| Parameter | |
|---|---|
status |
open or resolved |
channel |
web, email, whatsapp, messenger, instagram, telegram, sms, line, viber, slack, teams or discord |
contact_id |
Only this contact’s conversations |
limit, cursor |
See Pagination |
curl "https://app.dazza.io/api/v1/conversations?status=open&channel=email" \
-H "Authorization: Bearer dz_sk_…"
Each conversation looks like this:
{
"object": "conversation",
"id": "cnv_9x2k…",
"channel": "web",
"status": "open",
"with": "team",
"needs_reply": true,
"subject": "Can I change my booking?",
"contact_id": "cnt_4hq1…",
"contact": { "object": "contact", "id": "cnt_4hq1…", "name": "Sam Taylor", "email": "sam@example.com", "phone": null, "attributes": { "plan": "Pro" }, "created_at": "…", "updated_at": "…" },
"verified": { "email": "sam@example.com", "via": "signed" },
"assignee": null,
"handover": { "at": "2026-10-27T10:42:00.000Z", "reason": "customer_request", "reason_label": "Asked for a person", "summary": "Sam wants to move their booking to Friday." },
"tags": ["Bookings"],
"sentiment": "neutral",
"rating": { "value": "good", "comment": null, "rated_at": "…" },
"language": "en",
"page_url": "https://example.com/contact",
"created_at": "2026-10-27T10:40:12.000Z",
"last_message_at": "2026-10-27T10:42:03.000Z",
"resolved_at": null
}
with is dazza while Dazza is answering, and team once it’s handed over or someone took it over. verified is only set when the customer proved who they are; see Verify your customers.
Get a conversation
GET /conversations/{id} returns the conversation with all its messages, oldest first.
curl https://app.dazza.io/api/v1/conversations/cnv_9x2k… \
-H "Authorization: Bearer dz_sk_…"
{
"object": "conversation",
"id": "cnv_9x2k…",
"…": "…",
"messages": [
{ "object": "message", "id": "msg_…", "conversation_id": "cnv_9x2k…", "role": "customer", "text": "Can I change my booking to Friday?", "author_name": null, "sources": [], "action": null, "delivery": null, "rating": null, "created_at": "…" },
{ "object": "message", "id": "msg_…", "conversation_id": "cnv_9x2k…", "role": "dazza", "text": "You can move a booking up to 24 hours before [1].", "author_name": null, "sources": [{ "n": 1, "title": "Bookings", "url": "https://example.com/bookings" }], "action": null, "delivery": null, "rating": "helpful", "created_at": "…" }
]
}
role is customer, dazza, team, note (internal, never seen by the customer), system or action (something Dazza did, with its name and status). delivery is set for email and messaging apps: draft, sent, delivered, failed and so on.
Reply as the team
POST /conversations/{id}/reply
| Field | |
|---|---|
text |
Required. Up to 5,000 characters. |
author_name |
Optional. The name the customer sees, e.g. “Maya Patel”. Their first name shows in the chat and signs emails. Defaults to “Team”. |
The reply goes out on the conversation’s own channel: into the website chat, as an email in the same thread, or on WhatsApp, Messenger and the rest. If Dazza is still answering, the team takes the conversation over first, as Take over does in the inbox, so Dazza and your team never both reply.
curl -X POST https://app.dazza.io/api/v1/conversations/cnv_9x2k…/reply \
-H "Authorization: Bearer dz_sk_…" \
-H "Content-Type: application/json" \
-d '{ "text": "Hi Sam, Friday at 10 is booked for you.", "author_name": "Maya Patel" }'
Returns 201 with the message and the updated conversation. If the channel refused it (for example, WhatsApp’s 24-hour window had passed), you get 502 with the saved message and why.
Resolve a conversation
POST /conversations/{id}/resolve marks it resolved. Resolving one that’s already resolved is fine. Returns the conversation.
curl -X POST https://app.dazza.io/api/v1/conversations/cnv_9x2k…/resolve \
-H "Authorization: Bearer dz_sk_…"
If the customer writes again, it reopens, as it does in the inbox.
Contacts
List contacts
GET /contacts lists customers Dazza knows by email, phone or name, newest first. Visitors who chatted without saying who they are aren’t included.
| Parameter | |
|---|---|
email |
Find one person by email |
limit, cursor |
See Pagination |
curl "https://app.dazza.io/api/v1/contacts?email=sam@example.com" \
-H "Authorization: Bearer dz_sk_…"
attributes holds the details your own sign-in sent about the customer, such as their plan. See Verify your customers.
Get a contact
GET /contacts/{id}
curl https://app.dazza.io/api/v1/contacts/cnt_4hq1… \
-H "Authorization: Bearer dz_sk_…"
Knowledge
Add a Q&A
POST /knowledge/qa
| Field | |
|---|---|
question |
Required. Up to 300 characters. |
answer |
Required. Up to 5,000 characters. |
title |
Optional. What it’s called in Knowledge. Defaults to the question. |
Like Q&As written in the dashboard, it counts as your own words: it ranks first, and wins over a web page that says something different. Dazza can answer from it straight away.
curl -X POST https://app.dazza.io/api/v1/knowledge/qa \
-H "Authorization: Bearer dz_sk_…" \
-H "Content-Type: application/json" \
-d '{ "question": "Do you deliver on Saturdays?", "answer": "Yes, in London. Order by 2pm on Friday." }'
{ "object": "knowledge_source", "id": "src_…", "type": "qa", "title": "Do you deliver on Saturdays?", "question": "…", "answer": "…", "status": "ready", "error": null, "created_at": "…" }
To change or remove a Q&A, use Knowledge in the dashboard.