List tickets
GET/api/v1/tickets
Tickets in the workspace, most recently updated first. Spam, deleted and merged tickets are left out. Filter by status (or the shorthands unresolved and resolved), priority, assignee, team, contact or tag, and search subject and message text with q.
Query parameters
| Parameter | Type | Description |
|---|---|---|
status | string | A status value, or unresolved / resolved for every status in that category. |
priority | string | — |
assigneeId | string | Only tickets assigned to this user. Pass unassigned for tickets with nobody. |
teamId | string | — |
contactId | string | — |
tag | string | — |
q | string | Full-text search over subject, messages and the requester. |
limit | number | Page size, 1 to 100. Default 50. |
cursor | string | The nextCursor from the previous page. |
Example request
curl "https://crowdstack.org/api/v1/tickets?status=unresolved&priority=high" \
-H "Authorization: Bearer $CROWDSTACK_API_KEY"Example response
{
"tickets": [
{
"id": "cmf3k2x9a0100abcd",
"number": 3243,
"key": "#3243",
"subject": "Cannot export invoices",
"status": "open",
"priority": "high",
"summary": null,
"tags": [
"billing"
],
"fields": {},
"contact": {
"id": "cmf3k2x9a0001abcd",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@acme.com"
},
"assignee": {
"id": "cmf3k2x9a0003abcd",
"name": "Jane Doe",
"email": "jane@acme-mail.com"
},
"team": null,
"cc": [],
"messageCount": 2,
"sla": {
"firstReplyDueAt": "2026-09-15T14:12:00.000Z",
"resolveDueAt": "2026-09-17T10:12:00.000Z",
"firstReplyBreachedAt": null,
"resolveBreachedAt": null
},
"firstAgentReplyAt": null,
"resolvedAt": null,
"statusChangedAt": "2026-09-15T10:12:00.000Z",
"createdAt": "2026-09-15T10:12:00.000Z",
"updatedAt": "2026-09-15T10:12:00.000Z"
}
],
"nextCursor": null
}Get a ticket
GET/api/v1/tickets/:id
One ticket with its full conversation, oldest message first. Internal notes are included and flagged with isInternal. Look a ticket up by number with list_tickets and q if you only have the number.
Responses
| Status | Meaning |
|---|---|
| 404 | No ticket with that id. |
Example request
curl "https://crowdstack.org/api/v1/tickets/cmf3k2x9a0001abcd" \
-H "Authorization: Bearer $CROWDSTACK_API_KEY"Example response
{
"ticket": {
"id": "cmf3k2x9a0100abcd",
"number": 3243,
"key": "#3243",
"subject": "Cannot export invoices",
"status": "open",
"priority": "high",
"summary": null,
"tags": [
"billing"
],
"fields": {},
"contact": {
"id": "cmf3k2x9a0001abcd",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@acme.com"
},
"assignee": {
"id": "cmf3k2x9a0003abcd",
"name": "Jane Doe",
"email": "jane@acme-mail.com"
},
"team": null,
"cc": [],
"messageCount": 2,
"sla": {
"firstReplyDueAt": "2026-09-15T14:12:00.000Z",
"resolveDueAt": "2026-09-17T10:12:00.000Z",
"firstReplyBreachedAt": null,
"resolveBreachedAt": null
},
"firstAgentReplyAt": null,
"resolvedAt": null,
"statusChangedAt": "2026-09-15T10:12:00.000Z",
"createdAt": "2026-09-15T10:12:00.000Z",
"updatedAt": "2026-09-15T10:12:00.000Z",
"messages": [
{
"id": "cmf3k2x9a0110abcd",
"body": "Hi Jane, thanks for flagging this. Which date range were you exporting?",
"authorType": "agent",
"author": {
"id": "cmf3k2x9a0003abcd",
"name": "Jane Doe",
"email": "jane@acme-mail.com"
},
"isInternal": false,
"attachments": [],
"createdAt": "2026-09-15T10:20:00.000Z"
}
]
}
}Create a ticket
POST/api/v1/tickets
Opens a ticket for a customer. Identify them by contactId or by email (a contact is created if needed). By default the body is logged as the customer's message, as if they had written in; set intent to outreach to have the body sent to them as the first agent reply instead.
On-create automations and AI Responses run exactly as they do for a ticket that arrives by email, so an auto-acknowledgement may go out.
The ticket starts in the workspace's default status. Priority defaults to the workspace's default. Tags are free text; get_workspace lists suggestions.
Request body
| Field | Type | Description |
|---|---|---|
subjectrequired | string | — |
bodyrequired | string | The first message, plain text. |
contactId | string | An existing contact. Either this or email is required. |
email | string | The customer's email. A contact is created when none exists. |
firstName | string | Used only when a new contact is created. |
lastName | string | — |
intent | on_behalf | outreach | on_behalf logs the body as the customer's message. outreach sends it to the customer as the first reply. Default "on_behalf". |
priority | string | — |
assigneeId | string | null | Leave out for an unassigned ticket. |
teamId | string | null | — |
tags | string[] | — |
fields | object | Custom field values keyed by field key. Unknown keys are rejected; get_workspace lists the defined fields. |
Responses
| Status | Meaning |
|---|---|
| 201 | Body: { ticket }. |
| 422 | Neither contactId nor email given, or a value did not validate. |
Example request
curl -X POST https://crowdstack.org/api/v1/tickets \
-H "Authorization: Bearer $CROWDSTACK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@acme.com",
"firstName": "Jane",
"subject": "Cannot export invoices",
"body": "Export button does nothing on the invoices page.",
"priority": "high",
"tags": [
"billing"
]
}'Example response
{
"ticket": {
"id": "cmf3k2x9a0100abcd",
"number": 3243,
"key": "#3243",
"subject": "Cannot export invoices",
"status": "open",
"priority": "high",
"summary": null,
"tags": [
"billing"
],
"fields": {},
"contact": {
"id": "cmf3k2x9a0001abcd",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@acme.com"
},
"assignee": {
"id": "cmf3k2x9a0003abcd",
"name": "Jane Doe",
"email": "jane@acme-mail.com"
},
"team": null,
"cc": [],
"messageCount": 2,
"sla": {
"firstReplyDueAt": "2026-09-15T14:12:00.000Z",
"resolveDueAt": "2026-09-17T10:12:00.000Z",
"firstReplyBreachedAt": null,
"resolveBreachedAt": null
},
"firstAgentReplyAt": null,
"resolvedAt": null,
"statusChangedAt": "2026-09-15T10:12:00.000Z",
"createdAt": "2026-09-15T10:12:00.000Z",
"updatedAt": "2026-09-15T10:12:00.000Z"
}
}Update a ticket
PATCH/api/v1/tickets/:id
Change status, priority, assignee, team, tags, subject, summary or custom fields. Only keys you send are changed. Status, priority and assignee changes fire the workspace's on-update automations, so a move to Solved can email the customer if an automation says so.
Closed cannot be set by hand; it is applied by automation after a ticket stays Solved. Use the Solved status.
Request body
| Field | Type | Description |
|---|---|---|
subject | string | — |
status | string | A ticket status by value or label. |
priority | string | — |
assigneeId | string | null | null unassigns. |
teamId | string | null | null removes the team. |
tags | string[] | Replaces the tag set. |
addTags | string[] | — |
removeTags | string[] | — |
summary | string | null | The agent-written summary shown on the ticket. |
fields | object | Custom field values keyed by field key. Unknown keys are rejected; get_workspace lists the defined fields. |
Responses
| Status | Meaning |
|---|---|
| 200 | Body: { ticket }. |
| 404 | No ticket with that id. |
Example request
curl -X PATCH https://crowdstack.org/api/v1/tickets/cmf3k2x9a0001abcd \
-H "Authorization: Bearer $CROWDSTACK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "solved",
"addTags": [
"resolved-by-agent"
]
}'Example response
{
"ticket": {
"id": "cmf3k2x9a0100abcd",
"number": 3243,
"key": "#3243",
"subject": "Cannot export invoices",
"status": "solved",
"priority": "high",
"summary": null,
"tags": [
"billing",
"resolved-by-agent"
],
"fields": {},
"contact": {
"id": "cmf3k2x9a0001abcd",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@acme.com"
},
"assignee": {
"id": "cmf3k2x9a0003abcd",
"name": "Jane Doe",
"email": "jane@acme-mail.com"
},
"team": null,
"cc": [],
"messageCount": 2,
"sla": {
"firstReplyDueAt": "2026-09-15T14:12:00.000Z",
"resolveDueAt": "2026-09-17T10:12:00.000Z",
"firstReplyBreachedAt": null,
"resolveBreachedAt": null
},
"firstAgentReplyAt": null,
"resolvedAt": null,
"statusChangedAt": "2026-09-15T10:12:00.000Z",
"createdAt": "2026-09-15T10:12:00.000Z",
"updatedAt": "2026-09-15T10:12:00.000Z"
}
}Reply to a ticket or add a note
POST/api/v1/tickets/:id/messages
Adds a message to the ticket. A public reply is emailed to the customer by the workspace's reply automation and moves the ticket according to its reply rules; an internal note (internal: true) is visible only to the team. Optionally set the status in the same call.
Whether a public reply reaches the customer depends on the workspace's automations, exactly as it does for a reply from the inbox. If autoAssignOnReply is on and the ticket is unassigned, the member behind the key becomes the assignee.
Request body
| Field | Type | Description |
|---|---|---|
bodyrequired | string | Plain text. |
internal | boolean | true for an internal note the customer never sees. Default false. |
status | string | Set the ticket status at the same time, by value or label. |
Responses
| Status | Meaning |
|---|---|
| 201 | Body: { message, ticket }. |
| 404 | No ticket with that id. |
Example request
curl -X POST https://crowdstack.org/api/v1/tickets/cmf3k2x9a0001abcd/messages \
-H "Authorization: Bearer $CROWDSTACK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"body": "Hi Jane, thanks for flagging this. Which date range were you exporting?",
"status": "pending"
}'Example response
{
"message": {
"id": "cmf3k2x9a0110abcd",
"body": "Hi Jane, thanks for flagging this. Which date range were you exporting?",
"authorType": "agent",
"author": {
"id": "cmf3k2x9a0003abcd",
"name": "Jane Doe",
"email": "jane@acme-mail.com"
},
"isInternal": false,
"attachments": [],
"createdAt": "2026-09-15T10:20:00.000Z"
},
"ticket": {
"id": "cmf3k2x9a0100abcd",
"number": 3243,
"key": "#3243",
"subject": "Cannot export invoices",
"status": "pending",
"priority": "high",
"summary": null,
"tags": [
"billing"
],
"fields": {},
"contact": {
"id": "cmf3k2x9a0001abcd",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@acme.com"
},
"assignee": {
"id": "cmf3k2x9a0003abcd",
"name": "Jane Doe",
"email": "jane@acme-mail.com"
},
"team": null,
"cc": [],
"messageCount": 2,
"sla": {
"firstReplyDueAt": "2026-09-15T14:12:00.000Z",
"resolveDueAt": "2026-09-17T10:12:00.000Z",
"firstReplyBreachedAt": null,
"resolveBreachedAt": null
},
"firstAgentReplyAt": null,
"resolvedAt": null,
"statusChangedAt": "2026-09-15T10:12:00.000Z",
"createdAt": "2026-09-15T10:12:00.000Z",
"updatedAt": "2026-09-15T10:12:00.000Z"
}
}