dskr.

Get started

Introduction

The dskr.ai API lets your tools and AI assistants work with your help desk: list and read tickets, open new ones, reply to customers, add internal notes, save drafts, change status and assign.

  • Base URL: https://app.dskr.ai/functions/agentApi
  • Format: every call is a POST with a JSON body. Responses are JSON.
  • Plan: available on the Scale plan.
  • MCP: the same actions are available to Claude, ChatGPT and other AI assistants through our MCP server (see AI Assistants).
Base URL
https://app.dskr.ai/functions/agentApi

Authentication

Every request needs a connection key in the Authorization header.

Note: Using Claude or ChatGPT? You don't need a key. You sign in with your dskr.ai account instead. See AI Assistants (MCP).

To create one:

  1. 1Sign in to dskr.ai as an admin.
  2. 2Go to Settings → AI agents & automation and create a connection.
  3. 3Tick the actions this connection may use.
  4. 4Copy the key. It starts with dskr_agent_ and is shown only once.

Each key works for one company only and can only perform the actions you ticked. Keep it secret, never put it in browser code, and delete the connection if it leaks.

Header
Authorization: Bearer dskr_agent_your_key_here

Quickstart

Using Zapier, n8n or Make? Add an HTTP step (Zapier: Webhooks by Zapier → POST, n8n: HTTP Request, Make: HTTP → Make a request) with the same address, header and JSON body.

curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "read",
    "view": "tickets",
    "limit": 5
  }'
Response200
{
  "tickets": [
    {
      "id": "6a1b2c3d4e5f60718293a4b5",
      "ticket_number": 1042,
      "customer_id": "6a0f1e2d3c4b5a6978877665",
      "subject": "Can't log in",
      "status": "Open",
      "priority": "Normal",
      "assigned_to_id": ""
    }
  ],
  "next_offset": 5
}

Requests and responses

  • Send only these fields in the body: action, view, ticket_id, customer_id, requester_id, subject, body, status, assignee_id, request_id, limit, offset. Any other field is rejected.
  • The body can be up to 16,000 characters.
  • A successful call returns HTTP 200 with the result object directly.
  • Ids are 24-character text strings, for example 6a1b2c3d4e5f60718293a4b5. ticket_number is a number.
  • Dates are ISO 8601 text, for example 2026-10-18T14:30:00.000Z.
  • Responses are never cached (Cache-Control: no-store).

Pagination

List actions accept limit (1–50, default 20) and offset (0–10,000, default 0). Responses include next_offset: send it as offset to get the next page, and stop when it's null.

Idempotency

Every action that changes something (create, send, note, draft, status, assign) needs a request_id: a UUID you generate, such as 6f1c2b9e-3a47-4d2e-9b1f-8c0e5a7d2f41.

  • If a call times out, retry with the same request_id. If the first call already succeeded, you get the original response back and nothing happens twice.
  • Use a new request_id for every new action.
  • Reusing a request_id for a different action returns 409.
REQUEST_ID=$(uuidgen)

Errors

