sondahub

sondahub / Helpdesk API / Tickets

Fake tickets API

2,000 tickets from the Helpdesk API, a fake helpdesk API. A support request. Allowed status moves: open → pending | resolved; pending → open | resolved; resolved → closed | open; closed → open (reopen). Anything else answers 422.

Reads with filters, sorting, search and relations; writes that answer like a real server and stay in your session token. Same ids on every build. Free, no key, CORS open.

Connect

List
https://api.sondahub.com/v1/helpdesk/tickets
One record
https://api.sondahub.com/v1/helpdesk/tickets/{id}
OpenAPI 3
https://api.sondahub.com/v1/helpdesk/openapi.json
GraphQL
https://api.sondahub.com/v1/helpdesk/graphql
JSON file
https://api.sondahub.com/data/helpdesk/tickets.json
MCP
https://api.sondahub.com/mcp · list_records
The first three tickets
curl "https://api.sondahub.com/v1/helpdesk/tickets?limit=3"

Sample records

Records 1 to 3 of 2,000, exactly as GET /v1/helpdesk/tickets/{id} answers them. The data file holds all of them.

[
  {
    "id": 1,
    "created_at": "2026-07-24T22:23:40Z",
    "updated_at": "2026-07-31T02:08:40Z",
    "number": "HD-10001",
    "subject": "Cannot log in after password reset",
    "description": "I have already tried clearing the cache and signing in again. Here are the steps to reproduce it.",
    "status": "closed",
    "priority": "normal",
    "category": "account",
    "channel": "email",
    "customer_id": 208,
    "requester_email": "[email protected]",
    "assignee_id": 6,
    "team_id": 1,
    "tags": [],
    "first_response_at": "2026-07-25T18:32:40Z",
    "resolved_at": "2026-07-29T17:56:40Z",
    "closed_at": "2026-07-31T02:08:40Z",
    "due_at": "2026-07-25T22:23:40Z",
    "sla_breached": false,
    "satisfaction": null,
    "message_count": 3
  },
  {
    "id": 2,
    "created_at": "2026-05-09T02:21:47Z",
    "updated_at": "2026-05-15T05:38:47Z",
    "number": "HD-10002",
    "subject": "Change the email on my account",
    "description": "It happens on both my laptop and my phone.",
    "status": "closed",
    "priority": "high",
    "category": "account",
    "channel": "web",
    "customer_id": 58,
    "requester_email": "[email protected]",
    "assignee_id": 11,
    "team_id": 2,
    "tags": [
      "api"
    ],
    "first_response_at": "2026-05-10T15:35:47Z",
    "resolved_at": "2026-05-14T23:59:47Z",
    "closed_at": "2026-05-15T05:38:47Z",
    "due_at": "2026-05-12T02:21:47Z",
    "sla_breached": false,
    "satisfaction": 5,
    "message_count": 1
  },
  {
    "id": 3,
    "created_at": "2026-06-01T00:30:09Z",
    "updated_at": "2026-06-09T13:06:09Z",
    "number": "HD-10003",
    "subject": "Keyboard shortcut for new item",
    "description": "Here are the steps to reproduce it. I have already tried clearing the cache and signing in again.",
    "status": "closed",
    "priority": "normal",
    "category": "feature",
    "channel": "email",
    "customer_id": 226,
    "requester_email": "[email protected]",
    "assignee_id": 6,
    "team_id": 1,
    "tags": [],
    "first_response_at": "2026-06-01T18:53:09Z",
    "resolved_at": "2026-06-06T18:29:09Z",
    "closed_at": "2026-06-09T13:06:09Z",
    "due_at": "2026-06-04T00:30:09Z",
    "sla_breached": false,
    "satisfaction": null,
    "message_count": 4
  }
]

Fields

FieldTypeNotes
idread-onlyintAssigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.
created_atread-onlydatetimeWhen the record was created (ISO 8601, UTC).
updated_atread-onlydatetimeWhen the record last changed.
numberread-onlystring
subjectrequiredstring
descriptiontext
statusenumopen pending resolved closed
priorityenumlow normal high urgent
categoryenumbilling account bug feature howto
channelenumemail chat phone web api
customer_idrequiredint → customers
requester_emailstring
assignee_idint → agents
team_idint → teams
tagsjson string[]
first_response_atread-onlydatetime
resolved_atread-onlydatetime
closed_atread-onlydatetime
due_atdatetime
sla_breachedread-onlybool
satisfactionintCSAT given at close.
min 1, max 5
message_countread-onlyint

Relations: customer → one customer through customer_id; assignee → one agent through assignee_id; team → one team through team_id; messages → the messages whose ticket_id is this ticket. Use ?expand=customer,assignee,team,messages to embed them, or the nested routes.

