Build on your support inbox.
A REST API for conversations, contacts, tickets and knowledge, signed webhooks for every important moment, and identity verification for the customers who are signed in to your website.
Authentication
Create a key in Settings → Developers → API keys and send it as a bearer token from your server. Keys are shown once and only a hash is stored. A key reaches one workspace, the websites you pick, and the areas you allow, and it acts as the teammate who made it, never above their role.
| Scope | Lets the key |
|---|---|
inbox:readinbox:write | Conversations, their messages, and tickets. Write: Reply, close, reopen and assign conversations; create and update tickets. |
people:readpeople:write | Contacts and their custom attributes. Write: Create, upsert and update contacts. |
knowledge:readknowledge:write | Q&A snippets. Write: Create, change and delete snippets (administrator keys). |
Write includes read. The same keys also work with Chatrevia’s MCP server for AI tools, where more areas are available.
curl https://www.chatrevia.com/api/v1/me \
-H "Authorization: Bearer crv_sk_…"Responses & errors
Every response is JSON. One object comes as { data }, a list as { data, has_more, next_cursor }. Times are ISO 8601 in UTC. Each response carries an X-Request-Id.
| HTTP | error.type |
|---|---|
| 400 | invalid_request |
| 401 | authentication_required |
| 403 | permission_denied |
| 403 | plan_required |
| 404 | not_found |
| 405 | method_not_allowed |
| 409 | conflict |
| 422 | idempotency_key_reused |
| 429 | rate_limited |
| 500 | server_error |
| 503 | unavailable |
{
"error": {
"type": "permission_denied",
"message": "This key has no inbox:write access. Create a key with it in Settings → Developers.",
"request_id": "req_5f0c2b7e9a1d4c3b8e6f2a10"
}
}Pagination
Lists are newest first and use cursors, so records never repeat or go missing while you page. Pass limit (25 by default, up to 100) and the next_cursor of the previous page as cursor until has_more is false. Add updated_after to sync only what changed.
curl "https://www.chatrevia.com/api/v1/conversations?limit=50&cursor=WyIyMDI2LTEw…" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"Idempotency & rate limits
Send an Idempotency-Key header with any POST. If the request is retried with the same key and body within 24 hours, you get the first response back (marked Idempotent-Replayed: true) and nothing happens twice. The same key with a different body is refused with idempotency_key_reused.
Each key can make 120 requests a minute. Every response has X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; past the limit you get 429 with Retry-After.
Conversations
List conversations
GET/api/v1/conversationsinbox:read
Conversations in which the visitor has written, newest first. Previews and test chats are excluded.
website_iduuid- Only this website. Default: every website the key can use
status"open" | "needs_follow_up" | "closed"channel"web" | "whatsapp" | "messenger" | "instagram" | "email" | "voice"assignee_idstring- A teammate's user ID
emailstring- The visitor's email
updated_afterISO 8601 time- Only records updated after this time (ISO 8601)
created_afterISO 8601 time- Only records created after this time (ISO 8601)
limitinteger- Results per page, 1 to 100 (default 25)
cursorstring- next_cursor from the previous page
curl "https://www.chatrevia.com/api/v1/conversations?limit=10" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": [
{
"id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"object": "conversation",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"status": "open",
"channel": "web",
"visitor": {
"name": "Maya Chen",
"email": "maya.chen@example.com",
"user_id": "cus_48213",
"verified": true
},
"contact_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"assignee": null,
"taken_over": false,
"priority": "normal",
"tags": [
"orders"
],
"summary": "Where is my order #4417?",
"handoff_requested_at": null,
"snoozed_until": null,
"csat": null,
"last_visitor_message_at": "2026-10-04T18:21:07.000Z",
"closed_at": null,
"created_at": "2026-10-04T18:20:51.000Z",
"updated_at": "2026-10-04T18:21:07.000Z"
}
],
"has_more": true,
"next_cursor": "WyIyMDI2LTEwLTA0IDE4OjIwOjUxLjAwMCIsIjhkMGM1ZjhlIl0"
}Get a conversation
GET/api/v1/conversations/{id}inbox:read
curl "https://www.chatrevia.com/api/v1/conversations/8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": {
"id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"object": "conversation",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"status": "open",
"channel": "web",
"visitor": {
"name": "Maya Chen",
"email": "maya.chen@example.com",
"user_id": "cus_48213",
"verified": true
},
"contact_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"assignee": null,
"taken_over": false,
"priority": "normal",
"tags": [
"orders"
],
"summary": "Where is my order #4417?",
"handoff_requested_at": null,
"snoozed_until": null,
"csat": null,
"last_visitor_message_at": "2026-10-04T18:21:07.000Z",
"closed_at": null,
"created_at": "2026-10-04T18:20:51.000Z",
"updated_at": "2026-10-04T18:21:07.000Z"
}
}List a conversation's messages
GET/api/v1/conversations/{id}/messagesinbox:read
Oldest first. Includes visitor, AI, teammate and system messages (such as “Maya joined the chat”). Internal notes are not messages.
limitinteger- Results per page, 1 to 100 (default 25)
cursorstring- next_cursor from the previous page
curl "https://www.chatrevia.com/api/v1/conversations/8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41/messages?limit=10" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": [
{
"id": "6f7e8d9c-0b1a-4c2d-9e3f-4a5b6c7d8e9f",
"object": "message",
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"author": {
"type": "visitor",
"name": null
},
"text": "Hi! Where is my order #4417?",
"attachments": [],
"channel": "web",
"created_at": "2026-10-04T18:21:07.000Z"
}
],
"has_more": true,
"next_cursor": "WyIyMDI2LTEwLTA0IDE4OjIwOjUxLjAwMCIsIjhkMGM1ZjhlIl0"
}Close a conversation
POST/api/v1/conversations/{id}/closeinbox:write
reason"answered" | "fixed" | "feature_request" | "duplicate" | "no_response" | "spam" | "other"- Why it was resolved
notestring
curl -X POST "https://www.chatrevia.com/api/v1/conversations/8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41/close" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"reason": "answered"
}'{
"data": {
"id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"object": "conversation",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"status": "open",
"channel": "web",
"visitor": {
"name": "Maya Chen",
"email": "maya.chen@example.com",
"user_id": "cus_48213",
"verified": true
},
"contact_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"assignee": null,
"taken_over": false,
"priority": "normal",
"tags": [
"orders"
],
"summary": "Where is my order #4417?",
"handoff_requested_at": null,
"snoozed_until": null,
"csat": null,
"last_visitor_message_at": "2026-10-04T18:21:07.000Z",
"closed_at": null,
"created_at": "2026-10-04T18:20:51.000Z",
"updated_at": "2026-10-04T18:21:07.000Z"
}
}Reopen a conversation
POST/api/v1/conversations/{id}/reopeninbox:write
curl -X POST "https://www.chatrevia.com/api/v1/conversations/8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41/reopen" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"{
"data": {
"id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"object": "conversation",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"status": "open",
"channel": "web",
"visitor": {
"name": "Maya Chen",
"email": "maya.chen@example.com",
"user_id": "cus_48213",
"verified": true
},
"contact_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"assignee": null,
"taken_over": false,
"priority": "normal",
"tags": [
"orders"
],
"summary": "Where is my order #4417?",
"handoff_requested_at": null,
"snoozed_until": null,
"csat": null,
"last_visitor_message_at": "2026-10-04T18:21:07.000Z",
"closed_at": null,
"created_at": "2026-10-04T18:20:51.000Z",
"updated_at": "2026-10-04T18:21:07.000Z"
}
}Assign or unassign a conversation
POST/api/v1/conversations/{id}/assigninbox:write
assignee_idstring | nullrequired- A teammate's user ID, or null to unassign
curl -X POST "https://www.chatrevia.com/api/v1/conversations/8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41/assign" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"assignee_id": "usr_nora"
}'{
"data": {
"id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"object": "conversation",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"status": "open",
"channel": "web",
"visitor": {
"name": "Maya Chen",
"email": "maya.chen@example.com",
"user_id": "cus_48213",
"verified": true
},
"contact_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"assignee": null,
"taken_over": false,
"priority": "normal",
"tags": [
"orders"
],
"summary": "Where is my order #4417?",
"handoff_requested_at": null,
"snoozed_until": null,
"csat": null,
"last_visitor_message_at": "2026-10-04T18:21:07.000Z",
"closed_at": null,
"created_at": "2026-10-04T18:20:51.000Z",
"updated_at": "2026-10-04T18:21:07.000Z"
}
}Contacts
List contacts
GET/api/v1/contactspeople:read
People in the workspace, newest first.
website_iduuid- Only this website. Default: every website the key can use
emailstringexternal_idstring- Your own user ID
updated_afterISO 8601 time- Only records updated after this time (ISO 8601)
limitinteger- Results per page, 1 to 100 (default 25)
cursorstring- next_cursor from the previous page
curl "https://www.chatrevia.com/api/v1/contacts?limit=10" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": [
{
"id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"object": "contact",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"external_id": "cus_48213",
"name": "Maya Chen",
"email": "maya.chen@example.com",
"phone": null,
"company": null,
"job_title": null,
"stage": "New",
"tags": [],
"score": null,
"attributes": {
"plan": "Barista Club",
"lifetime_orders": 7
},
"verified": true,
"verified_at": "2026-10-04T18:20:52.000Z",
"source": "identify",
"conversation_id": null,
"created_at": "2026-09-12T09:14:03.000Z",
"updated_at": "2026-10-04T18:20:52.000Z"
}
],
"has_more": true,
"next_cursor": "WyIyMDI2LTEwLTA0IDE4OjIwOjUxLjAwMCIsIjhkMGM1ZjhlIl0"
}Get a contact
GET/api/v1/contacts/{id}people:read
curl "https://www.chatrevia.com/api/v1/contacts/c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": {
"id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"object": "contact",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"external_id": "cus_48213",
"name": "Maya Chen",
"email": "maya.chen@example.com",
"phone": null,
"company": null,
"job_title": null,
"stage": "New",
"tags": [],
"score": null,
"attributes": {
"plan": "Barista Club",
"lifetime_orders": 7
},
"verified": true,
"verified_at": "2026-10-04T18:20:52.000Z",
"source": "identify",
"conversation_id": null,
"created_at": "2026-09-12T09:14:03.000Z",
"updated_at": "2026-10-04T18:20:52.000Z"
}
}Create or update a contact
POST/api/v1/contactspeople:write
Upserts by external_id (your own user ID), else by email. Returns 201 when a contact was created and 200 when one was updated. Custom attributes are merged.
website_iduuid- Required when the key can use several websites
external_idstringnamestring | nullemailstring | nullphonestring | nullcompanystring | nulljob_titlestring | nullstage"New" | "Qualified" | "Contacted" | "Won" | "Lost"tagsarray of stringattributesobject- Custom attributes to merge: string, number or boolean values; null removes one
curl -X POST "https://www.chatrevia.com/api/v1/contacts" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"external_id": "cus_48213",
"email": "maya.chen@example.com",
"name": "Maya Chen",
"attributes": {
"plan": "Barista Club",
"lifetime_orders": 7
}
}'{
"data": {
"id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"object": "contact",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"external_id": "cus_48213",
"name": "Maya Chen",
"email": "maya.chen@example.com",
"phone": null,
"company": null,
"job_title": null,
"stage": "New",
"tags": [],
"score": null,
"attributes": {
"plan": "Barista Club",
"lifetime_orders": 7
},
"verified": true,
"verified_at": "2026-10-04T18:20:52.000Z",
"source": "identify",
"conversation_id": null,
"created_at": "2026-09-12T09:14:03.000Z",
"updated_at": "2026-10-04T18:20:52.000Z"
}
}Update a contact
PATCH/api/v1/contacts/{id}people:write
Changes only the fields you send. Custom attributes are merged (null removes one). Changes appear in the person's activity.
external_idstringnamestring | nullemailstring | nullphonestring | nullcompanystring | nulljob_titlestring | nullstage"New" | "Qualified" | "Contacted" | "Won" | "Lost"tagsarray of stringattributesobject- Custom attributes to merge: string, number or boolean values; null removes one
curl -X PATCH "https://www.chatrevia.com/api/v1/contacts/c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"stage": "Qualified",
"attributes": {
"vip": true
}
}'{
"data": {
"id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"object": "contact",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"external_id": "cus_48213",
"name": "Maya Chen",
"email": "maya.chen@example.com",
"phone": null,
"company": null,
"job_title": null,
"stage": "New",
"tags": [],
"score": null,
"attributes": {
"plan": "Barista Club",
"lifetime_orders": 7
},
"verified": true,
"verified_at": "2026-10-04T18:20:52.000Z",
"source": "identify",
"conversation_id": null,
"created_at": "2026-09-12T09:14:03.000Z",
"updated_at": "2026-10-04T18:20:52.000Z"
}
}Tickets
List tickets
GET/api/v1/ticketsinbox:read
Newest first.
website_iduuid- Only this website. Default: every website the key can use
status"submitted" | "in_progress" | "waiting" | "resolved"conversation_iduuidupdated_afterISO 8601 time- Only records updated after this time (ISO 8601)
limitinteger- Results per page, 1 to 100 (default 25)
cursorstring- next_cursor from the previous page
curl "https://www.chatrevia.com/api/v1/tickets?limit=10" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": [
{
"id": "0f1e2d3c-4b5a-4968-8776-655443322110",
"object": "ticket",
"number": 1042,
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"title": "Replace damaged grinder burr",
"description": "Customer received a cracked burr with order #4417.",
"type": "customer",
"status": "in_progress",
"priority": "high",
"assignee": {
"id": "usr_nora",
"name": "Nora Patel"
},
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"created_by": "Nora Patel",
"created_at": "2026-10-04T18:25:00.000Z",
"updated_at": "2026-10-04T18:40:12.000Z",
"resolved_at": null
}
],
"has_more": true,
"next_cursor": "WyIyMDI2LTEwLTA0IDE4OjIwOjUxLjAwMCIsIjhkMGM1ZjhlIl0"
}Get a ticket
GET/api/v1/tickets/{id}inbox:read
curl "https://www.chatrevia.com/api/v1/tickets/0f1e2d3c-4b5a-4968-8776-655443322110" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": {
"id": "0f1e2d3c-4b5a-4968-8776-655443322110",
"object": "ticket",
"number": 1042,
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"title": "Replace damaged grinder burr",
"description": "Customer received a cracked burr with order #4417.",
"type": "customer",
"status": "in_progress",
"priority": "high",
"assignee": {
"id": "usr_nora",
"name": "Nora Patel"
},
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"created_by": "Nora Patel",
"created_at": "2026-10-04T18:25:00.000Z",
"updated_at": "2026-10-04T18:40:12.000Z",
"resolved_at": null
}
}Create a ticket
POST/api/v1/ticketsinbox:write
A customer ticket linked to a conversation tells the visitor there and keeps them updated.
website_iduuid- Required when the key can use several websites (taken from the conversation when given)
titlestringrequireddescriptionstringtype"customer" | "back_office"priority"low" | "normal" | "high" | "urgent"conversation_iduuidassignee_idstring
curl -X POST "https://www.chatrevia.com/api/v1/tickets" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"title": "Replace damaged grinder burr",
"priority": "high",
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41"
}'{
"data": {
"id": "0f1e2d3c-4b5a-4968-8776-655443322110",
"object": "ticket",
"number": 1042,
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"title": "Replace damaged grinder burr",
"description": "Customer received a cracked burr with order #4417.",
"type": "customer",
"status": "in_progress",
"priority": "high",
"assignee": {
"id": "usr_nora",
"name": "Nora Patel"
},
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"created_by": "Nora Patel",
"created_at": "2026-10-04T18:25:00.000Z",
"updated_at": "2026-10-04T18:40:12.000Z",
"resolved_at": null
}
}Update a ticket
PATCH/api/v1/tickets/{id}inbox:write
Change status, priority, assignee, title or description. Status changes on customer tickets are posted to the linked conversation.
status"submitted" | "in_progress" | "waiting" | "resolved"priority"low" | "normal" | "high" | "urgent"assignee_idstring | nulltitlestringdescriptionstring
curl -X PATCH "https://www.chatrevia.com/api/v1/tickets/0f1e2d3c-4b5a-4968-8776-655443322110" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "in_progress",
"assignee_id": "usr_nora"
}'{
"data": {
"id": "0f1e2d3c-4b5a-4968-8776-655443322110",
"object": "ticket",
"number": 1042,
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"title": "Replace damaged grinder burr",
"description": "Customer received a cracked burr with order #4417.",
"type": "customer",
"status": "in_progress",
"priority": "high",
"assignee": {
"id": "usr_nora",
"name": "Nora Patel"
},
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"created_by": "Nora Patel",
"created_at": "2026-10-04T18:25:00.000Z",
"updated_at": "2026-10-04T18:40:12.000Z",
"resolved_at": null
}
}Knowledge
List Q&A snippets
GET/api/v1/knowledge/snippetsknowledge:read
Written answers the AI agent learns from, newest first.
website_iduuid- Only this website. Default: every website the key can use
status"published" | "draft" | "archived"limitinteger- Results per page, 1 to 100 (default 25)
cursorstring- next_cursor from the previous page
curl "https://www.chatrevia.com/api/v1/knowledge/snippets?limit=10" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": [
{
"id": "4e2d1c0b-9a8f-4e7d-8c6b-5a4f3e2d1c0b",
"object": "snippet",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"question": "Do you ship internationally?",
"answer": "Yes. We ship to the US, Canada, the UK and the EU in 5 to 9 business days.",
"status": "published",
"created_at": "2026-10-04T18:40:00.000Z",
"updated_at": "2026-10-04T18:40:00.000Z"
}
],
"has_more": true,
"next_cursor": "WyIyMDI2LTEwLTA0IDE4OjIwOjUxLjAwMCIsIjhkMGM1ZjhlIl0"
}Create a Q&A snippet
POST/api/v1/knowledge/snippetsknowledge:write
Published snippets are indexed at once and the AI agent can use them in its next answer; drafts wait for review in Knowledge. Needs a key that acts as an administrator.
website_iduuid- Required when the key can use several websites
questionstringrequiredanswerstringrequiredstatus"published" | "draft"
curl -X POST "https://www.chatrevia.com/api/v1/knowledge/snippets" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"question": "Do you ship internationally?",
"answer": "Yes. We ship to the US, Canada, the UK and the EU in 5 to 9 business days."
}'{
"data": {
"id": "4e2d1c0b-9a8f-4e7d-8c6b-5a4f3e2d1c0b",
"object": "snippet",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"question": "Do you ship internationally?",
"answer": "Yes. We ship to the US, Canada, the UK and the EU in 5 to 9 business days.",
"status": "published",
"created_at": "2026-10-04T18:40:00.000Z",
"updated_at": "2026-10-04T18:40:00.000Z"
}
}Update a Q&A snippet
PATCH/api/v1/knowledge/snippets/{id}knowledge:write
Changes only the fields you send; a published snippet stays published unless you set status. The previous text is kept in its version history.
questionstringanswerstringstatus"published" | "draft"
curl -X PATCH "https://www.chatrevia.com/api/v1/knowledge/snippets/4e2d1c0b-9a8f-4e7d-8c6b-5a4f3e2d1c0b" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "published"
}'{
"data": {
"id": "4e2d1c0b-9a8f-4e7d-8c6b-5a4f3e2d1c0b",
"object": "snippet",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"question": "Do you ship internationally?",
"answer": "Yes. We ship to the US, Canada, the UK and the EU in 5 to 9 business days.",
"status": "published",
"created_at": "2026-10-04T18:40:00.000Z",
"updated_at": "2026-10-04T18:40:00.000Z"
}
}Delete a Q&A snippet
DELETE/api/v1/knowledge/snippets/{id}knowledge:write
curl -X DELETE "https://www.chatrevia.com/api/v1/knowledge/snippets/4e2d1c0b-9a8f-4e7d-8c6b-5a4f3e2d1c0b" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": {
"id": "4e2d1c0b-9a8f-4e7d-8c6b-5a4f3e2d1c0b",
"object": "snippet",
"deleted": true
}
}Orders
Record an order
POST/api/v1/ordersorders:write
Reports an order from your backend for revenue attribution: Chatrevia attributes it to the conversation that led to it (the conversation_id you send, the buyer's email or phone, a chat discount code, a product added from chat) within the website's attribution window, and sends order.attributed. Idempotent on order_id: reporting the same order again returns it unchanged (200). It replaces an unattributed copy reported by the purchase snippet. Shopify orders arrive on their own. Needs a plan with commerce features.
website_iduuidorder_idstring | integerrequired- Your order ID; reporting it again changes nothing
namestring- Shown in reports, e.g. #1042
totalnumberrequired- Order total in its currency
subtotalnumbercurrencystringrequireditemsarray of objectdiscount_codesarray of stringemailstring- The buyer's email (attribution by email)
phonestringcustomer_namestringplaced_atISO 8601 time- When it was placed (default: now); up to 400 days ago
conversation_iduuid- The conversation that led to it, when your checkout knows it
curl -X POST "https://www.chatrevia.com/api/v1/orders" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"order_id": "1042",
"total": 46.5,
"currency": "USD",
"email": "maya.chen@example.com",
"items": [
{
"id": "NW-ETH-GUJI-12",
"name": "Ethiopia Guji Natural · 12 oz",
"quantity": 2,
"price": 19
}
],
"discount_codes": [
"NORA-7XK2QP"
]
}'{
"data": {
"id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"object": "order",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"platform": "shopify",
"source": "shopify",
"order_id": "5512044331",
"name": "#1042",
"total": 46.5,
"subtotal": 51.5,
"currency": "USD",
"items": [
{
"id": "NW-ETH-GUJI-12",
"variant_id": "44012345678",
"product_id": "8123456789",
"name": "Ethiopia Guji Natural · 12 oz",
"quantity": 2,
"price": 19
},
{
"id": "NW-FLT-V60",
"variant_id": "44012345990",
"product_id": "8123456990",
"name": "Hario V60 Paper Filters",
"quantity": 1,
"price": 13.5
}
],
"discount_codes": [
"NORA-7XK2QP"
],
"email": "maya.chen@example.com",
"placed_at": "2026-10-04T19:02:44.000Z",
"attribution": {
"type": "direct",
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"contact_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"channel": "web",
"handled_by": "ai",
"reasons": [
"discount",
"conversation"
],
"last_chat_at": "2026-10-04T18:21:09.000Z",
"window_days": 7
},
"created_at": "2026-10-04T19:02:46.000Z"
}
}List orders
GET/api/v1/ordersorders:read
Orders reported by Shopify, the purchase snippet and the API, newest first, with their attribution.
website_iduuid- Only this website. Default: every website the key can use
attribution"direct" | "influenced" | "recovered" | "none" | "any"- any: attributed to a conversation (direct, influenced or recovered from an abandoned cart)
conversation_iduuidplaced_afterISO 8601 time- Only records placed after this time (ISO 8601)
limitinteger- Results per page, 1 to 100 (default 25)
cursorstring- next_cursor from the previous page
curl "https://www.chatrevia.com/api/v1/orders?limit=10" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": [
{
"id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"object": "order",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"platform": "shopify",
"source": "shopify",
"order_id": "5512044331",
"name": "#1042",
"total": 46.5,
"subtotal": 51.5,
"currency": "USD",
"items": [
{
"id": "NW-ETH-GUJI-12",
"variant_id": "44012345678",
"product_id": "8123456789",
"name": "Ethiopia Guji Natural · 12 oz",
"quantity": 2,
"price": 19
},
{
"id": "NW-FLT-V60",
"variant_id": "44012345990",
"product_id": "8123456990",
"name": "Hario V60 Paper Filters",
"quantity": 1,
"price": 13.5
}
],
"discount_codes": [
"NORA-7XK2QP"
],
"email": "maya.chen@example.com",
"placed_at": "2026-10-04T19:02:44.000Z",
"attribution": {
"type": "direct",
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"contact_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"channel": "web",
"handled_by": "ai",
"reasons": [
"discount",
"conversation"
],
"last_chat_at": "2026-10-04T18:21:09.000Z",
"window_days": 7
},
"created_at": "2026-10-04T19:02:46.000Z"
}
],
"has_more": true,
"next_cursor": "WyIyMDI2LTEwLTA0IDE4OjIwOjUxLjAwMCIsIjhkMGM1ZjhlIl0"
}Get an order
GET/api/v1/orders/{id}orders:read
curl "https://www.chatrevia.com/api/v1/orders/2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": {
"id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"object": "order",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"platform": "shopify",
"source": "shopify",
"order_id": "5512044331",
"name": "#1042",
"total": 46.5,
"subtotal": 51.5,
"currency": "USD",
"items": [
{
"id": "NW-ETH-GUJI-12",
"variant_id": "44012345678",
"product_id": "8123456789",
"name": "Ethiopia Guji Natural · 12 oz",
"quantity": 2,
"price": 19
},
{
"id": "NW-FLT-V60",
"variant_id": "44012345990",
"product_id": "8123456990",
"name": "Hario V60 Paper Filters",
"quantity": 1,
"price": 13.5
}
],
"discount_codes": [
"NORA-7XK2QP"
],
"email": "maya.chen@example.com",
"placed_at": "2026-10-04T19:02:44.000Z",
"attribution": {
"type": "direct",
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"contact_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"channel": "web",
"handled_by": "ai",
"reasons": [
"discount",
"conversation"
],
"last_chat_at": "2026-10-04T18:21:09.000Z",
"window_days": 7
},
"created_at": "2026-10-04T19:02:46.000Z"
}
}Workspace
Check your key
GET/api/v1/me
The key's workspace, scopes and websites. A quick way to test authentication.
curl "https://www.chatrevia.com/api/v1/me" \
-H "Authorization: Bearer $CHATREVIA_API_KEY"{
"data": {
"object": "api_key",
"id": "3f2e1d0c-…",
"name": "Order system",
"scopes": [
"inbox:write",
"people:write",
"knowledge:read"
],
"role": "admin",
"workspace": {
"id": "1a2b3c4d-…",
"name": "Northwind Coffee",
"plan": "pro"
},
"websites": [
{
"id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"name": "Northwind Coffee",
"url": "https://northwindcoffee.com"
}
]
}
}Webhooks
Add an endpoint in Settings → Developers → Webhooks and pick its events. Chatrevia sends a POST with this JSON body the moment the change is saved. Any 2xx response within 10 seconds counts as delivered.
| Event | When |
|---|---|
conversation.created | A visitor sent the first message in a conversation (data.message is that message). |
message.created | A visitor, the AI agent or a teammate sent a message (data.message.author.type is visitor, ai or teammate). |
conversation.assigned | A conversation was assigned to a teammate. |
conversation.closed | A conversation was resolved. |
handoff.requested | A visitor asked to talk to a person. |
conversation.escalated | A conversation was sent to your helpdesk (Zendesk, Gorgias or Freshdesk) and the ticket was created. data.escalation.external_ticket has its id and link. |
csat.submitted | A visitor rated a resolved conversation (1 to 5). |
contact.identified | Your website identified a signed-in user in the messenger (identify). data.verified says whether identity verification passed. |
lead.captured | A visitor shared their contact details with consent. |
ticket.created | A ticket was created by a teammate, an automation or the API. |
ticket.updated | A ticket's status, priority, assignee, title or description changed. data.previous holds the old values. |
action.run | The AI agent ran one of your AI actions (succeeded, failed or blocked). |
discount.issued | The AI agent gave a shopper a single-use Shopify discount code (value and rules from your discount settings). |
return.requested | A shopper submitted a return or exchange in the messenger: a Shopify return request, or a ticket when Shopify couldn't take it. |
order.attributed | An order (Shopify, the purchase snippet or the API) was attributed to a conversation: direct (a product added from chat, a chat discount code, checkout from the messenger), influenced (the buyer chatted within the attribution window) or recovered (it recovered an abandoned cart). |
cart.abandoned | A shopper's cart sat untouched past your "abandoned after" time and cart recovery started (Recovery settings). data.cart has its items and total. |
cart.recovered | An order recovered an abandoned cart: it came through the cart-restore link, or the shopper bought that cart after a reminder. data.order is the order. |
Signatures
Every request has a Chatrevia-Signature header: t=<unix seconds>,v1=<hex>, where v1 is the HMAC-SHA256 of t + "." + raw body with the endpoint’s signing secret. Compare in constant time and reject timestamps older than 5 minutes. After you roll a secret, both the new and the old signature are sent until the old one expires.
Retries
Failed deliveries are retried 5 times, after about 1 min, 10 min, 1 h, 6 h, 16 h (6 attempts over about a day). Each attempt, its status, latency and response are in the delivery log, where you can resend any delivery or send a test event. An endpoint that fails for 3 days is turned off and your administrators are told. Events can arrive out of order; use created_at and the event id to order and de-duplicate.
{
"id": "evt_3f9c2a7d1b8e4f60a1c5d7e9b2f4a6c8",
"type": "conversation.closed",
"created_at": "2026-10-04T18:32:40.000Z",
"workspace_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"data": {
"conversation": {
"id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41",
"object": "conversation",
"website_id": "5b8e1c2a-7d34-4f0b-8e6a-1c9d2f3a4b5c",
"status": "closed",
"channel": "web",
"visitor": {
"name": "Maya Chen",
"email": "maya.chen@example.com",
"user_id": "cus_48213",
"verified": true
},
"contact_id": "c1a2b3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"assignee": null,
"taken_over": false,
"priority": "normal",
"tags": [
"orders"
],
"summary": "Where is my order #4417?",
"handoff_requested_at": null,
"snoozed_until": null,
"csat": null,
"last_visitor_message_at": "2026-10-04T18:21:07.000Z",
"closed_at": "2026-10-04T18:32:40.000Z",
"created_at": "2026-10-04T18:20:51.000Z",
"updated_at": "2026-10-04T18:21:07.000Z"
}
}
}import crypto from "node:crypto";
import express from "express";
const app = express();
// The raw body: verify exactly the bytes Chatrevia signed.
app.post("/chatrevia", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("Chatrevia-Signature") || "";
const t = header.match(/t=(\d+)/)?.[1];
const sent = [...header.matchAll(/v1=([0-9a-f]{64})/g)].map((m) => m[1]);
const expected = crypto
.createHmac("sha256", process.env.CHATREVIA_WEBHOOK_SECRET)
.update(`${t}.${req.body}`)
.digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
const valid = sent.some((s) =>
crypto.timingSafeEqual(Buffer.from(s, "hex"), Buffer.from(expected, "hex")),
);
if (!t || !fresh || !valid) return res.sendStatus(400);
const event = JSON.parse(req.body);
// Handle event.type (e.g. "conversation.closed"), then answer quickly.
res.sendStatus(200);
});Zapier, Make & n8n
There’s no app to install: webhooks and the REST API work with any automation tool. To send new conversations to a Google Sheet or a Slack channel with Zapier:
- In Zapier, create a Zap with the trigger Webhooks by Zapier → Catch Hook and copy its URL.
- In Chatrevia, open Settings → Developers → Webhooks, choose Add endpoint, paste the URL and pick events such as
conversation.createdandlead.captured. - Open the endpoint and choose Send test event. Back in Zapier, click Test trigger: the sample event appears, with fields like
data__conversation__visitor__email. - Add your action (Google Sheets, Slack, HubSpot…) and map the fields. To act back in Chatrevia, add a Webhooks by Zapier → Custom Request step that calls the REST API with your key, for example to create a ticket.
In Make, use the Webhooks → Custom webhook module; in n8n, the Webhook node with method POST. Check the signature in a code step when the flow changes data.
curl -X POST "https://www.chatrevia.com/api/v1/tickets" \
-H "Authorization: Bearer $CHATREVIA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"title": "Replace damaged grinder burr",
"priority": "high",
"conversation_id": "8d0c5f8e-2f6b-4c1e-9a52-3f1d7b9e6a41"
}'Identity verification
When a customer is signed in to your website, tell the messenger who they are with Chatrevia.identify(). To prove it, your server signs the user with the website’s identity secret (Settings → Developers → Identity verification):
- User hash: HMAC-SHA256 of the user ID, as hex. The user ID is verified; name and email are taken as given.
- JWT: an HS256 token with
sub(your user ID),exp(at most 24 hours ahead), and optionallyemail,nameandattributes. Its email counts as verified, so order lookup won’t ask for it.
Verified visitors are linked to one person per user ID, marked Verified in the inbox and People, and announced with a contact.identified webhook. With Require verification on, an unsigned identify() can’t set a name or email or link to anyone. Never put the secret in your page.
import crypto from "node:crypto";
// On your server, for the signed-in user. Never put the secret in the page.
const userHash = crypto
.createHmac("sha256", process.env.CHATREVIA_IDENTITY_SECRET)
.update(String(user.id))
.digest("hex");<script>
// After the Chatrevia embed, on pages where the user is signed in.
Chatrevia.identify({
userId: "{{ user.id }}",
email: "{{ user.email }}",
name: "{{ user.name }}",
userHash: "{{ user_hash }}" // from your server
});
</script>import jwt from "jsonwebtoken";
const token = jwt.sign(
{ sub: String(user.id), email: user.email, name: user.name },
process.env.CHATREVIA_IDENTITY_SECRET,
{ algorithm: "HS256", expiresIn: "1h" },
);Connect Chatrevia to the rest of your stack.
Start free, then add the REST API and webhooks on Pro when you’re ready to automate.