Errors return a 4xx or 5xx status and a body like the example.

  • 400The body must be JSON.The body must be a JSON object.
    The body isn't a JSON object.
  • 400Action request is too large.
    The body is over 16,000 characters.
  • 400Only the advertised ticket actions are allowed.
    Unknown action, or a field that isn't allowed.
  • 400Mutating actions require a stable UUID request_id for safe retries.
    Missing or invalid request_id.
  • 400Choose a limit of 1–50 and an offset of 0–10000.
    limit or offset out of range.
  • 400Unsupported view.
    Unknown view.
  • 400Invalid ticket.
    ticket_id isn't a valid id.
  • 400Enter a message of 1–10000 characters.
    body is empty or too long.
  • 400Choose Open, Waiting, Resolved or Closed.
    Invalid status.
  • 400Choose a customer.
    Missing or invalid customer_id.
  • 400Choose a customer and requester, and enter a subject of 1–200 characters.
    Invalid create request.
  • 400Choose an active assignable support user in this workspace.
    Invalid assignee_id.
  • 401Invalid key.
    Missing, wrong or deleted key.
  • 403This connection is off. Turn it on in Settings → AI agents / automation.
    The connection is turned off.
  • 403AI agents & automation is not available on your plan. Upgrade to Scale to use this connection.
    Not on the Scale plan.
  • 403This connection is not allowed to perform this action.
    The action isn't ticked for this connection.
  • 403Choose an active linked requester in this workspace.
    The requester isn't active for that customer.
  • 403Internal ticket contents are not exposed to external agents.
    The ticket is internal-only.
  • 403Internal tickets cannot send customer replies.
    Send on an internal-only ticket.
  • 403Only customer-visible tickets can have reply drafts.
    Draft on an internal-only ticket.
  • 404Ticket not found.
    No such ticket in your company.
  • 404Customer not found.
    No such customer in your company.
  • 405Send a POST request with a JSON body.
    The method isn't POST.
  • 409This request id belongs to a different action.
    request_id reused for another action.
  • 409Archived tickets are read-only.
    Changing an archived ticket.
  • 409The support queue is unavailable.
    Your company has no active Support queue.
  • 409Connection changed or is busy. Retry shortly.
    Two calls collided. Retry.
  • 429This connection is busy. Retry shortly.
    Another call on this connection is still running.
  • 429Connection limit reached: 60 actions per minute.
    Rate limit reached.
  • 500Agent action could not complete.
    Unexpected error. Retry with the same request_id.
Response404
{ "error": "Ticket not found." }

Rate limits

  • 60 actions per minute per connection. The count resets at the start of each minute (UTC).
  • One action at a time per connection. Wait for each call to finish before sending the next.
  • There's no Retry-After header. On a 429 or 409 … Retry shortly, wait a few seconds and retry with the same request_id.
  • For more throughput, create separate connections for separate workflows.

API reference

List tickets

POSThttps://app.dskr.ai/functions/agentApi

Lists customer-visible tickets that aren't archived, most recently updated first.

Body parameters

  • actionrequired
    string
    "read".
  • viewoptional
    string
    "tickets". This is the default.
  • limitoptional
    integer
    1–50, default 20.
  • offsetoptional
    integer
    0–10,000, default 0.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "read",
    "view": "tickets",
    "limit": 20
  }'
Response200
{
  "tickets": [
    {
      "id": "6a1b2c3d4e5f60718293a4b5",
      "ticket_number": 1042,
      "customer_id": "6a0f1e2d3c4b5a6978877665",
      "subject": "Can't log in",
      "status": "Open",
      "priority": "Normal",
      "assigned_to_id": ""
    }
  ],
  "next_offset": 20
}

Get a ticket

POSThttps://app.dskr.ai/functions/agentApi

Returns one ticket with its description and customer-visible messages, newest first.

Body parameters

  • actionrequired
    string
    "read".
  • viewoptional
    string
    "tickets".
  • ticket_idrequired
    string
    The ticket's id.
  • limitoptional
    integer
    Page through the messages.
  • offsetoptional
    integer
    Page through the messages.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "read",
    "view": "tickets",
    "ticket_id": "6a1b2c3d4e5f60718293a4b5"
  }'
Response200
{
  "ticket": {
    "id": "6a1b2c3d4e5f60718293a4b5",
    "ticket_number": 1042,
    "customer_id": "6a0f1e2d3c4b5a6978877665",
    "subject": "Can't log in",
    "status": "Open",
    "priority": "Normal",
    "assigned_to_id": "",
    "description": "I get an error."
  },
  "messages": [
    {
      "id": "6a2c3d4e5f60718293a4b5c6",
      "body": "We're on it.",
      "author_name": "Ana",
      "created_at": "2026-10-18T14:30:00.000Z"
    }
  ],
  "next_offset": null
}

