Help Desk API
Read and work your SiteSmith Help Desk tickets, customers and knowledge base from your own code.
Overview#
The Help Desk API lets your own code list, open, create and update tickets, reply to customers, add internal notes, look up customers, and read your knowledge base.
- Base URL:
https://api.sitesmith.cloud/v1/helpdesk - Bodies are JSON (
Content-Type: application/json). Responses are JSON. - Dates are ISO 8601 strings in UTC, like
2026-09-29T10:00:00.000Z. - Bodies over 256 KB are refused with
413.
Authentication#
Create a key in your help desk's agent console under Settings › API. You need a role that can manage API keys. The key is shown once, so copy it somewhere safe. Send it in the Authorization header:
curl https://api.sitesmith.cloud/v1/helpdesk/tickets \
-H "Authorization: Bearer ssh_your_key_here"A key reaches one help desk only, and acts with the permissions of the person who created it. If that person leaves the desk or the account, the key stops working.
| Scope | What it can do |
|---|---|
read | GET requests only. Anything else returns 403. |
write | Everything below. |
Errors#
Errors return a JSON body with a message, and field messages when custom field values fail validation:
{ "error": "Fill in Order number", "fieldErrors": { "fld123": "Fill in Order number" } }| Status | Meaning |
|---|---|
400 | The request is malformed (bad JSON, an unknown status, per_page over 100). |
401 | No key, or the key is wrong or revoked. |
402 | Your plan's limit is reached, or the ticket came in over the monthly limit and is held until you upgrade. |
403 | A read key tried to write, or the key's owner isn't allowed to do that. |
404 | The ticket, customer or article doesn't exist, or belongs to another desk. |
409 | The ticket is closed. Replies to closed tickets aren't allowed; open a follow-up instead. |
413 | The body is over 256 KB. |
422 | Custom field values failed validation. See fieldErrors, keyed by field id. |
429 | Too many requests. Wait the number of seconds in the Retry-After header. |
Rate limits#
Each key can make 120 requests a minute.
Tickets#
A ticket looks like this:
{
"id": "k3Jd9sQw1a",
"number": 42,
"subject": "Can't sign in",
"status": "open",
"priority": "normal",
"type": null,
"channel": "email",
"requesterId": "r8Hs2kLm0p",
"assigneeId": null,
"groupId": null,
"tags": ["login"],
"fields": {},
"ccs": [],
"followers": [],
"dueAt": null,
"firstResponseAt": null,
"solvedAt": null,
"closedAt": null,
"firstResponseDueAt": "2026-09-29T14:00:00.000Z",
"resolutionDueAt": null,
"firstResponseBreachedAt": null,
"resolutionBreachedAt": null,
"mergedIntoId": null,
"followUpOfId": null,
"spam": false,
"csatRating": null,
"createdAt": "2026-09-29T10:00:00.000Z",
"updatedAt": "2026-09-29T10:05:00.000Z"
}Statuses are new, open, pending, on_hold, solved and closed. Priorities are low, normal, high and urgent. Custom field values in fields are keyed by field id.
List tickets#
GET /tickets
| Query | Meaning |
|---|---|
view | A view id. Uses the view's filters and sort instead of the ones below. |
status | One status, or a comma list like new,open. |
priority | One priority, or a comma list. |
assignee, group, requester | An id, or none for tickets without one. |
tag | A tag. Repeat it to require several. |
updated_since | A date, like 2026-09-01. |
sort | updatedAt (default), createdAt, priority, number, status, dueAt or nextSlaAt. |
dir | desc (default) or asc. |
page | From 0. |
per_page | 1 to 100 (default 50). |
Spam, merged and held tickets are never listed.
curl "https://api.sitesmith.cloud/v1/helpdesk/tickets?status=new,open&sort=createdAt&per_page=20" \
-H "Authorization: Bearer ssh_your_key_here"{ "tickets": [ { "id": "k3Jd9sQw1a", "number": 42, "requesterName": "Ada Lovelace", "requesterEmail": "[email protected]", "assigneeName": null, "groupName": null } ], "total": 1, "page": 0, "perPage": 20, "hasMore": false }Each row is a full ticket plus requesterName, requesterEmail, assigneeName and groupName.
Get a ticket#
GET /tickets/{id}
Returns ticket, requester, org (or null), every messages entry (public replies and internal notes, oldest first), and followUpOf, mergedInto and followUps links.
List a ticket's messages#
GET /tickets/{id}/messages
Add ?kind=reply for public replies only, or ?kind=note for internal notes only.
{
"messages": [
{
"id": "m1",
"ticketId": "k3Jd9sQw1a",
"kind": "reply",
"authorKind": "requester",
"authorUserId": null,
"requesterId": "r8Hs2kLm0p",
"authorName": "Ada Lovelace",
"body": "I can't sign in since this morning.",
"html": null,
"via": "email",
"delivery": "none",
"createdAt": "2026-09-29T10:00:00.000Z",
"attachments": []
}
]
}Create a ticket#
POST /tickets (write key)
curl https://api.sitesmith.cloud/v1/helpdesk/tickets \
-H "Authorization: Bearer ssh_your_key_here" \
-H "Content-Type: application/json" \
-d '{"subject":"Refund for order 1001","body":"Hi Ada, we have started your refund.","requesterEmail":"[email protected]","requesterName":"Ada Lovelace","priority":"high","tags":["billing"]}'| Field | Notes |
|---|---|
subject, body | Required. |
requesterEmail | Required unless you send requesterId. requesterName is optional. |
firstMessage | reply (default, emailed to the customer) or note (internal). |
priority, type, status, groupId, assigneeId, tags, fields, ccs, dueAt | Optional. Required custom fields must be filled. |
Returns 201 { "ticket": { … } }. The ticket's channel is api.
Update a ticket#
PATCH /tickets/{id} (write key)
Send any of subject, status, priority, type, assigneeId, groupId, tags, fields, ccs, followers, dueAt and requesterId. null clears a value. Triggers run just as they do for an agent's change, and solving a ticket sends the satisfaction survey when it's turned on.
curl -X PATCH https://api.sitesmith.cloud/v1/helpdesk/tickets/k3Jd9sQw1a \
-H "Authorization: Bearer ssh_your_key_here" \
-H "Content-Type: application/json" \
-d '{"status":"pending","tags":["billing","refund"]}'Returns 200 { "ticket": { … } }.
Reply to the customer#
POST /tickets/{id}/replies (write key)
Body: { "body": "…", "status"?: "pending", "ccs"?: ["…"] }. The reply is emailed to the requester and anyone copied. status sets the ticket's status as the reply is sent; without it, a new ticket becomes open. Returns 201 { "message": { … }, "ticket": { … } }. Closed tickets return 409.
Add an internal note#
POST /tickets/{id}/notes (write key)
Body: { "body": "…" }. Customers never see notes. Mention an agent with <@userId> to notify them. Returns 201 { "message": { … }, "ticket": { … } }.
Customers#
List customers#
GET /requesters
Query: q (name or email), org (an organization id), limit (1 to 500, default 100).
{ "requesters": [ { "id": "r8Hs2kLm0p", "email": "[email protected]", "name": "Ada Lovelace", "orgId": null, "orgName": null, "ticketCount": 3, "blocked": false, "createdAt": "2026-09-01T09:00:00.000Z", "updatedAt": "2026-09-01T09:00:00.000Z" } ] }Get a customer#
GET /requesters/{id}
Returns { "requester": { … } }.
Create a customer#
POST /requesters (write key)
Body: { "email": "…", "name"?: "…", "orgId"?: "…" }. If a customer with that email already exists, you get that one back. Returns 201 { "requester": { … } }.
Knowledge base#
List or search articles#
GET /articles
Without a query, returns every article in knowledge base order, drafts included, each with its section and category. With ?q=, returns the best matches first, each with a rank.
{ "articles": [ { "id": "a1", "sectionId": "s1", "title": "Resetting your password", "slug": "resetting-your-password", "excerpt": "…", "status": "published", "visibility": "public", "helpfulYes": 12, "helpfulNo": 1, "views": 340, "publishedAt": "2026-09-01T09:00:00.000Z", "createdAt": "2026-09-01T09:00:00.000Z", "updatedAt": "2026-09-10T09:00:00.000Z", "rank": 0.42 } ] }visibility is public or signed_in (only signed-in customers see it in your help center).
Get an article#
GET /articles/{id}
Returns { "article": { …, "body": "<p>…</p>" } }. The body is sanitized HTML.



