Full API reference
Every route your Shopify app can call to open tickets, send messages and keep a merchant's inbox live. Call them from your server: your API key must never reach a browser.
Base URL
https://api.wishsupport.app/v1All paths below are relative to it. Requests and responses are JSON with camelCase fields, and every time is an ISO 8601 UTC string.
Authentication
Send both headers on every request. Create a key in your space under Settings → API keys; it is shown once, so store it right away.
Authorization: Bearer <your API key>
X-Shop-Domain: acme.myshopify.comHeaders
| Name | Type | Description |
|---|---|---|
Authorizationrequired | string | Bearer and your API key. The key picks your space. |
X-Shop-Domainrequired | string | The merchant's .myshopify.com domain. Every read and write is limited to this shop. |
Set X-Shop-Domain on your server from your own authenticated Shopify session, never from user input. The key works for every shop in your space, so a shop domain taken from a request would let one merchant read another's tickets.Conventions
- Lists are paged with
cursorandlimit; pass backnextCursoruntil it isnull. - A ticket that belongs to another shop answers
404, the same as one that does not exist. - A new ticket is always accepted, even when your plan's monthly request limit is reached.
- Branch on the error
code, never onmessage.
Tickets
A ticket is one conversation between a merchant and your support team. Every route is scoped to the shop in X-Shop-Domain.
Create a ticket
https://api.wishsupport.app/v1/client/ticketsOpens a conversation and writes its first message in one call. Keep ticket.code: every later call uses it.
Body (JSON)
| Name | Type | Description |
|---|---|---|
shopNamerequired | string | 1 to 120 characters. Saved as shown at the time. |
requesterNamerequired | string | 1 to 120 characters. The person writing in. |
requesterEmailrequired | string | A valid email. Replies are emailed here when unseen. |
subjectrequired | string | 1 to 200 characters. |
message | string | Up to 5,000 characters. Required unless attachments has a file. |
attachments | UploadedAttachment[] | Up to 4 files from Upload a file, passed back unchanged. Defaults to []. |
plan | string | Up to 60 characters. The merchant's plan in your app. |
priority | number | Integer 1 to 10. Defaults to 5. |
Request
{
"shopName": "Acme Supplies",
"requesterName": "Nadia Rahman",
"requesterEmail": "nadia@acme.example",
"subject": "COD form not showing at checkout",
"message": "The form disappeared after the last update.",
"plan": "growth",
"priority": 5
}curl -X POST "https://api.wishsupport.app/v1/client/tickets" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com" \
-H "Content-Type: application/json" \
-d '{
"shopName": "Acme Supplies",
"requesterName": "Nadia Rahman",
"requesterEmail": "nadia@acme.example",
"subject": "COD form not showing at checkout",
"message": "The form disappeared after the last update.",
"plan": "growth",
"priority": 5
}'Response { ticket: Ticket, message: Message }
{
"ticket": {
"id": 1042,
"code": "TCK-A7K2P9X",
"shopDomain": "acme.myshopify.com",
"shopName": "Acme Supplies",
"requesterName": "Nadia Rahman",
"requesterEmail": "nadia@acme.example",
"subject": "COD form not showing at checkout",
"plan": "growth",
"priority": 5,
"status": "open",
"lastActivityAt": "2026-10-21T09:14:03.000Z",
"lastSenderType": "shop",
"lastMessage": {
"id": 5531,
"senderType": "shop",
"senderName": "Nadia Rahman",
"body": "The form disappeared after the last update.",
"isDeleted": false,
"createdAt": "2026-10-21T09:14:03.000Z"
},
"unread": false,
"agentSeenMessageId": 0,
"createdAt": "2026-10-21T09:14:03.000Z",
"updatedAt": "2026-10-21T09:14:03.000Z"
},
"message": {
"id": 5531,
"senderType": "shop",
"senderUserId": null,
"senderName": "Nadia Rahman",
"body": "The form disappeared after the last update.",
"attachments": [],
"isDeleted": false,
"deletedAt": null,
"deletedByType": null,
"createdAt": "2026-10-21T09:14:03.000Z"
}
}List tickets
https://api.wishsupport.app/v1/client/ticketsThis shop's conversations, newest activity first. Each row carries lastMessage, so a preview needs no extra call.
Query parameters
| Name | Type | Description |
|---|---|---|
status | 'open' | 'closed' | 'archived' | Omit for everything except archived. |
search | string | 1 to 200 characters. Matches the code, subject and message text. |
unread | '1' | Only conversations the shop has not read. |
cursor | number | nextCursor from the previous page. |
limit | number | 1 to 100. Defaults to 25. |
Request
curl -X GET "https://api.wishsupport.app/v1/client/tickets?status=open&limit=25" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com"Response { items: Ticket[], nextCursor: number | null }
{
"items": [
{
"id": 1042,
"code": "TCK-A7K2P9X",
"shopDomain": "acme.myshopify.com",
"shopName": "Acme Supplies",
"requesterName": "Nadia Rahman",
"requesterEmail": "nadia@acme.example",
"subject": "COD form not showing at checkout",
"plan": "growth",
"priority": 5,
"status": "open",
"lastActivityAt": "2026-10-21T09:14:03.000Z",
"lastSenderType": "shop",
"lastMessage": {
"id": 5531,
"senderType": "shop",
"senderName": "Nadia Rahman",
"body": "The form disappeared after the last update.",
"isDeleted": false,
"createdAt": "2026-10-21T09:14:03.000Z"
},
"unread": false,
"agentSeenMessageId": 0,
"createdAt": "2026-10-21T09:14:03.000Z",
"updatedAt": "2026-10-21T09:14:03.000Z"
}
],
"nextCursor": null
}nextCursorisnullon the last page.
Count tickets
https://api.wishsupport.app/v1/client/tickets/countsExact counts by status for tab badges, unaffected by page size.
Query parameters
| Name | Type | Description |
|---|---|---|
search | string | Narrows the counts exactly as it narrows the list. |
Request
curl -X GET "https://api.wishsupport.app/v1/client/tickets/counts" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com"Response { open, closed, archived, total, unread: number }
{
"open": 12,
"closed": 143,
"archived": 27,
"total": 182,
"unread": 3
}totalis the sum of the three statuses.unreadcounts open and closed tickets the shop has not read, and is not part oftotal.
List ticket changes
https://api.wishsupport.app/v1/client/tickets/updatesTickets whose status, priority, archive state or the shop's read state changed since a time, oldest first. Use it to catch up after a reconnect.
Query parameters
| Name | Type | Description |
|---|---|---|
sincerequired | string | ISO 8601 with an offset. Send polledAt from your last call. |
afterId | number | Send it back when the last response returned one. |
Request
curl -X GET "https://api.wishsupport.app/v1/client/tickets/updates?since=2026-10-21T09:00:00.000Z" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com"Response { items: Ticket[], deletedCodes: string[], polledAt: string, afterId: number | null }
{
"items": [
{
"id": 1042,
"code": "TCK-A7K2P9X",
"shopDomain": "acme.myshopify.com",
"shopName": "Acme Supplies",
"requesterName": "Nadia Rahman",
"requesterEmail": "nadia@acme.example",
"subject": "COD form not showing at checkout",
"plan": "growth",
"priority": 5,
"status": "open",
"lastActivityAt": "2026-10-21T09:14:03.000Z",
"lastSenderType": "shop",
"lastMessage": {
"id": 5531,
"senderType": "shop",
"senderName": "Nadia Rahman",
"body": "The form disappeared after the last update.",
"isDeleted": false,
"createdAt": "2026-10-21T09:14:03.000Z"
},
"unread": false,
"agentSeenMessageId": 0,
"createdAt": "2026-10-21T09:14:03.000Z",
"updatedAt": "2026-10-21T09:14:03.000Z"
}
],
"deletedCodes": [],
"polledAt": "2026-10-21T09:14:03.000Z",
"afterId": null
}- Drop any cached ticket whose code is in
deletedCodes. Dedupeitemsbyid.
Get a ticket
https://api.wishsupport.app/v1/client/tickets/{code}One ticket by its code.
Path parameters
| Name | Type | Description |
|---|---|---|
coderequired | string | The ticket code, for example TCK-A7K2P9X. |
Request
curl -X GET "https://api.wishsupport.app/v1/client/tickets/TCK-A7K2P9X" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com"Response Ticket
{
"id": 1042,
"code": "TCK-A7K2P9X",
"shopDomain": "acme.myshopify.com",
"shopName": "Acme Supplies",
"requesterName": "Nadia Rahman",
"requesterEmail": "nadia@acme.example",
"subject": "COD form not showing at checkout",
"plan": "growth",
"priority": 5,
"status": "open",
"lastActivityAt": "2026-10-21T09:14:03.000Z",
"lastSenderType": "shop",
"lastMessage": {
"id": 5531,
"senderType": "shop",
"senderName": "Nadia Rahman",
"body": "The form disappeared after the last update.",
"isDeleted": false,
"createdAt": "2026-10-21T09:14:03.000Z"
},
"unread": false,
"agentSeenMessageId": 0,
"createdAt": "2026-10-21T09:14:03.000Z",
"updatedAt": "2026-10-21T09:14:03.000Z"
}Close or reopen a ticket
https://api.wishsupport.app/v1/client/tickets/{code}Sets the status to closed or open. Archiving happens on its own after a quiet period.
Path parameters
| Name | Type | Description |
|---|---|---|
coderequired | string | The ticket code, for example TCK-A7K2P9X. |
Body (JSON)
| Name | Type | Description |
|---|---|---|
statusrequired | 'open' | 'closed' | The new status. |
Request
{
"status": "closed"
}curl -X PATCH "https://api.wishsupport.app/v1/client/tickets/TCK-A7K2P9X" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com" \
-H "Content-Type: application/json" \
-d '{
"status": "closed"
}'Response Ticket
{
"id": 1042,
"code": "TCK-A7K2P9X",
"shopDomain": "acme.myshopify.com",
"shopName": "Acme Supplies",
"requesterName": "Nadia Rahman",
"requesterEmail": "nadia@acme.example",
"subject": "COD form not showing at checkout",
"plan": "growth",
"priority": 5,
"status": "closed",
"lastActivityAt": "2026-10-21T09:14:03.000Z",
"lastSenderType": "shop",
"lastMessage": {
"id": 5531,
"senderType": "shop",
"senderName": "Nadia Rahman",
"body": "The form disappeared after the last update.",
"isDeleted": false,
"createdAt": "2026-10-21T09:14:03.000Z"
},
"unread": false,
"agentSeenMessageId": 0,
"createdAt": "2026-10-21T09:14:03.000Z",
"updatedAt": "2026-10-21T09:14:03.000Z"
}Mark as read
https://api.wishsupport.app/v1/client/tickets/{code}/readMarks the conversation read for the shop. Call it when the merchant actually opens the thread; it also stops the unseen-reply email.
Path parameters
| Name | Type | Description |
|---|---|---|
coderequired | string | The ticket code, for example TCK-A7K2P9X. |
Body (JSON)
| Name | Type | Description |
|---|---|---|
upToMessageId | number | A message on this ticket. Omit to mark everything read. |
Request
{
"upToMessageId": 5531
}curl -X POST "https://api.wishsupport.app/v1/client/tickets/TCK-A7K2P9X/read" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com" \
-H "Content-Type: application/json" \
-d '{
"upToMessageId": 5531
}'Response Ticket
{
"id": 1042,
"code": "TCK-A7K2P9X",
"shopDomain": "acme.myshopify.com",
"shopName": "Acme Supplies",
"requesterName": "Nadia Rahman",
"requesterEmail": "nadia@acme.example",
"subject": "COD form not showing at checkout",
"plan": "growth",
"priority": 5,
"status": "open",
"lastActivityAt": "2026-10-21T09:14:03.000Z",
"lastSenderType": "shop",
"lastMessage": {
"id": 5531,
"senderType": "shop",
"senderName": "Nadia Rahman",
"body": "The form disappeared after the last update.",
"isDeleted": false,
"createdAt": "2026-10-21T09:14:03.000Z"
},
"unread": false,
"agentSeenMessageId": 0,
"createdAt": "2026-10-21T09:14:03.000Z",
"updatedAt": "2026-10-21T09:14:03.000Z"
}- The marker only moves forward, so the call is safe to retry.
Mark as unread
https://api.wishsupport.app/v1/client/tickets/{code}/readMarks the conversation unread again, from your support team's newest reply.
Path parameters
| Name | Type | Description |
|---|---|---|
coderequired | string | The ticket code, for example TCK-A7K2P9X. |
Request
curl -X DELETE "https://api.wishsupport.app/v1/client/tickets/TCK-A7K2P9X/read" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com"Response Ticket
{
"id": 1042,
"code": "TCK-A7K2P9X",
"shopDomain": "acme.myshopify.com",
"shopName": "Acme Supplies",
"requesterName": "Nadia Rahman",
"requesterEmail": "nadia@acme.example",
"subject": "COD form not showing at checkout",
"plan": "growth",
"priority": 5,
"status": "open",
"lastActivityAt": "2026-10-21T09:14:03.000Z",
"lastSenderType": "shop",
"lastMessage": {
"id": 5531,
"senderType": "shop",
"senderName": "Nadia Rahman",
"body": "The form disappeared after the last update.",
"isDeleted": false,
"createdAt": "2026-10-21T09:14:03.000Z"
},
"unread": true,
"agentSeenMessageId": 0,
"createdAt": "2026-10-21T09:14:03.000Z",
"updatedAt": "2026-10-21T09:14:03.000Z"
}Messages
The messages inside one ticket. Messages you send are recorded as sent by the shop.
Read a thread
https://api.wishsupport.app/v1/client/tickets/{code}/messagesWith no cursor, the newest page, newest first. With afterId, only new messages, oldest first.
Path parameters
| Name | Type | Description |
|---|---|---|
coderequired | string | The ticket code, for example TCK-A7K2P9X. |
Query parameters
| Name | Type | Description |
|---|---|---|
beforeId | number | Older history before this message. Not with afterId. |
afterId | number | New messages after this id. Send 0 for an empty thread. |
afterDeletionId | number | Deletions after this cursor. Needs afterId. |
limit | number | 1 to 100. Defaults to 50. |
Request
curl -X GET "https://api.wishsupport.app/v1/client/tickets/TCK-A7K2P9X/messages?afterId=5530&afterDeletionId=0" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com"Response { items: Message[], deletions: Message[], messageCursor: number, deletionCursor: number }
{
"items": [
{
"id": 5531,
"senderType": "shop",
"senderUserId": null,
"senderName": "Nadia Rahman",
"body": "The form disappeared after the last update.",
"attachments": [],
"isDeleted": false,
"deletedAt": null,
"deletedByType": null,
"createdAt": "2026-10-21T09:14:03.000Z"
}
],
"deletions": [],
"messageCursor": 5531,
"deletionCursor": 0
}- Replace a message you hold with its entry in
deletions; never remove the row.
Send a message
https://api.wishsupport.app/v1/client/tickets/{code}/messagesAdds a message from the merchant. Sending to an archived ticket reopens it; a closed ticket must be reopened first.
Path parameters
| Name | Type | Description |
|---|---|---|
coderequired | string | The ticket code, for example TCK-A7K2P9X. |
Body (JSON)
| Name | Type | Description |
|---|---|---|
body | string | Up to 5,000 characters. Required unless attachments has a file. |
attachments | UploadedAttachment[] | Up to 4 files from Upload a file. Defaults to []. |
Request
{
"body": "Here is a screenshot of the checkout page.",
"attachments": [
{
"url": "https://files.example.com/acme.myshopify.com/TCK-A7K2P9X/screenshot.png",
"filename": "screenshot.png",
"mimeType": "image/png",
"sizeBytes": 182044
}
]
}curl -X POST "https://api.wishsupport.app/v1/client/tickets/TCK-A7K2P9X/messages" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com" \
-H "Content-Type: application/json" \
-d '{
"body": "Here is a screenshot of the checkout page.",
"attachments": [
{
"url": "https://files.example.com/acme.myshopify.com/TCK-A7K2P9X/screenshot.png",
"filename": "screenshot.png",
"mimeType": "image/png",
"sizeBytes": 182044
}
]
}'Response Message
{
"id": 5534,
"senderType": "shop",
"senderUserId": null,
"senderName": "Nadia Rahman",
"body": "Here is a screenshot of the checkout page.",
"attachments": [
{
"url": "https://files.example.com/acme.myshopify.com/TCK-A7K2P9X/screenshot.png",
"filename": "screenshot.png",
"mimeType": "image/png",
"sizeBytes": 182044
}
],
"isDeleted": false,
"deletedAt": null,
"deletedByType": null,
"createdAt": "2026-10-21T09:14:03.000Z"
}Delete a message
https://api.wishsupport.app/v1/client/tickets/{code}/messages/{messageId}Deletes one of the shop's own messages. It stays in the thread as a deleted message, so render isDeleted.
Path parameters
| Name | Type | Description |
|---|---|---|
coderequired | string | The ticket code, for example TCK-A7K2P9X. |
messageIdrequired | number | The message to delete. |
Request
curl -X DELETE "https://api.wishsupport.app/v1/client/tickets/TCK-A7K2P9X/messages/5531" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com"Response No content
No body- A message from your support team cannot be deleted here:
403 MESSAGE_NOT_DELETABLE.
Files
Upload first, then pass what the upload returns in attachments when you create a ticket or send a message.
Upload a file
https://api.wishsupport.app/v1/client/attachmentsUploads one file as multipart/form-data with a single file part.
Query parameters
| Name | Type | Description |
|---|---|---|
ticketCode | string | The ticket the file belongs to, when it already exists. |
Form data
| Name | Type | Description |
|---|---|---|
filerequired | file | Up to 10 MB, images up to 5 MB. PNG, JPEG, GIF, WebP, PDF, text, CSV, ZIP, GZIP, TAR or 7z. |
Request
curl -X POST "https://api.wishsupport.app/v1/client/attachments?ticketCode=TCK-A7K2P9X" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com" \
-F "file=@screenshot.png"Response UploadedAttachment
{
"url": "https://files.example.com/acme.myshopify.com/TCK-A7K2P9X/screenshot.png",
"filename": "screenshot.png",
"mimeType": "image/png",
"sizeBytes": 182044
}- File URLs are public but unguessable; do not treat them as private.
Live updates
A WebSocket delivers new messages and ticket changes in under a second, with the same objects these routes return.
Create a socket ticket
https://api.wishsupport.app/v1/client/socket-ticketsA single-use credential that lets a browser open the WebSocket without ever holding your API key. Mint it on your server and pass it to the page.
Request
curl -X POST "https://api.wishsupport.app/v1/client/socket-tickets" \
-H "Authorization: Bearer $WISHSUPPORT_API_KEY" \
-H "X-Shop-Domain: acme.myshopify.com"Response { ticket: string, expiresAt: string }
{
"ticket": "k3J9xQ2mZ7bR4tY8wP1sV6nL",
"expiresAt": "2026-10-21T09:15:03.000Z"
}- Connect with
wss://api.wishsupport.app/v1/client/socket?ticket=<ticket>within 60 seconds. Your server can connect with the same two headers instead.
Connect to the WebSocket
Your server connects with the same two headers. A browser connects with a socket ticket instead, so it never holds the key. It is a plain WebSocket, not socket.io.
import WebSocket from 'ws';
const socket = new WebSocket('wss://api.wishsupport.app/v1/client/socket', {
headers: {
Authorization: `Bearer ${process.env.WISHSUPPORT_API_KEY}`,
'X-Shop-Domain': 'acme.myshopify.com',
},
});// Your server mints a ticket with POST /client/socket-tickets, then your page connects:
const socket = new WebSocket(`wss://api.wishsupport.app/v1/client/socket?ticket=${ticket}`);Frames you send
{ "op": "subscribe", "ticket": "TCK-A7K2P9X" }
{ "op": "unsubscribe", "ticket": "TCK-A7K2P9X" }
{ "op": "ping" }Every message and ticket change for the shop arrives without subscribing. Subscribe to the thread a merchant has open, and again after every reconnect. Send aping every 30 seconds and treat a missing socket.pong as a dead connection.
Frames you receive
{
"event": "message.created",
"at": "2026-10-21T09:14:03.000Z",
"ticket": "TCK-A7K2P9X",
"data": {
"id": 5532,
"senderType": "agent",
"body": "We have shipped a fix."
}
}| Event | data | Means |
|---|---|---|
message.created | Message | A new message on a ticket, from either side. |
message.deleted | Message | A message was deleted. Replace your copy; keep the row. |
ticket.created | Ticket | A new conversation for this shop. |
ticket.updated | Ticket | Status, priority, preview or unread changed. |
ticket.archived | Ticket | The ticket was archived after a quiet period. |
ticket.read | Ticket | The shop's own read marker moved, for example from another tab. |
ticket.seen | Ticket | Your support team read the merchant's messages up to agentSeenMessageId. |
Delivery is at most once. After every reconnect, catch up with Read a thread using afterId andList ticket changes, then subscribe again. Dedupe by id: your own writes echo back as events.
Objects
Ticket
Returned by every ticket route and carried by ticket events.
Fields
| Name | Type | Description |
|---|---|---|
id | number | Use code in URLs. |
code | string | For example TCK-A7K2P9X. |
shopDomain | string | |
shopName | string | As sent when the ticket was created. |
requesterName | string | As sent when the ticket was created. |
requesterEmail | string | |
subject | string | |
plan | string | null | |
priority | number | 1 to 10. Your support team may change it. |
status | 'open' | 'closed' | 'archived' | |
lastActivityAt | string | The list is sorted by this. |
lastSenderType | 'shop' | 'agent' | null | shop means the merchant is waiting for a reply. |
lastMessage | LastMessage | null | The newest message, its body cut to 200 characters. |
unread | boolean | The shop has not read your support team's newest reply. |
agentSeenMessageId | number | The newest merchant message your support team has seen. |
createdAt | string | |
updatedAt | string |
LastMessage
The preview on every Ticket.
Fields
| Name | Type | Description |
|---|---|---|
id | number | |
senderType | 'shop' | 'agent' | 'system' | |
senderName | string | The name shown when it was sent. |
body | string | Up to 200 characters. Empty when deleted or files only. |
isDeleted | boolean | |
createdAt | string |
Message
One message in a thread.
Fields
| Name | Type | Description |
|---|---|---|
id | number | Also the thread cursor. |
senderType | 'shop' | 'agent' | 'system' | Show system as a status line, not a bubble. |
senderUserId | number | null | null for shop and system messages. |
senderName | string | The name shown when it was sent. |
body | string | Empty when deleted or files only. |
attachments | UploadedAttachment[] | |
isDeleted | boolean | Keep the row and show it as deleted. |
deletedAt | string | null | |
deletedByType | 'user' | 'client' | null | user is your support team, client is the shop. |
createdAt | string |
UploadedAttachment
What an upload returns, and what a message carries.
Fields
| Name | Type | Description |
|---|---|---|
url | string | A public, unguessable URL. |
filename | string | |
mimeType | string | |
sizeBytes | number |
Errors
Every failure returns the same shape. Validation failures add details. Quote requestId when you contact support.
{
"statusCode": 409,
"code": "TICKET_CLOSED",
"message": "This ticket is closed.",
"requestId": "01JAC7Q2V8T3M5N9P4R6S2W1XY"
}| Code | HTTP | What to do |
|---|---|---|
VALIDATION_ERROR | 400 | A bad body or query, or a missing X-Shop-Domain. Read details. |
UNAUTHORIZED | 401 | A missing, unknown or revoked key. Do not retry. |
MESSAGE_NOT_DELETABLE | 403 | Not the shop's own message. |
NOT_FOUND | 404 | No such ticket for this shop. Another shop's ticket answers the same. |
TICKET_CLOSED | 409 | Reopen the ticket before sending. |
ATTACHMENT_TOO_LARGE | 413 | The file is over the size limit. |
ATTACHMENT_TYPE_REJECTED | 400 | The file type is not accepted. |
RATE_LIMIT_EXCEEDED | 429 | Back off and retry with jitter. |
INTERNAL_ERROR | 500 | Safe to retry once. Keep the requestId. |
Limits
| Limit | Value |
|---|---|
| Requests per API key | 10 per second |
| Requests per IP address | 60 per second |
| Message body | 5,000 characters |
| Files per message | 4 |
| File size | 10 MB, images 5 MB |
| Page size | Up to 100 |
| WebSocket connections per key and shop | 10 |
| Socket ticket lifetime | 60 seconds, single use |