List customers

POSThttps://app.dskr.ai/functions/agentApi

Lists your customer companies, sorted by name.

Body parameters

  • actionrequired
    string
    "read".
  • viewrequired
    string
    "customers".
  • limitoptional
    integer
    1–50, default 20.
  • offsetoptional
    integer
    0–10,000, default 0.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "read",
    "view": "customers"
  }'
Response200
{
  "customers": [
    {
      "id": "6a0f1e2d3c4b5a6978877665",
      "name": "Acme Dental"
    }
  ],
  "next_offset": null
}

List requesters

POSThttps://app.dskr.ai/functions/agentApi

Lists the people at one customer who can be requesters on a ticket.

Body parameters

  • actionrequired
    string
    "read".
  • viewrequired
    string
    "requesters".
  • customer_idrequired
    string
    From List customers.
  • limitoptional
    integer
    1–50, default 20.
  • offsetoptional
    integer
    0–10,000, default 0.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "read",
    "view": "requesters",
    "customer_id": "6a0f1e2d3c4b5a6978877665"
  }'
Response200
{
  "requesters": [
    {
      "id": "6a3d4e5f60718293a4b5c6d7",
      "name": "Jane Doe"
    }
  ],
  "next_offset": null
}

List assignees

POSThttps://app.dskr.ai/functions/agentApi

Lists team members who can be assigned tickets.

Body parameters

  • actionrequired
    string
    "read".
  • viewrequired
    string
    "assignees".
  • limitoptional
    integer
    1–50, default 20.
  • offsetoptional
    integer
    0–10,000, default 0.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "read",
    "view": "assignees"
  }'
Response200
{
  "assignees": [
    {
      "id": "6a4e5f60718293a4b5c6d7e8",
      "name": "Ana Ruiz"
    }
  ],
  "next_offset": null
}

Create a ticket

POSThttps://app.dskr.ai/functions/agentApi

Opens a new ticket for a requester at one of your customers.

Body parameters

  • actionrequired
    string
    "create".
  • customer_idrequired
    string
    From List customers.
  • requester_idrequired
    string
    From List requesters.
  • subjectrequired
    string
    1–200 characters.
  • bodyrequired
    string
    1–10,000 characters.
  • request_idrequired
    UUID
    A new UUID for this action. See Idempotency.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "create",
    "customer_id": "6a0f1e2d3c4b5a6978877665",
    "requester_id": "6a3d4e5f60718293a4b5c6d7",
    "subject": "Printer offline",
    "body": "Our front desk printer stopped working this morning.",
    "request_id": "6f1c2b9e-3a47-4d2e-9b1f-8c0e5a7d2f41"
  }'
Response200
{
  "ticket_id": "6a1b2c3d4e5f60718293a4b5",
  "ticket_number": 1043
}

Reply to a customer

POSThttps://app.dskr.ai/functions/agentApi

Posts a reply the customer sees and receives by email.

Body parameters

  • actionrequired
    string
    "send".
  • ticket_idrequired
    string
    The ticket's id.
  • bodyrequired
    string
    1–10,000 characters.
  • request_idrequired
    UUID
    A new UUID for this action. See Idempotency.
Warning: This sends an email to the customer. Use Save a draft if a person should review it first.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "send",
    "ticket_id": "6a1b2c3d4e5f60718293a4b5",
    "body": "Thanks for reaching out. We'\''re looking into this now.",
    "request_id": "0b7e9c2a-5d14-4f3e-a8b6-2c9d1e4f7a30"
  }'
Response200
{
  "message_id": "6a5f60718293a4b5c6d7e8f9",
  "ticket_id": "6a1b2c3d4e5f60718293a4b5"
}

Add an internal note

POSThttps://app.dskr.ai/functions/agentApi

Adds a note only your team can see. The customer is never notified.

