Tickets
Tickets are the core entity in Keme. Every player support interaction — whether it arrives via the in-game SDK, Discord, Steam, email, or the REST API — creates a ticket. This reference covers creation, retrieval, status and priority updates, assignment, resolution, and deletion.
Tickets are workspace-scoped. All write operations require a valid Authorization: Bearer header using a workspace secret key. Read operations also support read-only API keys with the tickets:read scope.
aiTriaged, aiSuggestedCategory, aiConfidence, and aiSuggestedReply fields are populated within seconds of creation and are read-only.The Ticket Object
A ticket object is returned by all endpoints that interact with individual tickets. The table below describes the full set of fields.
| Field | Type | Description |
|---|---|---|
| id | string | Unique ticket identifier. Prefix: tkt_. |
| workspaceId | string | The workspace this ticket belongs to. |
| playerId | string | The player who submitted the ticket. |
| title | string | Short summary of the issue (max 255 chars). |
| body | string | Full description of the issue. |
| status | enum | open | in_progress | resolved | closed |
| priority | enum | low | medium | high | urgent |
| category | string | Support category (e.g. billing, gameplay, account). |
| source | enum | api | sdk | discord | steam | email |
| tags | string[] | Arbitrary string labels for filtering and reporting. |
| metadata | object | Caller-defined key/value pairs (game version, platform, order IDs, etc.). |
| assigneeId | string | null | ID of the assigned support agent, or null if unassigned. |
| assignee | object | null | Expanded agent object when the ticket is fetched individually. |
| aiTriaged | boolean | Whether AI triage has completed for this ticket. |
| aiSuggestedCategory | string | null | Category recommended by the AI triage engine. |
| aiConfidence | number | null | Confidence score between 0 and 1 for the AI suggestion. |
| aiSuggestedReply | string | null | AI-drafted first reply. Only present on GET /v1/tickets/:id. |
| messages | array | Conversation thread. Only present on GET /v1/tickets/:id. |
| messageCount | number | Total number of messages in the thread. |
| createdAt | string | ISO 8601 timestamp of ticket creation. |
| updatedAt | string | ISO 8601 timestamp of the last update. |
| resolvedAt | string | null | ISO 8601 timestamp when the ticket was resolved, or null. |
| closedAt | string | null | ISO 8601 timestamp when the ticket was closed, or null. |
Status Lifecycle
Tickets move through a defined lifecycle. Valid transitions are shown below. Attempting an invalid transition returns a 422 Unprocessable Entity.
open— Initial state for all new tickets.in_progress— An agent has been assigned and is actively working the issue.resolved— The issue has been addressed. The player may re-open by replying.closed— Terminal state. The ticket is archived and cannot be re-opened via reply.
resolved for 72 hours without a player reply are automatically transitioned to closed by the Keme automation engine. This threshold is configurable per workspace.Endpoints
/v1/tickets🔒 Auth requiredCreate a new support ticket on behalf of a player. The AI triage engine will automatically categorise and draft a suggested reply within seconds of creation.
| Parameter | Type | Required | Description |
|---|---|---|---|
| workspaceId | string | Required | The workspace to create the ticket in. |
| playerId | string | Required | The ID of the player submitting the ticket. |
| title | string | Required | Short summary of the issue. Max 255 characters. |
| body | string | Required | Full description of the issue written by the player. |
| category | string | Optional | Support category (e.g. billing, gameplay, account, technical). If omitted, AI triage will suggest one. |
| priority | enum | Optional | low | medium | high | urgent. Defaults to medium. |
| source | enum | Optional | api | sdk | discord | steam | email. Defaults to api. |
| metadata | object | Optional | Arbitrary key/value pairs to attach to the ticket (game version, platform, order IDs, etc.). |
| tags | string[] | Optional | Array of string labels for filtering and reporting. |
1curl -X POST https://api.kemegames.com/v1/tickets \2 -H "Authorization: Bearer sk_live_••••••••" \3 -H "Content-Type: application/json" \4 -d '{5 "workspaceId": "ws_01HXYZ123456",6 "playerId": "plr_01HABC789012",7 "title": "Cannot access purchased DLC after update",8 "body": "After the v2.4.1 update I can no longer access the Starfall DLC I purchased last month. The content is missing from the main menu and my receipt is attached.",9 "category": "billing",10 "priority": "high",11 "source": "sdk",12 "tags": ["dlc", "billing", "v2.4.1"],13 "metadata": {14 "gameVersion": "2.4.1",15 "platform": "steam",16 "orderId": "S-98712345",17 "dlcId": "dlc_starfall_pack"18 }19 }'
1{2 "id": "tkt_01HYZA456789",3 "workspaceId": "ws_01HXYZ123456",4 "playerId": "plr_01HABC789012",5 "title": "Cannot access purchased DLC after update",6 "body": "After the v2.4.1 update I can no longer access the Starfall DLC I purchased last month. The content is missing from the main menu and my receipt is attached.",7 "status": "open",8 "priority": "high",9 "category": "billing",10 "source": "sdk",11 "tags": ["dlc", "billing", "v2.4.1"],12 "metadata": {13 "gameVersion": "2.4.1",14 "platform": "steam",15 "orderId": "S-98712345",16 "dlcId": "dlc_starfall_pack"17 },18 "assigneeId": null,19 "assignee": null,20 "aiTriaged": true,21 "aiSuggestedCategory": "billing",22 "aiConfidence": 0.94,23 "messageCount": 0,24 "createdAt": "2026-06-15T09: 12: 34.000Z",25 "updatedAt": "2026-06-15T09: 12: 34.000Z",26 "resolvedAt": null,27 "closedAt": null28}
/v1/tickets🔒 Auth requiredReturn a paginated list of tickets for a workspace. Supports filtering by status, priority, category, assignee, and player, as well as full-text search across title and body.
| Parameter | Type | Required | Description |
|---|---|---|---|
| workspaceId | string | Required | Filter results to this workspace. |
| status | enum | Optional | open | in_progress | resolved | closed. Comma-separate for multiple values. |
| priority | enum | Optional | low | medium | high | urgent. Comma-separate for multiple values. |
| category | string | Optional | Filter by support category. |
| assigneeId | string | Optional | Return only tickets assigned to this agent ID. Pass unassigned to return tickets with no assignee. |
| playerId | string | Optional | Return only tickets submitted by this player. |
| search | string | Optional | Full-text search across ticket title and body. |
| sortBy | enum | Optional | createdAt | updatedAt | priority. Defaults to createdAt. |
| order | enum | Optional | asc | desc. Defaults to desc. |
| limit | integer | Optional | Number of results per page. Min 1, max 100. Defaults to 25. |
| offset | integer | Optional | Number of records to skip for pagination. Defaults to 0. |
1curl "https://api.kemegames.com/v1/tickets?workspaceId=ws_01HXYZ123456&status=open&priority=high&sortBy=createdAt&order=desc&limit=20&offset=0" \2 -H "Authorization: Bearer sk_live_••••••••"
1{2 "data": [3 {4 "id": "tkt_01HYZA456789",5 "workspaceId": "ws_01HXYZ123456",6 "playerId": "plr_01HABC789012",7 "title": "Cannot access purchased DLC after update",8 "status": "open",9 "priority": "high",10 "category": "billing",11 "source": "sdk",12 "tags": ["dlc", "billing", "v2.4.1"],13 "assigneeId": null,14 "aiTriaged": true,15 "messageCount": 0,16 "createdAt": "2026-06-15T09: 12: 34.000Z",17 "updatedAt": "2026-06-15T09: 12: 34.000Z"18 },19 {20 "id": "tkt_01HYBX654321",21 "workspaceId": "ws_01HXYZ123456",22 "playerId": "plr_01HDEF345678",23 "title": "Matchmaking stuck in queue for 30+ minutes",24 "status": "open",25 "priority": "high",26 "category": "gameplay",27 "source": "discord",28 "tags": ["matchmaking", "lag"],29 "assigneeId": "agt_01HGHI901234",30 "aiTriaged": true,31 "messageCount": 3,32 "createdAt": "2026-06-15T08: 47: 10.000Z",33 "updatedAt": "2026-06-15T09: 01: 55.000Z"34 }35 ],36 "pagination": {37 "total": 142,38 "limit": 20,39 "offset": 0,40 "hasMore": true41 }42}
/v1/tickets/:id🔒 Auth requiredRetrieve a single ticket by ID. This endpoint returns the full ticket object including the complete message thread, expanded player and assignee objects, and the AI-suggested reply.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Required | The unique ID of the ticket (prefix: tkt_). |
1curl "https://api.kemegames.com/v1/tickets/tkt_01HYZA456789" \2 -H "Authorization: Bearer sk_live_••••••••"
1{2 "id": "tkt_01HYZA456789",3 "workspaceId": "ws_01HXYZ123456",4 "playerId": "plr_01HABC789012",5 "player": {6 "id": "plr_01HABC789012",7 "displayName": "QuantumViper",8 "email": "player@example.com",9 "platform": "steam",10 "steamId": "76561198012345678",11 "accountAge": "2y 4m",12 "lifetimeSpend": 84.97,13 "loyaltyTier": "gold"14 },15 "title": "Cannot access purchased DLC after update",16 "body": "After the v2.4.1 update I can no longer access the Starfall DLC I purchased last month. The content is missing from the main menu and my receipt is attached.",17 "status": "in_progress",18 "priority": "high",19 "category": "billing",20 "source": "sdk",21 "tags": ["dlc", "billing", "v2.4.1"],22 "metadata": {23 "gameVersion": "2.4.1",24 "platform": "steam",25 "orderId": "S-98712345",26 "dlcId": "dlc_starfall_pack"27 },28 "assigneeId": "agt_01HGHI901234",29 "assignee": {30 "id": "agt_01HGHI901234",31 "name": "Sara Chen",32 "avatarUrl": "https://cdn.kemegames.com/avatars/agt_01HGHI901234.jpg"33 },34 "aiTriaged": true,35 "aiSuggestedCategory": "billing",36 "aiConfidence": 0.94,37 "aiSuggestedReply": "Hi QuantumViper! I can see your Starfall DLC purchase from May 14. Let me verify the entitlement on our end and push a refresh to your account.",38 "messages": [39 {40 "id": "msg_01HYZB111111",41 "ticketId": "tkt_01HYZA456789",42 "authorId": "plr_01HABC789012",43 "authorType": "player",44 "body": "Still no luck, tried reinstalling the DLC already.",45 "createdAt": "2026-06-15T09: 45: 00.000Z"46 },47 {48 "id": "msg_01HYZB222222",49 "ticketId": "tkt_01HYZA456789",50 "authorId": "agt_01HGHI901234",51 "authorType": "agent",52 "body": "Thanks for trying that. I have pushed an entitlement refresh — please restart Steam and let me know if it appears.",53 "createdAt": "2026-06-15T10: 02: 17.000Z"54 }55 ],56 "messageCount": 2,57 "createdAt": "2026-06-15T09: 12: 34.000Z",58 "updatedAt": "2026-06-15T10: 02: 17.000Z",59 "resolvedAt": null,60 "closedAt": null61}
/v1/tickets/:id🔒 Auth requiredUpdate one or more fields on an existing ticket. Only the fields included in the request body are modified — this is a partial update. All fields are optional.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Required | The unique ID of the ticket to update. |
| Parameter | Type | Required | Description |
|---|---|---|---|
| status | enum | Optional | New status: open | in_progress | resolved | closed. Must follow valid lifecycle transitions. |
| priority | enum | Optional | New priority: low | medium | high | urgent. |
| assigneeId | string | Optional | Agent ID to assign the ticket to. Pass null to unassign. |
| category | string | Optional | Update the support category. |
| tags | string[] | Optional | Replace the full tags array. To clear all tags pass an empty array. |
| internalNote | string | Optional | Internal note visible only to agents — not shown to the player. |
1curl -X PATCH https://api.kemegames.com/v1/tickets/tkt_01HYZA456789 \2 -H "Authorization: Bearer sk_live_••••••••" \3 -H "Content-Type: application/json" \4 -d '{5 "status": "in_progress",6 "priority": "urgent",7 "assigneeId": "agt_01HGHI901234",8 "category": "billing",9 "tags": ["dlc", "billing", "v2.4.1", "escalated"],10 "internalNote": "Player has gold loyalty tier and $84 LTV — escalated to senior billing agent."11 }'
1{2 "id": "tkt_01HYZA456789",3 "status": "in_progress",4 "priority": "urgent",5 "category": "billing",6 "assigneeId": "agt_01HGHI901234",7 "tags": ["dlc", "billing", "v2.4.1", "escalated"],8 "updatedAt": "2026-06-15T10: 15: 00.000Z"9}
/v1/tickets/:id/assign🔒 Auth requiredAssign a ticket to a specific support agent. This is a convenience endpoint that sets the assignee and automatically transitions status to in_progress if the ticket is currently open. An optional internal note is recorded in the audit log.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Required | The unique ID of the ticket to assign. |
| Parameter | Type | Required | Description |
|---|---|---|---|
| agentId | string | Required | The ID of the agent to assign the ticket to. |
| note | string | Optional | Optional internal note explaining the assignment decision. Visible only to agents. |
1curl -X POST https://api.kemegames.com/v1/tickets/tkt_01HYZA456789/assign \2 -H "Authorization: Bearer sk_live_••••••••" \3 -H "Content-Type: application/json" \4 -d '{5 "agentId": "agt_01HGHI901234",6 "note": "Assigning to Sara — she handled the last three DLC entitlement issues this week."7 }'
1{2 "id": "tkt_01HYZA456789",3 "assigneeId": "agt_01HGHI901234",4 "assignee": {5 "id": "agt_01HGHI901234",6 "name": "Sara Chen",7 "avatarUrl": "https://cdn.kemegames.com/avatars/agt_01HGHI901234.jpg"8 },9 "status": "in_progress",10 "internalNote": "Assigning to Sara — she handled the last three DLC entitlement issues this week.",11 "updatedAt": "2026-06-15T10: 20: 00.000Z"12}
/v1/tickets/:id/resolve🔒 Auth requiredMark a ticket as resolved. Optionally include a resolution note summarising the outcome, and choose whether to send the player an automated resolution notification.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Required | The unique ID of the ticket to resolve. |
| Parameter | Type | Required | Description |
|---|---|---|---|
| resolutionNote | string | Optional | Internal summary of how the issue was resolved. Stored in the ticket record. |
| sendNotification | boolean | Optional | When true, Keme sends the player a resolution notification via their original contact channel. Defaults to true. |
1curl -X POST https://api.kemegames.com/v1/tickets/tkt_01HYZA456789/resolve \2 -H "Authorization: Bearer sk_live_••••••••" \3 -H "Content-Type: application/json" \4 -d '{5 "resolutionNote": "Pushed an entitlement refresh via Steam API. Player confirmed DLC is now accessible. No further action needed.",6 "sendNotification": true7 }'
1{2 "id": "tkt_01HYZA456789",3 "status": "resolved",4 "resolutionNote": "Pushed an entitlement refresh via Steam API. Player confirmed DLC is now accessible. No further action needed.",5 "notificationSent": true,6 "resolvedAt": "2026-06-15T11: 05: 42.000Z",7 "updatedAt": "2026-06-15T11: 05: 42.000Z"8}
/v1/tickets/:id🔒 Auth requiredPermanently delete a ticket and all associated messages, attachments, and audit events. This action cannot be undone.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Required | The unique ID of the ticket to delete. |
closed ticket is archived but its history is preserved for compliance and reporting purposes.Error Codes
All errors follow the standard Keme error envelope. The table below lists errors specific to the Tickets resource.
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | validation_error | A required field is missing or a field value is invalid. |
| 401 | unauthorized | No API key provided or the key is invalid. |
| 403 | forbidden | The API key does not have permission for this operation or workspace. |
| 404 | ticket_not_found | No ticket exists with the supplied ID in this workspace. |
| 404 | agent_not_found | The agentId supplied for assignment does not exist in this workspace. |
| 404 | player_not_found | The playerId supplied during ticket creation does not exist. |
| 409 | ticket_already_closed | Cannot update a ticket that is in the closed terminal state. |
| 422 | invalid_status_transition | The requested status change does not follow the allowed lifecycle transitions. |
| 429 | rate_limit_exceeded | Your workspace has exceeded its API rate limit. Retry after the duration in the Retry-After header. |
1{2 "error": {3 "code": "invalid_status_transition",4 "message": "Cannot transition a ticket from 'closed' to 'open'. Closed tickets are terminal.",5 "status": 422,6 "requestId": "req_01HYZZ999888"7 }8}
Rate Limits
The Tickets API is subject to workspace-level rate limits. Limits are applied per API key and reset on a rolling 60-second window.
- Starter plan: 120 requests / minute, 5,000 tickets / month
- Growth plan: 600 requests / minute, 50,000 tickets / month
- Scale plan: 3,000 requests / minute, unlimited tickets
When a rate limit is exceeded the API returns 429 Too Many Requests with a Retry-After header indicating the number of seconds to wait before retrying.