Endpoints

PATCH checks the status move (open → pending | resolved; pending → open | resolved; resolved → closed | open; closed → open) and answers 422 invalid_transition otherwise; resolving and closing stamp their timestamps, assigning stamps first_response_at. Counters on the customer and agent follow.
GET/v1/helpdesk/ticketsA page, with every filter, sort, search, field and expand option.
POST/v1/helpdesk/ticketsCreate one: 201 with the record, its id, a Location header and the session token that keeps it; 422 names each field that is wrong.
GET/v1/helpdesk/tickets/{id}One record, with an ETag; If-None-Match earns a 304.
PATCH/v1/helpdesk/tickets/{id}Change the fields you send.
PUT/v1/helpdesk/tickets/{id}Replace the record; required fields must all be there.
DELETE/v1/helpdesk/tickets/{id}Answers 200 with what was removed (a real server’s 204 lives at /v1/utils/status/204); gone for the session.
GET/v1/helpdesk/tickets/{id}/customerThe customer this record points at.
GET/v1/helpdesk/tickets/{id}/assigneeThe agent this record points at.
GET/v1/helpdesk/tickets/{id}/teamThe team this record points at.
GET/v1/helpdesk/tickets/{id}/messagesIts messages, as a page with all the list options.

Try it

List with a filter
curl "https://api.sondahub.com/v1/helpdesk/tickets?status=pending&satisfaction_gte=1&expand=customer&limit=3"
One record
curl https://api.sondahub.com/v1/helpdesk/tickets/1?expand=customer
Its messages
curl "https://api.sondahub.com/v1/helpdesk/tickets/1/messages?limit=5"
Create
curl -i -X POST https://api.sondahub.com/v1/helpdesk/tickets \
  -H "Content-Type: application/json" \
  -d '{"subject":"A subject","status":"open","priority":"low","category":"billing","channel":"email","customer_id":1}'
Read it back: newest first (send the session token)
curl "https://api.sondahub.com/v1/helpdesk/tickets?sort=-id&limit=3" \
  -H "X-Sondahub-Session: THE_TOKEN_FROM_THE_CREATE"
Change one field
curl -X PATCH https://api.sondahub.com/v1/helpdesk/tickets/4 \
  -H "Content-Type: application/json" \
  -d '{"status":"pending"}'
Delete the one you created
curl -X DELETE https://api.sondahub.com/v1/helpdesk/tickets/2001 \
  -H "X-Sondahub-Session: THE_TOKEN_FROM_THE_CREATE"

Query recipes

Every list option works on tickets; these are ready to paste. All the options.

WhatRequest
Page 2, 50 at a time (of 2,000)/v1/helpdesk/tickets?page=2&limit=50
Only status = open/v1/helpdesk/tickets?status=open
Satisfaction between two values, largest first/v1/helpdesk/tickets?satisfaction_gte=1&satisfaction_lte=500&sort=-satisfaction
Newest first by created at/v1/helpdesk/tickets?sort=-created_at&limit=5
Subject contains “cannot”/v1/helpdesk/tickets?subject_like=cannot
Full-text search/v1/helpdesk/tickets?q=cannot
Only some fields/v1/helpdesk/tickets?fields=id,subject&limit=5
Embed the customer/v1/helpdesk/tickets/1?expand=customer
Its messages (nested route)/v1/helpdesk/tickets/1/messages?limit=5
Just the count/v1/helpdesk/tickets?limit=1&fields=id

GraphQL

The same tickets as the tickets query on https://api.sondahub.com/v1/helpdesk/graphql, and one ticket as ticket(id: 1). Introspection is on. More on the GraphQL API.

{
  tickets(limit: 3, sort: "-id", filter: { status: open }) {
    total
    data {
      id number subject description
      customer { name }
      messages(limit: 2) { id }
    }
  }
}
Run it
curl https://api.sondahub.com/v1/helpdesk/graphql -H "Content-Type: application/json" -d '{"query": "{ tickets(limit: 3, sort: \"-id\", filter: { status: open }) { total data { id number subject description customer { name } messages(limit: 2) { id } } } }"}'

From an AI agent (MCP)

The MCP server reaches the same rows with list_records, get_record, create_record, update_record and delete_record, and as the resource sondahub://helpdesk/tickets.

tools/call
curl https://api.sondahub.com/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_records","arguments":{"api":"helpdesk","collection":"tickets","filters":{"status":"open"},"limit":3}}}'

More in the Helpdesk API

teams (4) · agents (25) · customers (300) · messages (5,069)

The live streams, and the whole API on one page: Helpdesk API. Other worlds: fake e-commerce API, fake IoT API, fake banking API, fake social media API, fake flight booking API, fake user directory API.