Every conversation your team works is a ticket: the record of who holds it, what state it is in, how urgent it is and how it is labelled. These endpoints list and read tickets and move them through their lifecycle. Read and write the messages inside a conversation with the messages endpoints.
Endpoints
GET/ticketsList ticketsGET/tickets/{ticketId}Retrieve a ticketPATCH/tickets/{ticketId}/statusChange a ticket’s statusPATCH/tickets/{ticketId}/assignmentAssign or transfer a ticketPOST/tickets/{ticketId}/claimClaim a ticketPOST/tickets/{ticketId}/labels/{labelId}Add a label to a ticketDELETE/tickets/{ticketId}/labels/{labelId}Remove a label from a ticketPOST/tickets/bulkAct on many ticketsThe ticket object
There is no separate conversation list: the Inbox lists tickets, and each ticket carries the conversationId you pass to the messages endpoints. Fields marked as nullable are null rather than omitted.
Attributes
idintegerTicket ID. This is the ID you use in every/tickets/{ticketId}path.conversationIdintegerThe conversation the ticket belongs to. Use it with the messages endpoints.statusstringWhere the ticket stands.One of:OPENPENDINGSNOOZEDRESOLVEDCLOSEDprioritystringThe key of the ticket’s priority case:MEDIUMfor the default,P<id>for the other cases your organisation defined.subjectstringnullableShort title of the ticket, when one was set.assignedAgentIdintegernullableAgent profile ID of the person who holds the ticket.nullwhile it waits unassigned.assignedAgentNamestringnullableDisplay name of that agent.inboxIdintegernullableThe queue the ticket is routed on.teamIdintegernullableThe team the ticket belongs to, if any.channelTypestringnullableChannel the conversation arrived on, e.g.WHATSAPPorWEBCHAT.contactIdintegernullableThe contact the conversation is with.contactobjectnullableA short summary of that contact, for list screens.labelsarray<object>Labels on the ticket.lastMessagePreviewobjectnullableThe newest message, truncated to 140 characters, for the list row.unreadCountintegerContact messages since the calling agent last saw the conversation.firstUnreadMessageIdintegernullableThe first message the calling agent has not seen.mutedbooleanWhether the ticket is muted.assigneeOnlyRepliesbooleanWhether only the assignee may reply on this ticket.waitReasonstringnullableWhy the ticket is waiting for an agent, if it is.waitReasonAtstringnullableWhen that reason started.waitEstimateobjectnullableA rough wait estimate, only on Retrieve a ticket. Keys:estimatedWaitSeconds,estimateReason(NOT_ENOUGH_DATAornull),positionandassignmentsInWindow.languagestringnullableThe conversation’s dominant language:ar,en,other, ornullwhile undecided.languageSourcestringnullableWhether an agent set the language by hand.One of:DETECTEDMANUALopenedAtstringWhen the ticket was opened (ISO 8601).lastActivityAtstringnullableNewest activity on the conversation (ISO 8601).firstResponseAtstringnullableWhen the first reply went out.firstResponseDueAtstringnullableSLA deadline for the first reply.nextResponseDueAtstringnullableSLA deadline for the next reply.resolutionDueAtstringnullableSLA deadline for resolution.slaPolicyIdintegernullableThe SLA policy applied to the ticket.slaobjectThe SLA clocks. Keys:firstResponseAtRiskAt,firstResponseBreachedAt,nextResponseAtRiskAt,nextResponseBreachedAt,resolutionAtRiskAt,resolutionBreachedAt,pausedAt,paused,firstResponseRemainingSeconds,nextResponseRemainingSecondsandresolutionRemainingSeconds.closedAtstringnullableWhen the ticket was resolved or closed.snoozedUntilstringnullableWhileSNOOZED: when it wakes up.nullmeans until the customer’s next reply.csatobjectnullableThe customer’s satisfaction rating, once submitted.versionintegerBumped by every assignment, status change and reopen. Send it back asexpectedVersionwhen assigning to avoid overwriting a colleague.
{
"id": 5120,
"conversationId": 4388,
"status": "OPEN",
"priority": "MEDIUM",
"subject": null,
"assignedAgentId": 31,
"assignedAgentName": "Omar Khalil",
"inboxId": 4,
"teamId": null,
"channelType": "WHATSAPP",
"contactId": 1842,
"contact": {
"displayName": "Layla Haddad",
"avatarUrl": null
},
"labels": [
{
"id": 9,
"name": "Billing",
"color": "#e8590c",
"description": null,
"count": 12
}
],
"lastMessagePreview": {
"snippet": "مرحبا، أريد تغيير موعد الفاتورة",
"messageType": "TEXT",
"senderType": "CONTACT",
"privateNote": false,
"createdAt": "2026-11-06T09:41:12Z"
},
"unreadCount": 1,
"firstUnreadMessageId": 90417,
"muted": false,
"assigneeOnlyReplies": false,
"waitReason": null,
"waitReasonAt": null,
"language": "ar",
"languageSource": "DETECTED",
"openedAt": "2026-11-06T09:40:05Z",
"lastActivityAt": "2026-11-06T09:41:12Z",
"firstResponseAt": null,
"firstResponseDueAt": "2026-11-06T10:40:05Z",
"nextResponseDueAt": null,
"resolutionDueAt": null,
"slaPolicyId": null,
"sla": {
"firstResponseAtRiskAt": "2026-11-06T10:25:05Z",
"firstResponseBreachedAt": null,
"nextResponseAtRiskAt": null,
"nextResponseBreachedAt": null,
"resolutionAtRiskAt": null,
"resolutionBreachedAt": null,
"pausedAt": null,
"paused": false,
"firstResponseRemainingSeconds": 3540,
"nextResponseRemainingSeconds": null,
"resolutionRemainingSeconds": null
},
"closedAt": null,
"snoozedUntil": null,
"csat": null,
"version": 3
}
List tickets
Returns one page of tickets, ordered by sort. This list is cursor paginated rather than offset or keyset: pass the nextCursor of one page as cursor to get the next, and stop when it is null. Treat the cursor as opaque — never build or decode one. Filters combine with AND; status takes one status or a comma-separated list, and statuses takes the key repeated. A bad sort, dir, sla or slaClock value answers 400.
liveagent.tickets:readQuery parameters
statusstringOne status or several, comma-separated, e.g.OPEN,PENDING.statusesstringSeveral statuses, as a repeated key:statuses=OPEN&statuses=PENDING.assignedAgentIdintegerOnly tickets held by this agent.inboxIdintegerOnly tickets in this queue.teamIdintegerOnly tickets of this team.labelIdintegerOnly tickets with this label.prioritystringOnly tickets with this priority key.unassignedbooleantruereturns only tickets nobody holds.unattendedbooleantruereturns open or pending tickets that have had no first response.participatingbooleantruereturns only tickets the calling agent follows.mentionedbooleantruereturns only tickets that mention the calling agent.slastringOnly open or pending tickets at risk of, or past, an SLA deadline.One of:AT_RISKBREACHEDslaClockstringNarrowsslato one clock.One of:FIRST_RESPONSENEXT_RESPONSERESOLUTIONcreatedFromstringCreated at or after this instant (ISO 8601). Pair withcreatedTo; the range is[from, to).createdTostringCreated before this instant.resolvedFromstringResolved at or after this instant. A ticket resolved and later reopened still matches.resolvedTostringResolved before this instant.lastActivityFromstringLast activity at or after this instant.lastActivityTostringLast activity before this instant.qstringFree text over subject, contact name, phone, email and message text. A number also matches the ticket ID. Send it as typed — Arabic letter forms and phone formats are folded server-side.sortstringSort mode. Defaults toopenedAt. An unknown value is a400.One of:lastActivityAtopenedAtcreatedAtpriorityunreadFirstwaitingSincedirstringDirection. OnlylastActivityAt,openedAt,createdAtandpriorityaccept one; the other modes answer400if you send it. Defaults todescforopenedAtandlastActivityAt,ascforcreatedAtandpriority.One of:ascdesclimitintegerPage size. Defaults to50, at most100.cursorstringThenextCursorof the previous page.
Returns
200The ticket object.
Errors
- 400
INVALID_REQUESTA `sort`, `dir`, `sla` or `slaClock` value is not one of the listed ones.
curl -X GET "https://api.cx.na6iq.com/api/v1/tickets" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/tickets', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/tickets",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"items": [
{
"id": 5120,
"conversationId": 4388,
"status": "OPEN",
"priority": "MEDIUM",
"subject": null,
"assignedAgentId": 31,
"assignedAgentName": "Omar Khalil",
"inboxId": 4,
"teamId": null,
"channelType": "WHATSAPP",
"contactId": 1842,
"contact": {
"displayName": "Layla Haddad",
"avatarUrl": null
},
"labels": [
{
"id": 9,
"name": "Billing",
"color": "#e8590c",
"description": null,
"count": 12
}
],
"lastMessagePreview": {
"snippet": "مرحبا، أريد تغيير موعد الفاتورة",
"messageType": "TEXT",
"senderType": "CONTACT",
"privateNote": false,
"createdAt": "2026-11-06T09:41:12Z"
},
"unreadCount": 1,
"firstUnreadMessageId": 90417,
"muted": false,
"assigneeOnlyReplies": false,
"waitReason": null,
"waitReasonAt": null,
"language": "ar",
"languageSource": "DETECTED",
"openedAt": "2026-11-06T09:40:05Z",
"lastActivityAt": "2026-11-06T09:41:12Z",
"firstResponseAt": null,
"firstResponseDueAt": "2026-11-06T10:40:05Z",
"nextResponseDueAt": null,
"resolutionDueAt": null,
"slaPolicyId": null,
"sla": {
"firstResponseAtRiskAt": "2026-11-06T10:25:05Z",
"firstResponseBreachedAt": null,
"nextResponseAtRiskAt": null,
"nextResponseBreachedAt": null,
"resolutionAtRiskAt": null,
"resolutionBreachedAt": null,
"pausedAt": null,
"paused": false,
"firstResponseRemainingSeconds": 3540,
"nextResponseRemainingSeconds": null,
"resolutionRemainingSeconds": null
},
"closedAt": null,
"snoozedUntil": null,
"csat": null,
"version": 3
}
],
"nextCursor": null
}
Retrieve a ticket
Returns one ticket. A ticket that is still waiting for an agent also carries why, and a rough wait estimate.
liveagent.tickets:readPath parameters
ticketIdintegerrequiredThe ticket’sid.
Returns
200The ticket object.
Errors
- 404
TICKET_NOT_FOUNDNo ticket with this ID in your organisation.
curl -X GET "https://api.cx.na6iq.com/api/v1/tickets/42" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/tickets/42', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/tickets/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"id": 5120,
"conversationId": 4388,
"status": "OPEN",
"priority": "MEDIUM",
"subject": null,
"assignedAgentId": 31,
"assignedAgentName": "Omar Khalil",
"inboxId": 4,
"teamId": null,
"channelType": "WHATSAPP",
"contactId": 1842,
"contact": {
"displayName": "Layla Haddad",
"avatarUrl": null
},
"labels": [
{
"id": 9,
"name": "Billing",
"color": "#e8590c",
"description": null,
"count": 12
}
],
"lastMessagePreview": {
"snippet": "مرحبا، أريد تغيير موعد الفاتورة",
"messageType": "TEXT",
"senderType": "CONTACT",
"privateNote": false,
"createdAt": "2026-11-06T09:41:12Z"
},
"unreadCount": 1,
"firstUnreadMessageId": 90417,
"muted": false,
"assigneeOnlyReplies": false,
"waitReason": null,
"waitReasonAt": null,
"language": "ar",
"languageSource": "DETECTED",
"openedAt": "2026-11-06T09:40:05Z",
"lastActivityAt": "2026-11-06T09:41:12Z",
"firstResponseAt": null,
"firstResponseDueAt": "2026-11-06T10:40:05Z",
"nextResponseDueAt": null,
"resolutionDueAt": null,
"slaPolicyId": null,
"sla": {
"firstResponseAtRiskAt": "2026-11-06T10:25:05Z",
"firstResponseBreachedAt": null,
"nextResponseAtRiskAt": null,
"nextResponseBreachedAt": null,
"resolutionAtRiskAt": null,
"resolutionBreachedAt": null,
"pausedAt": null,
"paused": false,
"firstResponseRemainingSeconds": 3540,
"nextResponseRemainingSeconds": null,
"resolutionRemainingSeconds": null
},
"closedAt": null,
"snoozedUntil": null,
"csat": null,
"version": 3
}
Change a ticket’s status
Moves the ticket to another status and returns it. Send SNOOZED together with snoozedUntil to snooze it until a time, or with snoozedUntil: null to snooze it until the customer’s next reply.
liveagent.tickets:writePath parameters
ticketIdintegerrequiredThe ticket’sid.
Request body
statusstringrequiredThe new status.One of:OPENPENDINGSNOOZEDRESOLVEDCLOSEDsnoozedUntilstringnullableOnly withSNOOZED: when to wake the ticket (ISO 8601), ornullfor the next customer reply.
Returns
200The ticket object.
Errors
- 400
INVALID_REQUEST`status` is not one of the listed values. - 409
TICKET_TERMINALYou tried to snooze a resolved or closed ticket. - 404
TICKET_NOT_FOUNDNo ticket with this ID in your organisation.
curl -X PATCH "https://api.cx.na6iq.com/api/v1/tickets/42/status" \
-H "Authorization: Bearer $NATIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "RESOLVED"
}'
const res = await fetch('https://api.cx.na6iq.com/api/v1/tickets/42/status', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"status": "RESOLVED"
}),
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.patch(
"https://api.cx.na6iq.com/api/v1/tickets/42/status",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
json={
"status": "RESOLVED"
},
)
res.raise_for_status()
data = res.json()
{
"id": 5120,
"conversationId": 4388,
"status": "RESOLVED",
"priority": "MEDIUM",
"subject": null,
"assignedAgentId": 31,
"assignedAgentName": "Omar Khalil",
"inboxId": 4,
"teamId": null,
"channelType": "WHATSAPP",
"contactId": 1842,
"contact": {
"displayName": "Layla Haddad",
"avatarUrl": null
},
"labels": [
{
"id": 9,
"name": "Billing",
"color": "#e8590c",
"description": null,
"count": 12
}
],
"lastMessagePreview": {
"snippet": "مرحبا، أريد تغيير موعد الفاتورة",
"messageType": "TEXT",
"senderType": "CONTACT",
"privateNote": false,
"createdAt": "2026-11-06T09:41:12Z"
},
"unreadCount": 1,
"firstUnreadMessageId": 90417,
"muted": false,
"assigneeOnlyReplies": false,
"waitReason": null,
"waitReasonAt": null,
"language": "ar",
"languageSource": "DETECTED",
"openedAt": "2026-11-06T09:40:05Z",
"lastActivityAt": "2026-11-06T09:41:12Z",
"firstResponseAt": null,
"firstResponseDueAt": "2026-11-06T10:40:05Z",
"nextResponseDueAt": null,
"resolutionDueAt": null,
"slaPolicyId": null,
"sla": {
"firstResponseAtRiskAt": "2026-11-06T10:25:05Z",
"firstResponseBreachedAt": null,
"nextResponseAtRiskAt": null,
"nextResponseBreachedAt": null,
"resolutionAtRiskAt": null,
"resolutionBreachedAt": null,
"pausedAt": null,
"paused": false,
"firstResponseRemainingSeconds": 3540,
"nextResponseRemainingSeconds": null,
"resolutionRemainingSeconds": null
},
"closedAt": "2026-11-06T11:02:30Z",
"snoozedUntil": null,
"csat": null,
"version": 4
}
Assign or transfer a ticket
Hands the ticket to an agent, sends it to another queue, or takes the agent off. Name one target: assignedAgentId (that agent, in the ticket’s current queue) or inboxId (the ticket goes to that queue unassigned, keeping its SLA time and age). Send neither to unassign. An optional note is posted into the conversation as a private note. Reassigning someone else’s ticket also needs liveagent.tickets:assign; the holder may hand over their own.
liveagent.tickets:writePath parameters
ticketIdintegerrequiredThe ticket’sid.
Request body
assignedAgentIdintegernullableThe agent to hand the ticket to.nullunassigns.inboxIdintegernullableA queue to transfer the ticket to. Never combine withassignedAgentId.notestringnullableHandover note, up to 2000 characters. Posted as a private note and kept on the audit trail.expectedVersionintegerThe ticketversionyour view showed. If the ticket moved on since, the call is refused instead of overwriting.
Returns
200The ticket object.
Errors
- 400
ONE_TARGETYou named both an agent and a queue. - 400
NOTE_TOO_LONGThe handover note is over 2000 characters. - 400
TEAM_ACTION_RETIREDYou sent `teamId`. Teams no longer receive tickets; transfer to a queue instead. - 403
PERMISSION_DENIEDYou tried to reassign someone else’s ticket without `liveagent.tickets:assign`. - 404
INBOX_NOT_FOUNDNo queue with this `inboxId`. - 409
ASSIGNMENT_CHANGEDThe ticket changed since `expectedVersion`. `error.data` is `{ assignedAgentId, assignedAgentName, version }`. - 409
AGENT_AT_CAPACITYThe chosen agent has no room for another conversation. - 404
TICKET_NOT_FOUNDNo ticket with this ID in your organisation.
curl -X PATCH "https://api.cx.na6iq.com/api/v1/tickets/42/assignment" \
-H "Authorization: Bearer $NATIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"assignedAgentId": 31,
"note": "Customer asked for a callback before 5pm.",
"expectedVersion": 3
}'
const res = await fetch('https://api.cx.na6iq.com/api/v1/tickets/42/assignment', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"assignedAgentId": 31,
"note": "Customer asked for a callback before 5pm.",
"expectedVersion": 3
}),
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.patch(
"https://api.cx.na6iq.com/api/v1/tickets/42/assignment",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
json={
"assignedAgentId": 31,
"note": "Customer asked for a callback before 5pm.",
"expectedVersion": 3
},
)
res.raise_for_status()
data = res.json()
{
"id": 5120,
"conversationId": 4388,
"status": "OPEN",
"priority": "MEDIUM",
"subject": null,
"assignedAgentId": 31,
"assignedAgentName": "Omar Khalil",
"inboxId": 4,
"teamId": null,
"channelType": "WHATSAPP",
"contactId": 1842,
"contact": {
"displayName": "Layla Haddad",
"avatarUrl": null
},
"labels": [
{
"id": 9,
"name": "Billing",
"color": "#e8590c",
"description": null,
"count": 12
}
],
"lastMessagePreview": {
"snippet": "مرحبا، أريد تغيير موعد الفاتورة",
"messageType": "TEXT",
"senderType": "CONTACT",
"privateNote": false,
"createdAt": "2026-11-06T09:41:12Z"
},
"unreadCount": 1,
"firstUnreadMessageId": 90417,
"muted": false,
"assigneeOnlyReplies": false,
"waitReason": null,
"waitReasonAt": null,
"language": "ar",
"languageSource": "DETECTED",
"openedAt": "2026-11-06T09:40:05Z",
"lastActivityAt": "2026-11-06T09:41:12Z",
"firstResponseAt": null,
"firstResponseDueAt": "2026-11-06T10:40:05Z",
"nextResponseDueAt": null,
"resolutionDueAt": null,
"slaPolicyId": null,
"sla": {
"firstResponseAtRiskAt": "2026-11-06T10:25:05Z",
"firstResponseBreachedAt": null,
"nextResponseAtRiskAt": null,
"nextResponseBreachedAt": null,
"resolutionAtRiskAt": null,
"resolutionBreachedAt": null,
"pausedAt": null,
"paused": false,
"firstResponseRemainingSeconds": 3540,
"nextResponseRemainingSeconds": null,
"resolutionRemainingSeconds": null
},
"closedAt": null,
"snoozedUntil": null,
"csat": null,
"version": 4
}
Claim a ticket
“Assign to me”: the ticket becomes the caller’s only while nobody holds it. Needs liveagent.tickets:write, not :assign, so a plain agent can take unassigned work. If two people claim at once, the loser gets a 409 that names the winner in error.data.
liveagent.tickets:writePath parameters
ticketIdintegerrequiredThe ticket’sid.
Returns
200The ticket object.
Errors
- 403
NOT_AN_AGENTThe caller has no agent profile. - 409
TICKET_ALREADY_CLAIMEDSomeone else holds the ticket. `error.data` carries `assignedAgentId`, `assignedAgentName` and `version`. - 404
TICKET_NOT_FOUNDNo ticket with this ID in your organisation.
curl -X POST "https://api.cx.na6iq.com/api/v1/tickets/42/claim" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/tickets/42/claim', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.post(
"https://api.cx.na6iq.com/api/v1/tickets/42/claim",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"id": 5120,
"conversationId": 4388,
"status": "OPEN",
"priority": "MEDIUM",
"subject": null,
"assignedAgentId": 31,
"assignedAgentName": "Omar Khalil",
"inboxId": 4,
"teamId": null,
"channelType": "WHATSAPP",
"contactId": 1842,
"contact": {
"displayName": "Layla Haddad",
"avatarUrl": null
},
"labels": [
{
"id": 9,
"name": "Billing",
"color": "#e8590c",
"description": null,
"count": 12
}
],
"lastMessagePreview": {
"snippet": "مرحبا، أريد تغيير موعد الفاتورة",
"messageType": "TEXT",
"senderType": "CONTACT",
"privateNote": false,
"createdAt": "2026-11-06T09:41:12Z"
},
"unreadCount": 1,
"firstUnreadMessageId": 90417,
"muted": false,
"assigneeOnlyReplies": false,
"waitReason": null,
"waitReasonAt": null,
"language": "ar",
"languageSource": "DETECTED",
"openedAt": "2026-11-06T09:40:05Z",
"lastActivityAt": "2026-11-06T09:41:12Z",
"firstResponseAt": null,
"firstResponseDueAt": "2026-11-06T10:40:05Z",
"nextResponseDueAt": null,
"resolutionDueAt": null,
"slaPolicyId": null,
"sla": {
"firstResponseAtRiskAt": "2026-11-06T10:25:05Z",
"firstResponseBreachedAt": null,
"nextResponseAtRiskAt": null,
"nextResponseBreachedAt": null,
"resolutionAtRiskAt": null,
"resolutionBreachedAt": null,
"pausedAt": null,
"paused": false,
"firstResponseRemainingSeconds": 3540,
"nextResponseRemainingSeconds": null,
"resolutionRemainingSeconds": null
},
"closedAt": null,
"snoozedUntil": null,
"csat": null,
"version": 4
}
Add a label to a ticket
Puts an existing label on the ticket. The call has no body and answers with no content.
liveagent.tickets:writePath parameters
ticketIdintegerrequiredThe ticket’sid.labelIdintegerrequiredThe label’sid(seeGET /labels).
Returns
204The label is on the ticket.
Errors
- 404
TICKET_NOT_FOUNDNo ticket with this ID in your organisation. - 404
LABEL_NOT_FOUNDNo label with this ID in your organisation.
curl -X POST "https://api.cx.na6iq.com/api/v1/tickets/42/labels/42" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/tickets/42/labels/42', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
import os, requests
res = requests.post(
"https://api.cx.na6iq.com/api/v1/tickets/42/labels/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
Remove a label from a ticket
Takes the label off this ticket only; the label itself and its other tickets are untouched.
liveagent.tickets:writePath parameters
ticketIdintegerrequiredThe ticket’sid.labelIdintegerrequiredThe label’sid.
Returns
204The label is off the ticket.
Errors
- 404
TICKET_NOT_FOUNDNo ticket with this ID in your organisation. - 404
LABEL_NOT_FOUNDNo label with this ID in your organisation.
curl -X DELETE "https://api.cx.na6iq.com/api/v1/tickets/42/labels/42" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/tickets/42/labels/42', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
import os, requests
res = requests.delete(
"https://api.cx.na6iq.com/api/v1/tickets/42/labels/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
Act on many tickets
Runs one action across up to 100 tickets. The response is always 200, even when every ticket failed — read results for each ticket’s outcome. Only the body fields that belong to action are read: ASSIGN reads assignedAgentId, MOVE_TO_QUEUE reads inboxId and note, STATUS reads status (and snoozedUntil), PRIORITY reads priority, and ADD_LABEL / REMOVE_LABEL read labelId. ASSIGN and MOVE_TO_QUEUE additionally need liveagent.tickets:assign or the whole call is a 403.
liveagent.tickets:writeRequest body
ticketIdsarray<integer>requiredThe tickets to act on. At most 100.actionstringrequiredWhat to do to each ticket.One of:ASSIGNMOVE_TO_QUEUESTATUSPRIORITYADD_LABELREMOVE_LABELassignedAgentIdintegernullableASSIGN: the agent.nullunassigns.inboxIdintegerMOVE_TO_QUEUE: the destination queue.statusstringSTATUS: the new status.snoozedUntilstringnullableSTATUSwithSNOOZED: wake-up time.prioritystringPRIORITY: the priority key.labelIdintegerADD_LABEL/REMOVE_LABEL: the label.notestringnullableASSIGN,MOVE_TO_QUEUE: one handover note posted on every ticket.
Returns
200`processed` counts the tickets that succeeded. Each result has `ok`, and an `error` code when it failed: for example `TICKET_NOT_FOUND`, `INVALID_ACTION`, a conflict code such as `AGENT_AT_CAPACITY`, or `INTERNAL_ERROR`.
Errors
- 400
VALIDATION_FAILEDMore than 100 tickets, or a field the action needs is missing. - 400
INVALID_REQUESTUnknown `action`. - 400
INBOX_REQUIRED`MOVE_TO_QUEUE` without an `inboxId`. - 400
NOTE_TOO_LONGThe handover note is over 2000 characters. - 400
TEAM_ACTION_RETIREDYou sent `teamId` with `ASSIGN`. Teams no longer receive tickets. - 403
PERMISSION_DENIEDThe action needs `liveagent.tickets:assign` and you lack it.
curl -X POST "https://api.cx.na6iq.com/api/v1/tickets/bulk" \
-H "Authorization: Bearer $NATIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ticketIds": [
5120,
5121,
5127
],
"action": "ADD_LABEL",
"labelId": 9
}'
const res = await fetch('https://api.cx.na6iq.com/api/v1/tickets/bulk', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"ticketIds": [
5120,
5121,
5127
],
"action": "ADD_LABEL",
"labelId": 9
}),
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.post(
"https://api.cx.na6iq.com/api/v1/tickets/bulk",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
json={
"ticketIds": [
5120,
5121,
5127
],
"action": "ADD_LABEL",
"labelId": 9
},
)
res.raise_for_status()
data = res.json()
{
"processed": 3,
"results": [
{
"ticketId": 5120,
"ok": true,
"error": null
},
{
"ticketId": 5121,
"ok": true,
"error": null
},
{
"ticketId": 5127,
"ok": false,
"error": "TICKET_NOT_FOUND"
}
]
}