Поддержка игроков
Все операции используют разрешённый documentId и требуют Authorization: Bearer <sessionId>. Внутренняя обработка и Omnidesk работают через один публичный контракт.
Портал поддержки
playerSupportPortal
Возвращает опубликованные правила формы, категории, выбранный способ обработки и текущее право игрока писать в поддержку.
Входные данные
Операция не принимает переменные.
Результат: PlayerSupportPortal!
{
"documentId": "playerSupportPortal",
"variables": {}
}
{
"data": {
"playerSupportPortal": {
"enabled": true,
"provider": "INTERNAL",
"minimumTitleLength": 5,
"maximumTitleLength": 160,
"minimumMessageLength": 10,
"maximumMessageLength": 5000,
"attachmentsEnabled": true,
"maxFileSizeMb": 10,
"maxFiles": 5,
"maxTotalSizeMb": 25,
"allowedMimeTypes": [
"image/jpeg",
"image/png",
"image/webp"
],
"writeAccess": {
"allowed": true,
"reason": null,
"expiresAt": null
},
"categories": [
{
"id": "1",
"name": "Платежи",
"icon": "ti ti-credit-card"
},
{
"id": "2",
"name": "Игровой аккаунт",
"icon": "ti ti-user"
}
]
}
}
}
Список обращений
playerSupportTickets
Возвращает обращения текущего игрока и независимую сводку. Для продолжения передайте курсор из pageInfo.
Входные данные
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
cursor | String | - | Курсор следующей или предыдущей выборки. |
limit | Int | - | Размер выборки; по умолчанию 20. |
Результат: PlayerSupportTicketConnection! и PlayerSupportTicketSummary!
{
"documentId": "playerSupportTickets",
"variables": {
"cursor": null,
"limit": 20
}
}
{
"data": {
"playerSupportTickets": {
"items": [
{
"id": "1042",
"title": "Платёж успешно проведён, баланс не изменился",
"categoryId": 1,
"status": "WAITING_FOR_STAFF",
"messagesCount": 1,
"unreadCount": 0,
"lastMessage": "Приложил чек к обращению.",
"createdAt": "2026-08-08T10:24:15Z",
"updatedAt": "2026-08-08T10:24:15Z"
}
],
"pageInfo": {
"nextCursor": "eyJpZCI6MTA0Mn0",
"previousCursor": null,
"hasMore": true
}
},
"playerSupportTicketSummary": {
"all": 3,
"waitingForPlayer": 1,
"waitingForStaff": 1,
"closed": 1
}
}
}
Обращение и сообщения
playerSupportTicket
Возвращает одно обращение текущего игрока и курсорную историю сообщений.
Входные данные
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
ticketId | ID! | ✓ | ID обращения. |
cursor | String | - | Курсор истории сообщений. |
limit | Int | - | Размер выборки; по умолчанию 50. |
Результат: PlayerSupportTicket или null
{
"documentId": "playerSupportTicket",
"variables": {
"ticketId": "1042",
"cursor": null,
"limit": 50
}
}
{
"data": {
"playerSupportTicket": {
"id": "1042",
"title": "Платёж успешно проведён, баланс не изменился",
"categoryId": 1,
"status": "WAITING_FOR_PLAYER",
"messages": {
"items": [
{
"id": "9101",
"content": "Проверили платёж. Баланс обновлён.",
"author": "STAFF",
"authorLabel": "Служба поддержки",
"redacted": false,
"deliveryState": "DELIVERED",
"feedback": null,
"feedbackAllowed": true,
"attachments": [
{
"url": "https://project.example/support/attachments/9101/original?token=short-lived",
"thumbnailUrl": "https://project.example/support/attachments/9101/thumbnail?token=short-lived"
}
],
"createdAt": "2026-08-08T11:02:41Z"
}
],
"pageInfo": {
"nextCursor": null,
"previousCursor": null,
"hasMore": false
}
},
"messagesCount": 2,
"unreadCount": 1,
"lastMessage": "Проверили платёж. Баланс обновлён.",
"createdAt": "2026-08-08T10:24:15Z",
"updatedAt": "2026-08-08T11:02:41Z"
}
}
}
Проверка доступа к обращению
playerSupportTicketAccess
Проверяет, может ли текущая сессия читать обращение перед выдачей защищённого ресурса.
Входные данные
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
ticketId | ID! | ✓ | ID обращения. |
Результат: Boolean!
{
"documentId": "playerSupportTicketAccess",
"variables": {
"ticketId": "1042"
}
}
{
"data": {
"playerSupportTicketAccess": true
}
}
Проверка доступа к сообщению
playerSupportMessageAccess
Проверяет доступ текущей сессии к сообщению перед открытием связанного вложения.
Входные данные
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
messageId | ID! | ✓ | ID сообщения. |
Результат: Boolean!
{
"documentId": "playerSupportMessageAccess",
"variables": {
"messageId": "9101"
}
}
{
"data": {
"playerSupportMessageAccess": true
}
}
Создать обращение
createPlayerSupportTicket
Идемпотентно создаёт тикет и первое сообщение. Новый пользовательский action получает новый requestId; безопасный повтор того же запроса использует прежнее значение.
Входные данные
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
input.requestId | ID! | ✓ | Уникальный ID попытки. |
input.categoryId | Int! | ✓ | ID опубликованной категории. |
input.title | String! | ✓ | Тема в пределах portal limits. |
input.message | String! | ✓ | Первое сообщение. |
input.account | String | - | Игровой аккаунт. |
input.character | String | - | Персонаж. |
input.attachmentClaim | PlayerSupportAttachmentClaimInput | - | ID и credential предварительно загруженного набора файлов. |
Результат: PlayerSupportMutationResult!
{
"documentId": "createPlayerSupportTicket",
"variables": {
"input": {
"requestId": "3a124288-6ced-4a58-9956-7ed994c419a7",
"categoryId": 1,
"title": "Платёж успешно проведён, баланс не изменился",
"message": "Прикладываю чек и номер операции.",
"account": "demo_account",
"character": "Aster",
"attachmentClaim": {
"id": "01J4Q6N8WQ4G4Q5S8YQJ6R7M2D",
"credential": "claim-capability"
}
}
}
}
{
"data": {
"createPlayerSupportTicket": {
"message": "Обращение создано.",
"ticketId": "1042",
"messageId": "9100",
"deliveryPending": false
}
}
}
Ответить на обращение
replyPlayerSupportTicket
Идемпотентно добавляет сообщение игрока в доступное незакрытое обращение.
Входные данные
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
input.requestId | ID! | ✓ | Уникальный ID попытки. |
input.ticketId | ID! | ✓ | ID обращения текущего игрока. |
input.message | String! | ✓ | Текст ответа. |
input.attachmentClaim | PlayerSupportAttachmentClaimInput | - | Необязательный набор загруженных файлов. |
Результат: PlayerSupportMutationResult!
{
"documentId": "replyPlayerSupportTicket",
"variables": {
"input": {
"requestId": "e8c00d5d-f727-4b7c-96a4-413bd8d6207c",
"ticketId": "1042",
"message": "Баланс обновился, спасибо.",
"attachmentClaim": null
}
}
}
{
"data": {
"replyPlayerSupportTicket": {
"message": "Ответ отправлен.",
"ticketId": "1042",
"messageId": "9102",
"deliveryPending": false
}
}
}
Оценить ответ сотрудника
ratePlayerSupportMessage
Сохраняет оценку конкретного ответа сотрудника в обращении текущего игрока. Оценивать можно только доставленный и не скрытый ответ команды. Повтор того же выбора не создаёт новую оценку, а другой вариант заменяет предыдущее значение.
Входные данные
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
input.messageId | ID! | ✓ | ID доступного ответа сотрудника. |
input.feedback | PlayerSupportMessageFeedback! | ✓ | HELPFUL или NOT_HELPFUL. |
Результат: PlayerSupportMessageFeedbackResult!
{
"documentId": "ratePlayerSupportMessage",
"variables": {
"input": {
"messageId": "9101",
"feedback": "HELPFUL"
}
}
}
{
"data": {
"ratePlayerSupportMessage": {
"messageId": "9101",
"feedback": "HELPFUL"
}
}
}
Публичные ошибки
Ошибки имеют extensions.category = support и безопасный extensions.code.
| Код | Значение |
|---|---|
SUPPORT_DISABLED | Раздел выключен для проекта |
BANNED | Игроку запрещены новые обращения и ответы |
RATE_LIMITED | Не истекла настроенная пауза |
INVALID_CATEGORY | Категория выключена или не существует |
TITLE_LENGTH / MESSAGE_LENGTH | Нарушены опубликованные границы длины |
TICKET_NOT_FOUND | Обращение не существует или недоступно игроку |
TICKET_CLOSED / TICKET_BANNED | Ответ запрещён состоянием обращения |
MESSAGE_NOT_FOUND | Сообщение не существует или недоступно игроку |
FEEDBACK_NOT_ALLOWED | Это сообщение нельзя оценить |
INVALID_ATTACHMENT_CLAIM | Набор файлов недействителен или принадлежит другой сессии |
ATTACHMENTS_DISABLED / TOO_MANY_ATTACHMENTS | Вложения не соответствуют правилам портала |
ATTACHMENT_SERVICE_UNAVAILABLE | Хранилище временно недоступно |
REQUEST_CONFLICT | Идемпотентный ID повторён с другим содержимым |
SENSITIVE_CONTENT | Сообщение отклонено политикой содержимого |
{
"documentId": "createPlayerSupportTicket",
"variables": {
"input": {
"requestId": "3a124288-6ced-4a58-9956-7ed994c419a7",
"categoryId": 1,
"title": "Нет",
"message": "Коротко"
}
}
}
{
"errors": [
{
"message": "Длина темы должна быть от 5 до 160 символов.",
"extensions": {
"code": "TITLE_LENGTH",
"category": "support"
}
}
],
"data": {
"createPlayerSupportTicket": null
}
}