Skip to content

API reference

Read and change tickets from your own code, Zapier, Make or n8n. Every plan includes the API. There are no extra charges for using it.

Authentication

An admin makes a key in Flatdesk under Integrations. Send it in the Authorization header. Requests and responses are JSON. A key can make up to 1,000 requests an hour.

curl https://flatdesk.app/api/v1/tickets?status=open \
  -H "Authorization: Bearer fd_your_key"

Errors come back as { "error": "..." } with a status code: 400 for a bad field, 401 for a missing or revoked key, 402 when the trial ended without a card (reading still works), 404, and 429 when you go too fast.

Endpoints

GET/api/v1/me

The team and key name. Use it to test a connection.

GET/api/v1/tickets

Tickets, most recently changed first.

status
open, pending or closed
updated_since
only tickets changed after this time (ISO 8601), for polling
customer_email
only this customer's tickets
tag
only tickets with this tag
limit
1 to 100, default 50

POST/api/v1/tickets

A new ticket from a customer, as if they had emailed. Your replies go to them by email. The AI answers it like any new email unless ai_answer is false.

customer_email
required
subject
required
body
required, the customer's message
customer_name
optional
tags
optional array; assignment rules apply
ai_answer
optional, default true
{
  "customer_email": "sam@example.com",
  "customer_name": "Sam Lee",
  "subject": "Order #1042 arrived damaged",
  "body": "The mug was broken when it arrived.",
  "tags": ["damaged"]
}

GET/api/v1/tickets/:number

One ticket with its whole conversation, internal notes included.

PATCH/api/v1/tickets/:number

Change the status, assignee or tags.

status
open, pending or closed
assignee_email
someone on the team, or null to unassign
tags
replaces the tags
add_tags
adds to the tags
{ "status": "closed", "add_tags": ["refunded"] }

POST/api/v1/tickets/:number/messages

Reply to the customer (emailed to them), or add an internal note. A reply sets the ticket to pending unless you send a status.

body
required
internal
true for a note only the team sees
author_email
who it's from; defaults to whoever made the key
status
open, pending or closed
{ "body": "Sorry about that, Sam. A replacement is on its way.", "status": "closed" }

GET/api/v1/customers?email=

A customer, their fields, and their tickets.

Tickets come back with number, subject, status, channel, tags, customer, assignee, answered_by_ai, url and timestamps. A ticket's messages have author_type (customer, agent, ai or system), author_name, body, internal and created_at.

Webhooks

Set a webhook address under Settings, Alerts, and choose which tickets to send: only the ones that need a person, or every new one. Slack, Discord and Google Chat addresses get a message in their own format. Any other address gets JSON like this, with event ticket.created or ticket.handed_back (a customer wrote back to an AI answer):

{
  "event": "ticket.created",
  "text": "New ticket for the team: #1042 Order #1042 arrived damaged from Sam Lee (sam@example.com) by email.",
  "needsTeam": true,
  "reason": null,
  "ticket": {
    "number": 1042,
    "subject": "Order #1042 arrived damaged",
    "channel": "email",
    "status": "open",
    "url": "https://flatdesk.app/app/tickets/1042",
    "customer": { "name": "Sam Lee", "email": "sam@example.com" },
    "assignee": null
  },
  "sentAt": "2026-10-06T09:14:00.000Z"
}

Check it came from Flatdesk with the X-Flatdesk-Signature header: sha256= followed by the HMAC-SHA256 of the raw body, keyed with the secret shown under Alerts.

Zapier, Make and n8n

  • To start a Zap when a ticket comes in, use Webhooks by Zapier, Catch Hook, and paste its address as your webhook in Flatdesk.
  • To make a ticket from another app, add a Webhooks by Zapier, POST step to /api/v1/tickets with your key in the Authorization header.
  • To catch every change, poll /api/v1/tickets?updated_since= with the newest updated_at you've seen.

All integrations