Skip to main content

Support Tickets

Create, filter, assign and move support tickets through their lifecycle, with server-managed response and resolution stamps.

Overview

A ticket is one unit of support work. It can stand alone, or hang off a conversation and a contact so an agent sees the thread that produced it.

The lifecycle timestamps — first_responded_at, resolved_at, closed_at, reopened_count — are server-managed. You never send them; you change status and the API stamps the rest. That is what makes the SLA endpoints and CSAT reporting trustworthy.

Authentication

Authorization: Bearer cm_your_api_key
OperationScope
List, get, list commentssupport_tickets:read
Create, update, assign, status, delete, add commentsupport_tickets:write

Enumerations

FieldValues
statusopen, pending, waiting_on_customer, resolved, closed
prioritylow, normal, high, urgent

resolved and closed are the terminal statuses; the other three are active.

The ticket object

{
  "id": "e5d4…",
  "tenant_id": "a0b1…",
  "conversation_id": "c0ff…",
  "contact_id": "4411…",
  "subject": "Refund not received",
  "description": "Customer says the refund has not landed after 7 days.",
  "status": "open",
  "priority": "high",
  "assignee_user_id": null,
  "tags": ["billing", "refund"],
  "first_responded_at": null,
  "resolved_at": null,
  "closed_at": null,
  "reopened_count": 0,
  "created_at": "2026-08-17T06:10:00Z",
  "updated_at": "2026-08-17T06:10:00Z"
}
FieldTypeNotes
assignee_user_idUUID | nullnull means the ticket is in the unassigned queue
tagsstring[] | nullTrimmed, blanks dropped, de-duplicated, order preserved
first_responded_atdatetime | nullStamped once, the first time the ticket leaves open. Never re-stamped
resolved_atdatetime | nullStamped on the move to resolved
closed_atdatetime | nullStamped on the move to closed
reopened_countintegerIncremented each time a terminal ticket returns to an active status

GET /api/v1/support/tickets

Returns an array of ticket objects, newest first.

ParameterTypeRequiredConstraints
statusstringNoOne of the five statuses
prioritystringNoOne of the four priorities
assignee_user_idUUIDNoOne agent's queue
contact_idUUIDNo
conversation_idUUIDNo
unassignedbooleanNotrue = no assignee, false = has one. Cannot be combined with assignee_user_id
qstringNoAt most 255 characters. Case-insensitive substring on subject
limitintegerNo1 <= limit <= 200, default 50
offsetintegerNo0 <= offset <= 100000, default 0
curl "https://api.callmissed.com/api/v1/support/tickets?status=open&unassigned=true&limit=50" \
  -H "Authorization: Bearer cm_your_api_key"

Sending both unassigned=true and assignee_user_id returns 422 unassigned=true cannot be combined with assignee_user_id — the two contradict each other, so the API refuses rather than silently picking one.

POST /api/v1/support/tickets

FieldTypeRequiredConstraints
subjectstringYes1–255 characters, not blank
descriptionstringNoAt most 20,000 characters
conversation_idUUIDNoMust exist in your tenant
contact_idUUIDNoMust exist in your tenant
assignee_user_idUUIDNoMust be a user in your tenant
statusstringNoDefault open
prioritystringNoDefault normal
tagsstring[]NoAt most 20 tags, each at most 64 characters
curl -X POST https://api.callmissed.com/api/v1/support/tickets \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Refund not received",
    "description": "Customer says the refund has not landed after 7 days.",
    "conversation_id": "c0ffee00-1111-2222-3333-444455556666",
    "priority": "high",
    "tags": ["billing", "refund"]
  }'

Returns 201. Creating a ticket directly as resolved or closed stamps the matching timestamp immediately.

Your active routing rules run on create, first match wins: a matching rule fills in assignee_user_id only when you sent none, sets priority only when you sent none, and adds its tags to yours. Values you send always win.

404 Conversation not found / Contact not found / Assignee not found when a linked id is not in your tenant.

GET /api/v1/support/tickets/{ticket_id}