Body parameters

  • actionrequired
    string
    "note".
  • ticket_idrequired
    string
    The ticket's id.
  • bodyrequired
    string
    1–10,000 characters.
  • request_idrequired
    UUID
    A new UUID for this action. See Idempotency.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "note",
    "ticket_id": "6a1b2c3d4e5f60718293a4b5",
    "body": "Thanks for reaching out. We'\''re looking into this now.",
    "request_id": "7e3a9c1d-2b4f-4e6a-9d8c-1f5b3a7e9c2d"
  }'
Response200
{
  "message_id": "6a5f60718293a4b5c6d7e8f9",
  "ticket_id": "6a1b2c3d4e5f60718293a4b5"
}

Save a draft

POSThttps://app.dskr.ai/functions/agentApi

Saves a reply for a team member to review and send. It is never sent automatically.

Body parameters

  • actionrequired
    string
    "draft".
  • ticket_idrequired
    string
    The ticket's id.
  • bodyrequired
    string
    1–10,000 characters.
  • request_idrequired
    UUID
    A new UUID for this action. See Idempotency.
Note: Only customer-visible tickets can have drafts.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "draft",
    "ticket_id": "6a1b2c3d4e5f60718293a4b5",
    "body": "Thanks for reaching out. We'\''re looking into this now.",
    "request_id": "5a9b3c7d-4e2f-4a1b-8c6d-3e9f1a5b7c2d"
  }'
Response200
{
  "draft_id": "6a60718293a4b5c6d7e8f9a0",
  "ticket_id": "6a1b2c3d4e5f60718293a4b5",
  "status": "pending",
  "message": "Draft saved for a person to review. It has not been sent."
}

Change status

POSThttps://app.dskr.ai/functions/agentApi

Sets a ticket to Open, Waiting, Resolved or Closed.

Body parameters

  • actionrequired
    string
    "status".
  • ticket_idrequired
    string
    The ticket's id.
  • statusrequired
    string
    Exactly Open, Waiting, Resolved or Closed.
  • request_idrequired
    UUID
    A new UUID for this action. See Idempotency.
Note: If the ticket already has that status, the response only contains ticket_id and status.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "status",
    "ticket_id": "6a1b2c3d4e5f60718293a4b5",
    "status": "Resolved",
    "request_id": "3c8a1f2e-7b45-4d9c-b0e6-5a2f8d1c9e47"
  }'
Response200
{
  "ticket_id": "6a1b2c3d4e5f60718293a4b5",
  "status": "Resolved",
  "resolved_at": "2026-10-18T14:30:00.000Z",
  "closed_at": ""
}

Assign a ticket

POSThttps://app.dskr.ai/functions/agentApi

Assigns a ticket to a team member, or unassigns it.

Body parameters

  • actionrequired
    string
    "assign".
  • ticket_idrequired
    string
    The ticket's id.
  • assignee_idrequired
    string
    An id from List assignees, or "" to unassign.
  • request_idrequired
    UUID
    A new UUID for this action. See Idempotency.
curl -X POST \
  https://app.dskr.ai/functions/agentApi \
  -H "Authorization: Bearer $DSKR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "assign",
    "ticket_id": "6a1b2c3d4e5f60718293a4b5",
    "assignee_id": "6a4e5f60718293a4b5c6d7e8",
    "request_id": "9d2e4b6a-1c3f-4a5e-8b7d-0f2a4c6e8b1d"
  }'
Response200
{
  "ticket_id": "6a1b2c3d4e5f60718293a4b5",
  "assigned_to_id": "6a4e5f60718293a4b5c6d7e8"
}

Webhooks

Overview

dskr.ai can send an HTTPS POST to your server when something happens. In Settings → AI agents & automation, open a connection, enter your HTTPS address and choose up to 5 events. You'll get an alert secret starting with dskr_evt_, shown once.

