Developer Documentation
Deskwoot REST API
Build integrations, automate workflows, and manage your entire Deskwoot account programmatically. All endpoints use JSON and return standard HTTP status codes.
Base URL: https://deskwoot.com/api/v1Authentication
The Deskwoot API uses bearer token authentication. API tokens can be created in your account settings under Settings > API Tokens. API access requires the Enterprise plan.
Include your API token in the Authorization header of every request:
curl https://deskwoot.com/api/v1/accounts/{account_id}/contacts \
-H "Authorization: Bearer dw_your_api_token_here" \
-H "Content-Type: application/json"Finding your account ID
Most endpoints live under /v1/accounts/{accountId}/..., so you need your account ID. It is shown in Settings > API Tokens next to the usage examples. To fetch it programmatically from a token, call GET /v1/me— the one endpoint that does not need an account ID in the path:
curl https://deskwoot.com/api/v1/me \
-H "Authorization: Bearer dw_your_api_token_here"
# Response
{
"user": { "id": "...", "email": "you@example.com", "name": "..." },
"accountId": "cmxxxxxxxxxxxxxxxxxxxxxxx",
"accountIds": ["cmxxxxxxxxxxxxxxxxxxxxxxx"],
"authMethod": "api_token",
"scopes": ["read", "write"]
}Token format
All API tokens start with the prefix dw_ followed by 64 hex characters. Tokens are shown only once at creation time. Store them securely.
Scopes
Each token has one or more scopes that control which resources it can access. The broad read and write scopes cover all resources. Use narrow scopes for least-privilege access.
| Parameter | Type | Required | Description |
|---|---|---|---|
read | scope | Optional | Read access to all resources |
write | scope | Optional | Write access to all resources |
contacts:read | scope | Optional | Read contacts only |
contacts:write | scope | Optional | Create and update contacts |
conversations:read | scope | Optional | Read conversations and messages |
conversations:write | scope | Optional | Update conversations and send messages |
help_center:read | scope | Optional | Read portals, articles, and categories |
help_center:write | scope | Optional | Create and update portals, articles, and categories |
Errors
The API returns standard HTTP status codes. Errors include a JSON body with an error field describing the problem.
| Parameter | Type | Required | Description |
|---|---|---|---|
200 | OK | Optional | Request succeeded |
201 | Created | Optional | Resource created |
400 | Bad Request | Optional | Invalid parameters or missing required fields |
401 | Unauthorized | Optional | Missing or invalid API token |
403 | Forbidden | Optional | Token lacks required scope or feature not available on your plan |
404 | Not Found | Optional | Resource does not exist |
409 | Conflict | Optional | Resource already exists (e.g. duplicate email) |
500 | Server Error | Optional | Unexpected error on our side |
Error response example
{
"error": "Label with this title already exists"
}Conversations
/v1/conversations/{conversationId}Retrieve a single conversation with its contact, inbox, assignee, team, labels, and messages.
Auth: Bearer token (conversations:read) or session
Response
{
"id": "clx1abc...",
"status": "OPEN",
"priority": "MEDIUM",
"inboxId": "clx2def...",
"contactId": "clx3ghi...",
"assigneeId": "clx4jkl...",
"teamId": null,
"muted": false,
"lastActivityAt": "2026-03-14T10:30:00Z",
"createdAt": "2026-03-13T08:00:00Z",
"contact": { "id": "...", "name": "Lisa", "email": "lisa@example.com" },
"inbox": { "id": "...", "name": "Live Chat", "channelType": "WEB" },
"assignee": { "id": "...", "name": "Jan", "email": "jan@deskwoot.com" },
"labels": [{ "id": "...", "title": "VIP", "color": "#6366F1" }],
"messages": [...]
}/v1/conversations/{conversationId}Update a conversation's status, priority, assignee, or team.
Auth: Bearer token (conversations:write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | Optional | OPEN, RESOLVED, PENDING, or SNOOZED |
priority | string | null | Optional | URGENT, HIGH, MEDIUM, LOW, or null to clear |
assigneeId | string | null | Optional | Agent ID to assign, or null to unassign |
teamId | string | null | Optional | Team ID to assign, or null to unassign |
muted | boolean | Optional | Mute notifications for this conversation |
Example
curl -X PATCH https://deskwoot.com/api/v1/conversations/{id} \
-H "Authorization: Bearer dw_your_token" \
-H "Content-Type: application/json" \
-d '{"status": "RESOLVED", "priority": null}'/v1/accounts/{accountId}/conversations/bulkUpdate multiple conversations at once. Supports status changes, assignments, priority, labels, and muting.
Auth: Bearer token (conversations:write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
conversationIds | string[] | Required | Array of conversation IDs |
action | string | Required | change_status, assign_agent, assign_team, change_priority, add_label, or mute |
value | string | null | Optional | The target value for the action |
Example
curl -X POST https://deskwoot.com/api/v1/accounts/{accountId}/conversations/bulk \
-H "Authorization: Bearer dw_your_token" \
-H "Content-Type: application/json" \
-d '{
"conversationIds": ["conv_1", "conv_2", "conv_3"],
"action": "change_status",
"value": "RESOLVED"
}'Messages
/v1/conversations/{conversationId}/messagesList all messages in a conversation, including sender info and attachments.
Auth: Bearer token (conversations:read) or session
Response
[
{
"id": "clx5mno...",
"content": "Hi, I need help with my order.",
"messageType": "INCOMING",
"private": false,
"createdAt": "2026-03-14T10:00:00Z",
"sender": { "id": "...", "name": "Lisa", "type": "contact" },
"attachments": []
},
{
"id": "clx6pqr...",
"content": "Sure, let me look into that for you!",
"messageType": "OUTGOING",
"private": false,
"createdAt": "2026-03-14T10:02:00Z",
"sender": { "id": "...", "name": "Jan", "type": "user" },
"attachments": []
}
]/v1/conversations/{conversationId}/messagesSend a new message in a conversation. The message is delivered to the customer through the original channel.
Auth: Bearer token (conversations:write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
content | string | Required | Message text |
private | boolean | Optional | If true, the message is only visible to agents (internal note). Default: false |
messageType | string | Optional | OUTGOING (default) or INCOMING |
Example
curl -X POST https://deskwoot.com/api/v1/conversations/{id}/messages \
-H "Authorization: Bearer dw_your_token" \
-H "Content-Type: application/json" \
-d '{"content": "Your order has been shipped!", "private": false}'/v1/conversations/{conversationId}/attachmentsUpload a file attachment to a conversation. Max file size: 10 MB.
Auth: Bearer token (conversations:write) or session
Example
curl -X POST https://deskwoot.com/api/v1/conversations/{id}/attachments \
-H "Authorization: Bearer dw_your_token" \
-F "file=@invoice.pdf" \
-F "content=Here is your invoice."/v1/conversations/{conversationId}/labelsAdd a label to a conversation.
Auth: Bearer token (conversations:write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
labelId | string | Required | The label ID to add |
/v1/conversations/{conversationId}/labels?labelId={labelId}Remove a label from a conversation.
Auth: Bearer token (conversations:write) or session
Contacts
/v1/accounts/{accountId}/contactsList contacts with optional search and segment filtering. Supports pagination.
Auth: Bearer token (contacts:read) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
search | string | Optional | Search by name, email, or phone number |
segment | string | Optional | Filter: active-7d, active-30d, no-email, has-email, has-phone, new |
page | number | Optional | Page number (default: 1) |
pageSize | number | Optional | Items per page (default: 25) |
Response
{
"contacts": [
{
"id": "clx7stu...",
"name": "Lisa Schmidt",
"email": "lisa@example.com",
"phone": "+49 170 1234567",
"avatarUrl": null,
"company": "Acme GmbH",
"lastActivityAt": "2026-03-14T09:00:00Z",
"createdAt": "2026-01-15T12:00:00Z"
}
],
"total": 142,
"page": 1,
"pageSize": 25
}/v1/accounts/{accountId}/contacts/mergeMerge two contact records into one. The primary contact keeps its data; the secondary contact's conversations are moved over.
Auth: Bearer token (contacts:write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
primaryContactId | string | Required | The contact to keep |
secondaryContactId | string | Required | The contact to merge and delete |
Inboxes
/v1/accounts/{accountId}/inboxesList all inboxes in your account.
Auth: Bearer token (read) or session
Response
[
{
"id": "clx8uvw...",
"name": "Website Chat",
"channelType": "WEB",
"greeting": "Hi! How can we help?",
"greetingEnabled": true,
"enableAutoAssign": true,
"csatEnabled": true,
"csatRatingStyle": "STARS",
"csatPromptText": null,
"createdAt": "2026-01-01T00:00:00Z"
},
{
"id": "clx9xyz...",
"name": "Support Email",
"channelType": "EMAIL",
"emailAddress": "support@acme.com",
"createdAt": "2026-01-01T00:00:00Z"
}
]/v1/accounts/{accountId}/inboxesCreate a new inbox. Supported channel types: WEB, EMAIL, TELEGRAM, WHATSAPP, SMS, LINE, TWITTER.
Auth: Session (permission: settings.manage_inboxes)
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Display name for the inbox |
channelType | string | Required | WEB, EMAIL, TELEGRAM, WHATSAPP, SMS, LINE, or TWITTER |
greeting | string | Optional | Welcome message shown to visitors |
greetingEnabled | boolean | Optional | Show greeting message (default: false) |
enableAutoAssign | boolean | Optional | Auto-assign to available agents (default: true) |
botEnabled | boolean | Optional | Enable AI bot for this inbox |
agentBotId | string | Optional | Bot ID to use when botEnabled is true |
Example: Create Telegram inbox
curl -X POST https://deskwoot.com/api/v1/accounts/{accountId}/inboxes \
-H "Authorization: Bearer dw_your_token" \
-H "Content-Type: application/json" \
-d '{
"name": "Telegram Support",
"channelType": "TELEGRAM",
"telegramBotToken": "123456:ABC-DEF..."
}'/v1/accounts/{accountId}/inboxes/{inboxId}Get full details for a single inbox.
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/inboxes/{inboxId}Update inbox settings such as name, greeting, auto-assign mode, CSAT, business hours, widget color, and bot configuration.
Auth: Session (permission: settings.manage_inboxes)
CSAT-related fields
{
"csatEnabled": true,
"csatRatingStyle": "STARS", // STARS | HEARTS | FIRE | SMILEYS
"csatPromptText": "How was your experience today?" // null = default
}csatRatingStyle is validated against the four allowed values. csatPromptText is capped at 240 characters and empty string is normalized to null (fall back to the localized default).
/v1/accounts/{accountId}/inboxes/{inboxId}Delete an inbox and all associated data. This action cannot be undone.
Auth: Session (permission: settings.manage_inboxes)
Agents
/v1/accounts/{accountId}/agentsList all agents (team members) in your account, including their role and custom role.
Auth: Bearer token (read) or session
Response
{
"agents": [
{
"user": {
"id": "clx_user1",
"name": "Jan",
"email": "jan@deskwoot.com",
"avatarUrl": null
},
"role": "ADMINISTRATOR",
"customRole": null
}
],
"maxAgents": 10,
"plan": "ENTERPRISE"
}/v1/accounts/{accountId}/agentsInvite a new agent to your account. An invitation email is sent automatically.
Auth: Session (admin only)
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Full name of the new agent |
email | string | Required | Email address |
role | string | Optional | AGENT (default) or ADMINISTRATOR |
customRoleId | string | Optional | ID of a custom role to assign |
/v1/accounts/{accountId}/agents/{agentId}Update an agent's role.
Auth: Session (admin only)
| Parameter | Type | Required | Description |
|---|---|---|---|
role | string | Optional | AGENT or ADMINISTRATOR |
customRoleId | string | null | Optional | Custom role ID or null to remove |
/v1/accounts/{accountId}/agents/{agentId}Remove an agent from your account.
Auth: Session (admin only)
Teams
Teams require the Business plan or higher.
/v1/accounts/{accountId}/teamsList all teams with their member count.
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/teamsCreate a new team.
Auth: Session (permission: settings.manage_teams)
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Team name |
description | string | Optional | Team description |
allowAutoAssign | boolean | Optional | Allow auto-assignment to this team (default: true) |
/v1/accounts/{accountId}/teams/{teamId}Get a team with its full member list.
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/teams/{teamId}Update team name, description, or auto-assign setting.
Auth: Session (permission: settings.manage_teams)
/v1/accounts/{accountId}/teams/{teamId}Delete a team.
Auth: Session (permission: settings.manage_teams)
/v1/accounts/{accountId}/teams/{teamId}/membersAdd an agent to a team.
Auth: Session (permission: settings.manage_teams)
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Required | The agent's user ID |
/v1/accounts/{accountId}/teams/{teamId}/membersRemove an agent from a team.
Auth: Session (permission: settings.manage_teams)
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Required | The agent's user ID |
Labels
/v1/accounts/{accountId}/labelsList all labels in your account.
Auth: Bearer token (read) or session
Response
[
{
"id": "clx_label1",
"title": "VIP",
"color": "#6366F1",
"description": "High-value customers",
"showOnSidebar": true
}
]/v1/accounts/{accountId}/labelsCreate a new label.
Auth: Session (permission: settings.manage_labels)
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | Required | Label name |
color | string | Optional | Hex color code (default: "#6366F1") |
description | string | Optional | Label description |
showOnSidebar | boolean | Optional | Show in sidebar filter (default: true) |
/v1/accounts/{accountId}/labels/{labelId}Update a label's title, color, description, or visibility.
Auth: Session (permission: settings.manage_labels)
/v1/accounts/{accountId}/labels/{labelId}Delete a label. It will be removed from all conversations.
Auth: Session (permission: settings.manage_labels)
Canned Responses
/v1/accounts/{accountId}/canned-responsesList all canned responses.
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/canned-responsesCreate a canned response. Agents can use it by typing the short code in the message input.
Auth: Session (permission: settings.manage_canned_responses)
| Parameter | Type | Required | Description |
|---|---|---|---|
shortCode | string | Required | Trigger shortcode (e.g. 'greeting') |
content | string | Required | Response text. Supports {{contact.name}} variables. |
/v1/accounts/{accountId}/canned-responses/{cannedResponseId}Update a canned response.
Auth: Session (permission: settings.manage_canned_responses)
/v1/accounts/{accountId}/canned-responses/{cannedResponseId}Delete a canned response.
Auth: Session (permission: settings.manage_canned_responses)
Macros
/v1/accounts/{accountId}/macrosList all public macros and your personal macros.
Auth: Bearer token (read) or session
Response
{
"data": [
{
"id": "clx_macro1",
"name": "Close and resolve",
"visibility": "PUBLIC",
"actions": [
{ "type": "change_status", "value": "RESOLVED" },
{ "type": "send_message", "value": "Thanks for reaching out! Closing this now." }
]
}
]
}/v1/accounts/{accountId}/macrosCreate a new macro with one or more actions.
Auth: Bearer token (write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Macro name |
actions | array | Optional | Array of action objects with type and value |
visibility | string | Optional | PERSONAL (default) or PUBLIC |
/v1/accounts/{accountId}/macros/{macroId}Update a macro.
Auth: Bearer token (write) or session
/v1/accounts/{accountId}/macros/{macroId}Delete a macro.
Auth: Bearer token (write) or session
Automation Rules
Automation rules require the Business plan or higher.
/v1/accounts/{accountId}/automation-rulesList all automation rules.
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/automation-rulesCreate an automation rule with conditions and actions.
Auth: Session (permission: settings.manage_automation)
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Rule name |
eventName | string | Required | Trigger event: conversation_created, conversation_updated, or message_created |
conditions | array | Optional | Array of condition objects (attribute, operator, value) |
actions | array | Optional | Array of action objects (type, value) |
active | boolean | Optional | Enable the rule (default: true) |
Example
curl -X POST https://deskwoot.com/api/v1/accounts/{accountId}/automation-rules \
-H "Authorization: Bearer dw_your_token" \
-H "Content-Type: application/json" \
-d '{
"name": "Auto-assign VIP to senior team",
"eventName": "conversation_created",
"conditions": [
{ "attribute": "label", "operator": "contains", "value": "VIP" }
],
"actions": [
{ "type": "assign_team", "value": "senior-support-team-id" }
]
}'/v1/accounts/{accountId}/automation-rules/{ruleId}Update an automation rule.
Auth: Session (permission: settings.manage_automation)
/v1/accounts/{accountId}/automation-rules/{ruleId}Delete an automation rule.
Auth: Session (permission: settings.manage_automation)
Campaigns
Campaigns require the Business plan or higher.
/v1/accounts/{accountId}/campaignsList all campaigns (ongoing and one-off).
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/campaignsCreate a new campaign.
Auth: Session (permission: settings.manage_campaigns)
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | Required | Campaign title |
message | string | Required | Message content |
campaignType | string | Optional | ONGOING or ONE_OFF (default: ONGOING) |
inboxId | string | Optional | Inbox to send from |
scheduledAt | string | Optional | ISO date for one-off campaigns |
audience | object | Optional | Audience targeting rules |
/v1/accounts/{accountId}/campaigns/{campaignId}Get campaign details.
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/campaigns/{campaignId}Update a campaign.
Auth: Session (permission: settings.manage_campaigns)
/v1/accounts/{accountId}/campaigns/{campaignId}/sendSend a one-off campaign immediately.
Auth: Session (permission: settings.manage_campaigns)
/v1/accounts/{accountId}/campaigns/{campaignId}Delete a campaign.
Auth: Session (permission: settings.manage_campaigns)
Webhooks
Webhooks let you receive real-time HTTP notifications when events happen in your Deskwoot account. Every webhook payload is signed with HMAC-SHA256 so you can verify authenticity.
Verifying webhook signatures
Each webhook request includes an X-Deskwoot-Signature header. Compute the HMAC-SHA256 of the raw request body using your webhook secret, and compare it to the header value.
Verification example (Node.js)
import crypto from "crypto";
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}Event types
| Parameter | Type | Required | Description |
|---|---|---|---|
message.created | event | Optional | A new message was sent or received in a conversation |
conversation.updated | event | Optional | A conversation's status, assignee, team, or priority changed |
conversation.created | event | Optional | A new conversation was started |
contact.created | event | Optional | A new contact was created |
contact.updated | event | Optional | A contact's details were updated |
/v1/accounts/{accountId}/webhooksList all webhooks.
Auth: Session (admin only)
/v1/accounts/{accountId}/webhooksCreate a webhook. A signing secret is generated automatically and returned in the response.
Auth: Session (admin only)
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Required | The HTTPS URL to receive webhook events |
subscriptions | string[] | Optional | Event types to subscribe to (default: all events) |
Example
curl -X POST https://deskwoot.com/api/v1/accounts/{accountId}/webhooks \
-H "Authorization: Bearer dw_your_token" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/deskwoot",
"subscriptions": ["message.created", "conversation.updated"]
}'Response
{
"id": "clx_wh1",
"url": "https://your-app.com/webhooks/deskwoot",
"subscriptions": ["message.created", "conversation.updated"],
"secret": "whsec_a1b2c3d4e5f6...",
"createdAt": "2026-03-14T12:00:00Z"
}/v1/accounts/{accountId}/webhooks/{webhookId}Update a webhook's URL or subscriptions.
Auth: Session (admin only)
/v1/accounts/{accountId}/webhooks/{webhookId}Delete a webhook.
Auth: Session (admin only)
API Tokens
API tokens require the Enterprise plan.
/v1/accounts/{accountId}/api-tokensList all API tokens. The actual token value is not included for security.
Auth: Session (admin only)
Response
[
{
"id": "clx_tk1",
"name": "Production Integration",
"scopes": ["read", "write"],
"lastUsedAt": "2026-03-14T10:00:00Z",
"expiresAt": null,
"createdAt": "2026-02-01T00:00:00Z"
}
]/v1/accounts/{accountId}/api-tokensCreate a new API token. The token value is only shown once in the response.
Auth: Session (admin only)
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Optional | A descriptive name for the token |
scopes | string[] | Optional | Array of scopes (default: ["read", "write"]) |
expiresAt | string | Optional | ISO date when the token expires (optional, never expires if omitted) |
/v1/accounts/{accountId}/api-tokens/{tokenId}Revoke an API token. It will immediately stop working.
Auth: Session (admin only)
Bots
/v1/accounts/{accountId}/botsList all AI bots. API keys are masked in the response.
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/botsCreate a new AI bot.
Auth: Session (permission: bots.manage)
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Bot name |
aiProvider | string | Optional | AI provider: openai, anthropic, google, groq, or custom |
aiApiKey | string | Optional | Your AI provider API key |
aiModel | string | Optional | Model name (e.g. gpt-4o, claude-sonnet-4-20250514) |
systemPrompt | string | Optional | Custom instructions for the bot |
useHelpCenter | boolean | Optional | Let the bot use your help center articles as context |
temperature | number | Optional | Creativity level 0-1 (default: 0.3) |
maxTokens | number | Optional | Max response length 100-2000 (default: 500) |
/v1/accounts/{accountId}/bots/{botId}Update a bot's settings.
Auth: Session (permission: bots.manage)
/v1/accounts/{accountId}/bots/{botId}Delete a bot.
Auth: Session (permission: bots.manage)
/v1/accounts/{accountId}/bots/testTest a bot's response with a sample message.
Auth: Session (permission: bots.manage)
| Parameter | Type | Required | Description |
|---|---|---|---|
botId | string | Required | Bot ID to test |
message | string | Required | Test message |
Custom Attributes
Custom attributes require the Business plan or higher.
/v1/accounts/{accountId}/custom-attributesList custom attribute definitions. Use ?model=CONVERSATION or ?model=CONTACT to filter.
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/custom-attributesCreate a custom attribute definition.
Auth: Session (admin only)
| Parameter | Type | Required | Description |
|---|---|---|---|
attributeDisplayName | string | Required | Display name shown in the UI |
attributeKey | string | Required | Unique key used in API (snake_case) |
attributeDisplayType | string | Optional | TEXT, NUMBER, LINK, DATE, LIST, or CHECKBOX (default: TEXT) |
attributeModel | string | Optional | CONVERSATION or CONTACT (default: CONVERSATION) |
attributeValues | string[] | Optional | Predefined values for LIST type |
/v1/accounts/{accountId}/custom-attributes/{attributeId}Update a custom attribute.
Auth: Session (admin only)
/v1/accounts/{accountId}/custom-attributes/{attributeId}Delete a custom attribute.
Auth: Session (admin only)
Custom Roles
/v1/accounts/{accountId}/custom-rolesList all custom roles with their permissions.
Auth: Session (admin only)
/v1/accounts/{accountId}/custom-rolesCreate a custom role with granular permissions.
Auth: Session (admin only)
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Role name |
description | string | Optional | Role description |
permissions | object | Optional | Permission flags (e.g. conversations.manage, settings.manage_inboxes) |
/v1/accounts/{accountId}/custom-roles/{roleId}Update a custom role.
Auth: Session (admin only)
/v1/accounts/{accountId}/custom-roles/{roleId}Delete a custom role.
Auth: Session (admin only)
SLA Policies
SLA policies require the Business plan or higher.
/v1/accounts/{accountId}/sla-policiesList all SLA policies with conversation counts.
Auth: Bearer token (read) or session
/v1/accounts/{accountId}/sla-policiesCreate an SLA policy.
Auth: Session (admin only)
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Policy name |
description | string | Optional | Policy description |
firstResponseTimeThreshold | number | Optional | Max seconds for first response |
nextResponseTimeThreshold | number | Optional | Max seconds between responses |
resolutionTimeThreshold | number | Optional | Max seconds to resolve |
onlyDuringBusinessHours | boolean | Optional | Only count time during business hours (default: false) |
/v1/accounts/{accountId}/sla-policies/{policyId}Update an SLA policy.
Auth: Session (admin only)
/v1/accounts/{accountId}/sla-policies/{policyId}Delete an SLA policy.
Auth: Session (admin only)
Business Hours
/v1/accounts/{accountId}/business-hoursGet your account's business hours configuration.
Auth: Bearer token (read) or session
Response
{
"enabled": true,
"timezone": "Europe/Berlin",
"schedule": [
{ "day": "monday", "enabled": true, "openHour": 9, "openMinute": 0, "closeHour": 17, "closeMinute": 0 },
{ "day": "tuesday", "enabled": true, "openHour": 9, "openMinute": 0, "closeHour": 17, "closeMinute": 0 },
{ "day": "saturday", "enabled": false, "openHour": 0, "openMinute": 0, "closeHour": 0, "closeMinute": 0 },
{ "day": "sunday", "enabled": false, "openHour": 0, "openMinute": 0, "closeHour": 0, "closeMinute": 0 }
]
}/v1/accounts/{accountId}/business-hoursSet business hours. Provide the full schedule.
Auth: Session (permission: settings.manage_account)
Help Center (Portals)
/v1/accounts/{accountId}/portalsList your help center portals with article and category counts.
Auth: Bearer token (help_center:read) or session
/v1/accounts/{accountId}/portalsCreate a new help center portal.
Auth: Bearer token (help_center:write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Portal name |
slug | string | Required | URL slug (e.g. 'help') |
headerText | string | Optional | Header text shown on the portal |
brandColor | string | Optional | Brand color hex (default: "#2563EB") |
customDomain | string | Optional | Custom domain for the portal |
/v1/accounts/{accountId}/portals/{portalId}Update portal settings, including which languages it offers translations in.
Auth: Bearer token (help_center:write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Optional | Portal name |
pageTitle | string | Optional | Large heading shown to visitors (defaults to the name) |
headerText | string | Optional | Subtitle shown under the title |
brandColor | string | Optional | Brand color hex |
faviconUrl | string | Optional | Absolute https URL to the browser-tab favicon (square PNG/ICO). Send empty to clear it. The Help Center then shows a generated branded icon, never the Deskwoot one. |
showChatWidget | boolean | Optional | Show your chat widget (the same one you embed on your website) on the Help Center pages. Requires a live-chat (website) inbox; if none exists nothing is shown. |
articleSidebar | boolean | Optional | Article pages get a left "In this category" sidebar listing sibling articles (docs-style navigation). Only appears when a category has more than one article. |
homePageLink | string | Optional | URL the portal name / logo links back to (usually your main website). |
topPillLabel | string | Optional | Small pill shown above the headline (announcement / tagline). Empty hides the pill. |
topPillBg | string | Optional | Background color hex for the top pill. |
topPillText | string | Optional | Text color hex for the top pill. |
searchEnabled | boolean | Optional | Show the search bar on the home page (default true). |
searchPlaceholder | string | Optional | Placeholder text for the search input. |
quickJumpEnabled | boolean | Optional | Show the quick-jump link row under the search bar. |
quickJumpItems | object[] | Optional | Quick-jump links: [{ label, url }]. Sanitized on save. Send null to clear. |
faqEnabled | boolean | Optional | Show the FAQ accordion on the home page. |
faqItems | object[] | Optional | FAQ entries: [{ question, answer }]. answer keeps a curated rich-text allow-list; an optional per-locale i18n map ({ question, answer }) is supported. Send null to clear. |
promoBannerEnabled | boolean | Optional | Show the promo banner. |
promoBanner | object | Optional | Promo banner content: { headline, body, ctaLabel, ctaUrl }. body keeps a curated rich-text allow-list. Send null to clear. |
enabledLocales | string[] | Optional | Languages the help center is translated into, e.g. ["en", "de", "fr", "ja", "zh-CN"]. English is always kept; unknown codes are dropped. Supported: en, ar, de, es, fr, hi, id, ja, ko, mn, pt-BR, ru, tr, uz, zh-CN, zh-TW. |
localeControlledExternally | boolean | Optional | When true, the public article page hides its own language switcher and serves the language from ?locale=. Use it when the help center is on a custom domain and the parent site already controls the language. |
categoryCardLayout | boolean | Optional | true renders categories as a Browse-by-Topic card grid (each card links to /category/<slug>); false (default) keeps the inline article list. |
featuredArticleId | string | Optional | Id of a published article in this portal to feature in a "Start Here" block at the top of the help center. Send null to clear it. |
fontFamily | string | Optional | Web font for the public help center: "" (system default), Inter, Roboto, Open Sans, Lato, Poppins, Montserrat, Nunito, Source Sans 3, or Plus Jakarta Sans. Unknown values fall back to the system font. |
latestGuidesEnabled | boolean | Optional | Adds a “Latest Guides” grid of recent article cards (cover image, category, title, excerpt, author, date) below the categories. |
heroAlignment | string | Optional | "left" or "center" (default) for the title / subtitle / search bar. |
theme | string | Optional | "light" (default), "dark", or "auto" (follows the visitor’s prefers-color-scheme). Applies on every public page. |
themeTokens | object | Optional | Optional per-token color overrides for the theme: { pageBg, surface, border, text, muted, heading } as hex. Unknown keys / non-hex values are dropped; omit for the built-in palette. Send null to clear. |
sectionOrder | string[] | Optional | Order of the home-page sections. Valid keys: pill, headline, subheader, search, featured, quickJump, faq, categories, latestGuides, promo. Sections whose content/toggle is off are skipped. Example: ["search","categories","featured","latestGuides"]. |
customCss | string | Optional | Scoped CSS injected on every public help-center page. @import, javascript: URLs, and external resource fetches are stripped on save. Max 20,000 characters. Send null to clear. |
whiteLabel | boolean | Optional | Enterprise. Removes the “Powered by Deskwoot” credit from the footer. 402 if the plan is below Enterprise. |
customFooterEnabled | boolean | Optional | Replace the default footer with a custom one (columns/bottom text below, or customFooterHtml). |
customFooterColumns | object[] | Optional | Up to 4 footer link columns: [{ title, links: [{ label, url }] }] (max 8 links per column). Sanitized on save. Send null to clear. |
customFooterBottomText | string | Optional | A single copyright / legal line rendered below the footer columns. Max 500 characters. Send null to clear. |
customFooterHtml | string | Optional | Raw footer HTML so the help center mirrors your own marketing-site footer. When set, it REPLACES customFooterColumns / customFooterBottomText on the public page. Sanitized on save (scripts, event handlers, <style>, and javascript: URLs stripped; class + style attributes survive so customCss can finish the styling). Max 20,000 characters. Two requirements when setting a non-empty value: the portal must run on an ACTIVE custom domain (409 otherwise, it stays hidden on the *.deskwoot.com subdomain) and the plan must be Enterprise (402 otherwise). Send null to clear. |
customHeaderHtml | string | Optional | Raw header HTML rendered above the help center, so it can carry your own marketing-site navbar. Same sanitizer as customFooterHtml (no script/style/iframe/form/handlers; class + inline style survive so customCss finishes the styling). Max 20,000 characters. Same two gates: an ACTIVE custom domain (409 otherwise) and an Enterprise plan (402 otherwise). Send null/empty to clear (no header is shown, there is no default). |
published | boolean | Optional | true = live, false = draft (public URL 404s) |
/v1/accounts/{accountId}/portals/{portalId}/articlesList articles in a portal.
Auth: Bearer token (help_center:read) or session
/v1/accounts/{accountId}/portals/{portalId}/articlesCreate a new help center article.
Auth: Bearer token (help_center:write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | Required | Article title (used for the H1, page title and SEO title) |
navTitle | string | Optional | Optional short label for the "In this category" sidebar (e.g. "Bybit"). Falls back to title when empty. The H1 / SEO title are unaffected. Per-locale overrides go in translations.{locale}.navTitle. Batch-set this across a category whose titles share a pattern. |
content | string | Required | Article body (HTML; <details>/<summary> are allowed for FAQ accordions) |
slug | string | Optional | URL slug (auto-generated from title if omitted) |
categoryId | string | Required | Category the article belongs to (create one via the categories endpoint first) |
status | string | Optional | DRAFT, PUBLISHED, or ARCHIVED (case-insensitive, default: DRAFT) |
translations | object | Optional | Per-language overlay keyed by locale code, e.g. { "de": { "title": "...", "navTitle": "...", "content": "...", "description": "...", "metaTitle": "...", "metaDescription": "..." } }. English stays in the top-level fields above and is ignored here; unknown locale codes are dropped. On PATCH this merges into the stored translations one field at a time: only the locales and fields you actually include change, and everything else is preserved. So { "de": { "navTitle": "LeveX" } } sets just de.navTitle and leaves the rest of the German translation intact. To delete a whole language send { "de": null }; to clear every translation send "translations": null. The result is served via ?locale= on the public endpoints. |
/v1/accounts/{accountId}/portals/{portalId}/articles/{articleId}Update an article, including its per-language translations object.
Auth: Bearer token (help_center:write) or session
/v1/accounts/{accountId}/portals/{portalId}/articles/{articleId}Delete an article.
Auth: Bearer token (help_center:write) or session
/v1/accounts/{accountId}/portals/{portalId}/categoriesList categories in a portal, ordered by position.
Auth: Bearer token (help_center:read) or session
/v1/accounts/{accountId}/portals/{portalId}/categoriesCreate a category. Every article must belong to a category, so create one before creating articles.
Auth: Bearer token (help_center:write) or session
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Category name |
slug | string | Required | URL slug (e.g. 'getting-started') |
description | string | Optional | Short description shown under the category title |
locale | string | Optional | Language code (default: "en") |
icon | string | Optional | Icon key shown on the category card: book, rocket, sparkles, gear, chat, shield, wallet, credit-card, chart, key, lifebuoy, globe, bolt, or document. Unknown values fall back to the book icon. |
Public Portal API (no authentication required)
These endpoints are publicly accessible and designed for embedding your help center in external websites or apps.
/v1/public/portals/{portalSlug}Get public portal info with categories and article count.
Auth: None
/v1/public/portals/{portalSlug}/articlesList published articles. Supports search and pagination.
Auth: None
| Parameter | Type | Required | Description |
|---|---|---|---|
categoryId | string | Optional | Filter by category |
search | string | Optional | Search articles by title or content |
page | number | Optional | Page number (default: 1) |
limit | number | Optional | Items per page (default: 20, max: 50) |
locale | string | Optional | Language to return titles/descriptions in (e.g. en, de, fr, ja, zh-CN). Falls back to English when a field is not translated. Defaults to the Accept-Language header, then en. |
/v1/public/portals/{portalSlug}/articles/{articleSlug}Get a single published article by slug, with its title, body, and SEO fields in the requested language.
Auth: None
| Parameter | Type | Required | Description |
|---|---|---|---|
locale | string | Optional | Language to return the article in. Falls back to English for fields that are not translated. Defaults to the Accept-Language header, then en. |
Account Settings
/v1/accounts/{accountId}/settingsGet account settings including name, locale, timezone, plan, and feature flags.
Auth: Bearer token (read) or session
Response
{
"id": "clx_acc1",
"name": "Acme Support",
"locale": "en",
"timezone": "Europe/Berlin",
"plan": "ENTERPRISE",
"autoResolveEnabled": true,
"autoResolveDuration": 48,
"brandColor": "#2563EB",
"liveTranslateEnabled": true,
"liveTranslateTargetLang": "en",
"createdAt": "2026-01-01T00:00:00Z"
}/v1/accounts/{accountId}/settingsUpdate account settings.
Auth: Session (permission: settings.manage_account)
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Optional | Account name |
locale | string | Optional | Default locale (e.g. en, de) |
timezone | string | Optional | IANA timezone (e.g. Europe/Berlin) |
autoResolveEnabled | boolean | Optional | Auto-resolve inactive conversations |
autoResolveDuration | number | Optional | Hours of inactivity before auto-resolve |
brandColor | string | Optional | Brand color hex code |
liveTranslateEnabled | boolean | Optional | Enable live translation |
liveTranslateTargetLang | string | Optional | Target language for translation |
Notifications
/v1/accounts/{accountId}/notificationsGet paginated notifications for the current user.
Auth: Session only
Response
{
"data": [
{
"id": "clx_notif1",
"type": "conversation_assigned",
"read": false,
"createdAt": "2026-03-14T10:00:00Z",
"conversation": { "id": "...", "contactName": "Lisa" }
}
],
"meta": {
"page": 1,
"pageSize": 20,
"total": 45,
"unreadCount": 3
}
}/v1/accounts/{accountId}/notificationsMark notifications as read.
Auth: Session only
| Parameter | Type | Required | Description |
|---|---|---|---|
markAllRead | boolean | Optional | Set to true to mark all as read |
notificationId | string | Optional | Or mark a single notification as read |
Audit Logs
Audit logs require the Enterprise plan.
/v1/accounts/{accountId}/audit-logsGet paginated audit logs for your account. Admin only.
Auth: Session (admin only)
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | Optional | Page number (default: 1) |
Response
{
"data": [
{
"id": "clx_log1",
"action": "inbox.created",
"actor": { "name": "Jan", "email": "jan@deskwoot.com" },
"details": { "inboxName": "WhatsApp" },
"createdAt": "2026-03-14T08:00:00Z"
}
],
"meta": { "page": 1, "pageSize": 25, "total": 200, "totalPages": 8 }
}Billing
/v1/accounts/{accountId}/billingGet billing information for your account.
Auth: Session (permission: settings.manage_billing)
Response
{
"plan": "ENTERPRISE",
"status": "ACTIVE",
"agentSeats": 10,
"activeAgents": 4,
"trialEndsAt": null,
"currentPeriodEnd": "2026-04-01T00:00:00Z"
}/v1/accounts/{accountId}/ai-billingGet the unified AI conversation meter, prepaid balance, and auto-recharge config. One conversation counts at most once per calendar month, regardless of whether the live-chat bot answered, an agent ran a Copilot action, or both.
Auth: Session (member of account)
Response
{
"plan": "ENTERPRISE",
"conversationsUsed": 499,
"conversationsIncluded": 500,
"unlimited": false,
"overageConversations": 0,
"overagePrice": 0.03,
"overageCostUsd": 0,
"prepaidBalance": 0.14,
"topUpAllowed": true,
"autoRecharge": {
"enabled": true,
"amount": 100,
"maxPerMonth": 5,
"currentCount": 0
},
"usageHistory": [
{
"periodStart": "2026-04-01T00:00:00Z",
"periodEnd": "2026-05-01T00:00:00Z",
"conversationsUsed": 487,
"conversationsIncluded": 500,
"overageConversations": 0,
"overageCostUsd": 0
}
]
}Plan caps: Hacker 10/month (no overage), Startup 100 ($0.07/conv), Business 200 ($0.05/conv), Enterprise 500 ($0.03/conv). topUpAllowed: false on Hacker. Calling /v1/stripe/topup on a Hacker account returns 402 with upgradeRequired: true.
/v1/accounts/{accountId}/ai-billingUpdate auto-recharge settings. The legacy addBalance field is rejected with 410 Gone, top-ups must go through /v1/stripe/topup so Stripe is the source of truth for balance increments.
Auth: Session (permission: ADMINISTRATOR)
Request
{
"autoRechargeEnabled": true,
"autoRechargeAmount": 100,
"autoRechargeMaxPerMonth": 5
}Auto-recharge fires when aiPrepaidBalance drops below $0.10 (not $0), so the next AI action does not briefly fail while the recharge lands.
Rate limits
API requests are limited to 60 requests per minute per API token. If you exceed the limit, you will receive a 429 Too Many Requests response. Wait and retry after the window resets.
Need higher limits? Contact us to discuss your requirements.
Need help?
If you have questions about the API or need help with your integration, reach out to support@deskwoot.com or use the live chat on our website.