One ticket. 404 Ticket not found.

curl https://api.callmissed.com/api/v1/support/tickets/{ticket_id} \
  -H "Authorization: Bearer cm_your_api_key"

PATCH /api/v1/support/tickets/{ticket_id}

Accepts the same editable fields as create. The lifecycle timestamps and reopened_count are not accepted — a status change here runs the same transition rules as the dedicated status endpoint.

Every field is optional; only the fields you send are changed. Linked ids (conversation_id, contact_id, assignee_user_id) are checked against your tenant exactly as on create. Returns the updated ticket.

curl -X PATCH https://api.callmissed.com/api/v1/support/tickets/{ticket_id} \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "priority": "urgent", "tags": ["billing", "escalated"] }'

subject sent as blank or null returns 422 subject must not be blank. An explicit null for status or priority is ignored rather than written.

POST /api/v1/support/tickets/{ticket_id}/assign

FieldTypeRequiredNotes
assignee_user_idUUID | nullNonull (or omitted) unassigns and returns the ticket to the queue
curl -X POST https://api.callmissed.com/api/v1/support/tickets/{ticket_id}/assign \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "assignee_user_id": "b1f2c3d4-1111-2222-3333-444455556666" }'

Returns the updated ticket. 404 Assignee not found when the user is not in your tenant.

POST /api/v1/support/tickets/{ticket_id}/status

FieldTypeRequiredConstraints
statusstringYesOne of the five statuses
curl -X POST https://api.callmissed.com/api/v1/support/tickets/{ticket_id}/status \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "status": "resolved" }'

Returns the updated ticket. Idempotent. Sending the status the ticket already has returns it untouched — no re-stamp, no reopened_count increment. Safe to retry.

Transition rules

MoveEffect
Same statusNo-op
→ resolvedStamps resolved_at if unset, clears closed_at
→ closedStamps closed_at, leaves resolved_at alone
Terminal → activeClears both stamps, reopened_count += 1
Leaving open for the first timeStamps first_responded_at once

A logged reply (see comments) also stamps first_responded_at if nothing has yet.

GET /api/v1/support/tickets/{ticket_id}/comments

The ticket's thread — internal notes and logged replies — oldest first.

ParameterTypeRequiredConstraints
limitintegerNo1–200, default 100
offsetintegerNo0–100000, default 0
curl https://api.callmissed.com/api/v1/support/tickets/{ticket_id}/comments \
  -H "Authorization: Bearer cm_your_api_key"
[
  {
    "id": "9a1c…",
    "ticket_id": "e5d4…",
    "author_user_id": "b1f2…",
    "body": "Refund re-issued, reference RF-2210.",
    "is_internal": false,
    "created_at": "2026-08-17T07:02:00Z"
  }
]

author_user_id is null for entries added with an API key. 404 Ticket not found.

POST /api/v1/support/tickets/{ticket_id}/comments

FieldTypeRequiredConstraints
bodystringYes1–20000 characters, not blank
is_internalbooleanNoDefault true. true is a team-only note; false records a reply the customer was given

A comment is recorded on the ticket only — nothing is sent to the customer. The first entry with is_internal: false stamps first_responded_at if it is still unset; internal notes never do.

curl -X POST https://api.callmissed.com/api/v1/support/tickets/{ticket_id}/comments \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "body": "Refund re-issued, reference RF-2210.", "is_internal": false }'

Returns 201 with the comment. 404 Ticket not found, 422 for a blank body.

DELETE /api/v1/support/tickets/{ticket_id}

Returns 204. 404 Ticket not found.

curl -X DELETE https://api.callmissed.com/api/v1/support/tickets/{ticket_id} \
  -H "Authorization: Bearer cm_your_api_key"

Errors

StatusWhen
403Key is missing support_tickets:read / support_tickets:write
404Ticket, conversation, contact or assignee is not in your tenant
422Unknown status/priority, blank subject, more than 20 tags or a tag over 64 characters, or unassigned combined with assignee_user_id

Nothing on this page consumes credits.