Events

  • ticket_created
    A new ticket is opened
  • new_reply
    A new reply is added
  • status_changed
    A ticket's status changes
  • assigned
    A ticket is assigned
  • resolved
    A ticket is resolved
  • test
    You send a test from Settings

Alerts are sent only for customer-visible tickets.

Payload

Each alert is a POST with these headers and a JSON body.

Message texts and email addresses are never included. The timestamp is Unix time in seconds.

Headers
X-Dskr-Event: ticket_created
X-Dskr-Event-Id: 9f2c4a7e1b3d5f60a8c2e4b6d8f0a1c3e5b7d9f1a3c5e7b9d0f2a4c6e8b0d2f4
X-Dskr-Timestamp: 1792332000
X-Dskr-Signature: v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
Body
{
  "ticket_number": 1042,
  "subject": "Can't log in to my account",
  "status": "Open",
  "customer_name": "Acme Dental",
  "link": "https://app.dskr.ai/helpdesk/6a1b2c3d4e5f60718293a4b5"
}

Verify signatures

Always check the signature before trusting an alert:

  1. 1Join timestamp, event id, event name and the raw request body with dots.
  2. 2Compute HMAC-SHA256 of that text with your alert secret, as lowercase hex.
  3. 3Compare it with the value after v1= using a constant-time comparison.
  4. 4Reject timestamps older than 5 minutes, and event ids you've already processed.
X-Dskr-Event: ticket_created
X-Dskr-Event-Id: 9f2c4a7e1b3d5f60a8c2e4b6d8f0a1c3e5b7d9f1a3c5e7b9d0f2a4c6e8b0d2f4
X-Dskr-Timestamp: 1792332000
X-Dskr-Signature: v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

{
  "ticket_number": 1042,
  "subject": "Can't log in to my account",
  "status": "Open",
  "customer_name": "Acme Dental",
  "link": "https://app.dskr.ai/helpdesk/6a1b2c3d4e5f60718293a4b5"
}

Retries

Answer with any 2xx status within 10 seconds. Otherwise we retry after 5, 15 and 60 minutes (4 attempts in total). Redirects aren't followed. Retries keep the same X-Dskr-Event-Id, so use it to skip duplicates.

AI assistants (MCP)

Overview

dskr.ai includes an MCP server, so AI assistants can use the same actions as the API, limited to what the connection allows. There are 11 tools: list tickets, get ticket, list customers, list requesters, list assignees, create ticket, reply to customer, add internal note, change status, assign, save draft.

Claude

  1. 1In Claude, open Settings → Connectors → Add custom connector.
  2. 2Enter https://app.dskr.ai/api/mcp
  3. 3Sign in with your dskr.ai team account.
  4. 4Choose the AI connection to use and click Approve.
MCP server
https://app.dskr.ai/api/mcp

ChatGPT

  1. 1In ChatGPT, open Settings → Apps, turn on Developer mode, then Create app.
  2. 2Enter https://app.dskr.ai/api/mcp and choose OAuth.
  3. 3Sign in, choose the AI connection, and approve.
MCP server
https://app.dskr.ai/api/mcp

Key-based clients (n8n, Claude Code, custom agents)

Connect to https://app.dskr.ai/functions/agentMcp as a Streamable HTTP server with the header Authorization: Bearer dskr_agent_your_key_here. Only the tools your connection allows are listed.

Streamable HTTP
https://app.dskr.ai/functions/agentMcp

Authorization: Bearer dskr_agent_your_key_here

Resources

Security

  • Each key works for one company only, and only for the actions you tick.
  • Keys are stored hashed and shown only once. If a key leaks, delete the connection and create a new one.
  • Connections can never read internal notes, change settings, users or keys, or edit archived tickets.
  • Every action is logged in the connection's activity in Settings.

Changelog

  • October 2026: API, webhooks and MCP server launched.

Support

Questions? Email dskr@email.dskr.ai.