Zapnoty — Helpdesk — support tickets

API Documentation

REST API for notifications via Telegram and Max. Subscribers, OTP, broadcasts, forms, helpdesk.

Helpdesk API

Ticket support system. Create tickets from customers, reply to them and manage statuses. Users are automatically subscribed to notifications when contacting support. Enable Helpdesk in project settings.

Ticket management via API

Full ticket CRUD is available over the REST API with the project API key (Bearer zn_live_…) — creation, filtered listing, conversation, status/priority changes, assignment and bulk operations. The same actions are available in the dashboard and via the MCP server for AI agents.

POST /v1/helpdesk/tickets — create ticket

Creates a ticket on behalf of a customer. Ticket number is auto-generated.

text string required

First message text

subject string

Ticket subject (optional)

channel string

Channel: telegram, max or virtual. Defaults to virtual

chat_id number

Messenger chat ID. Required for telegram/max

first_name string

Customer first name

username string

Customer username

ticket_type_id string

Ticket type UUID (from GET /v1/helpdesk/ticket-types). Optional.

POST /v1/helpdesk/tickets
Authorization: Bearer zn_live_...
{
"channel": "virtual",
"text": "Verification code not arriving",
"subject": "Login issue",
"first_name": "John",
"username": "ivan_p",
"ticket_type_id": "uuid-or-omit"
}

Response

{
"id": "550e8400-...",
"ticket_number": 42,
"status": "new",
"priority": "normal",
"channel": "virtual",
"ticket_type_id": "uuid-or-null",
"ticket_type_name": "Bug",
"created_at": "2026-03-05T12:00:00Z"
}

GET /v1/helpdesk/tickets — list tickets

Returns project tickets. Filter by status: ?status=new|in_progress|waiting|closed.

GET /v1/helpdesk/tickets?status=new&limit=50&offset=0
Authorization: Bearer zn_live_...
// filters: status (new|in_progress|waiting|closed),
// assigned_to (UUID), limit (≤100), offset

GET /v1/helpdesk/tickets/{id} — ticket details

Returns full ticket information by ID, including all messages.

POST /v1/helpdesk/tickets/{id}/reply — reply to ticket

Sends an agent reply to the ticket. Customer will receive a notification in messenger.

text string required

First message text

internal bool

true — internal note, hidden from the customer and not billed

POST /v1/helpdesk/tickets/{id}/reply
Authorization: Bearer zn_live_...
{
"text": "Check your Spam folder and request the code again",
"internal": false
}

POST /v1/helpdesk/tickets/{id}/customer-reply — virtual customer reply

Sends a reply on behalf of a virtual customer (channel=virtual). Only for tickets with virtual channel. Agents will be notified and a ticket.replied webhook will be dispatched.

text string required

First message text

PATCH /v1/helpdesk/tickets/{id}/status — change status

Changes ticket status. Allowed values: new, in_progress, waiting, closed.

status string required

New status: new, in_progress, waiting or closed

PATCH /v1/helpdesk/tickets/{id}/status
Authorization: Bearer zn_live_...
{
"status": "closed" // new | in_progress | waiting | closed
}

PATCH /v1/helpdesk/tickets/{id}/assign — assign agent

Assigns the ticket to a support agent.

assigned_to string | null

Agent UUID; null or omitted — remove the assignment

PATCH /v1/helpdesk/tickets/{id}/priority — ticket priority

Changes ticket priority. Allowed values: low, normal, high, urgent.

priority string required

Priority: low, normal, high, urgent

GET /v1/helpdesk/ticket-types — ticket types

Returns list of active ticket types for the project. Each type contains id, name, description. Use ticket_type_id when creating a ticket to classify requests. Types are configured in the dashboard (Settings → Support).

Webhook events

ticket.created — ticket created, ticket.replied — ticket replied, ticket.status_changed — status changed, ticket.assigned — agent assigned, ticket.closed — ticket closed, ticket.csat_received — CSAT rating received, ticket.unanswered_24h — ticket left unanswered.

SLA tracking (6.4.3)

The ticket response includes first_reply_at, closed_at and computed time_to_first_response_seconds, time_to_resolve_seconds. A per-project SLA report (average times, breach counts, average CSAT) is in the dashboard's Helpdesk tab.

Bulk operations (6.4.8)

POST /v1/helpdesk/tickets/bulk — an action over a list of tickets (up to 100). Fields: ticket_ids[], action (close / set_status / assign / set_priority / add_tag / remove_tag), value. Response: {affected}.

POST /v1/helpdesk/tickets/bulk
Authorization: Bearer zn_live_...
{
"ticket_ids": ["uuid-1", "uuid-2"],
"action": "set_status", // close|set_status|assign|set_priority|add_tag|remove_tag
"value": "closed"
}
// response: { "affected": 2 }

CSAT (6.4.5)

When csat_enabled is on, after a ticket is closed the customer receives a message with 1-5 buttons. The rating is stored in csat_rating and a ticket.csat_received webhook fires. Enabled in the dashboard's Helpdesk tab.

Auto-routing (6.4.9)

Rules run on ticket creation, the first matching rule applies. Condition (channel / subject_contains / text_contains / ticket_type_id) and action (assign_to / set_priority / add_tag). Configured in the dashboard.

Webhook ticket.unanswered_24h (6.4.10)

An hourly worker finds tickets in new/in_progress status where the last message is from the customer and older than the threshold (12/24/48h), and fires the webhook once. The threshold is configured in the dashboard.

POST /v1/helpdesk/request — ticket for non-subscribers

If the user isn't subscribed to the project yet, use this endpoint. The service creates a bot deeplink where the user consents to subscribe and lands directly in the ticket form.

  1. User clicks «Contact support» on your site → you call /v1/helpdesk/request and get request_id + deeplinks.
  2. Open the appropriate deeplink for the user (Telegram or Max). The bot shows project name + description and asks to subscribe.
  3. On consent the subscription is auto-created, helpdesk menu opens right away (create ticket, ticket-types, active tickets).
  4. Poll GET /v1/helpdesk/request/{request_id}/status until status=accepted — response contains subscriber_id.

Create request

channel string

Preferred channel (telegram or max). If omitted, both deeplinks are returned.

ticket_type_id string (UUID)

Optional: ticket type id for pre-selection on the ticket creation screen.

POST /v1/helpdesk/request
 
{
"channel": "telegram" // optional
}

Response

{
"request_id": "Kq9xV3mN2pT7rL8s",
"telegram_link": "https://t.me/zapnotybot?start=hdreq_Kq9xV3mN2pT7rL8s",
"max_link": "https://max.ru/zapnotybot?start=hdreq_Kq9xV3mN2pT7rL8s",
"expires_in": 900
}

Check status

Poll every 1-2s. Statuses: pending (waiting), accepted (subscribed and landed in helpdesk menu), cancelled (user tapped Cancel), expired (15 min TTL).

GET /v1/helpdesk/request/{request_id}/status
 
{
"status": "accepted", // pending | accepted | cancelled | expired
"subscriber_id": "550e8400-...",
"channel": "telegram"
}

request_id lives for 15 min. If the user is already subscribed, the bot skips the consent screen and opens helpdesk menu directly. Requires helpdesk_enabled=true and helpdesk_allow_create=true in project settings.

Helpdesk configuration via API

Module settings, SLA, ticket types, canned responses and routing rules can be changed not only in the dashboard but also via the REST API with the project API key (Bearer zn_live_…). The same operations are available to AI agents via the MCP server.

PUT /v1/helpdesk/settings — module settings: enable, welcome message, SLA, CSAT, allow_create/allow_view, unanswered threshold
GET /v1/helpdesk/sla — SLA compliance report and current thresholds
GET /v1/helpdesk/ticket-types/config — all ticket types, including disabled ones (the runtime list of enabled ones — GET /v1/helpdesk/ticket-types)
POST /v1/helpdesk/ticket-types, PUT/DELETE /v1/helpdesk/ticket-types/{type_id} — CRUD for ticket types
GET/POST /v1/helpdesk/canned-responses, PUT/DELETE /v1/helpdesk/canned-responses/{canned_id} — CRUD for canned responses
GET/POST /v1/helpdesk/routing-rules, PUT/DELETE /v1/helpdesk/routing-rules/{rule_id} — CRUD for ticket routing rules

Module settings — PUT /v1/helpdesk/settings

All fields are optional — pass only the ones you change. The helpdesk_welcome_message and helpdesk_close_message fields are objects of the form { ru, en }, not strings.

helpdesk_enabled bool

Enable/disable the helpdesk module

helpdesk_welcome_message object {ru,en}

Welcome message, a multilingual object

helpdesk_close_message object {ru,en}

Message shown when a ticket is closed, a multilingual object

sla_first_reply_hours int | null

First-reply SLA in hours, null to disable

sla_resolve_hours int | null

Resolution SLA in hours, null to disable

helpdesk_ticket_types_enabled bool

Enable ticket-type selection

helpdesk_allow_create bool

Allow subscribers to create tickets

helpdesk_allow_view bool

Allow subscribers to view their tickets

csat_enabled bool

Enable the CSAT satisfaction survey

csat_message_template string ≤1024

CSAT message text

helpdesk_unanswered_hours 12 | 24 | 48 | null

Unanswered-alert threshold, null to disable

PUT /v1/helpdesk/settings
Authorization: Bearer zn_live_...
{
"helpdesk_enabled": true,
"helpdesk_welcome_message": { "ru": "Hello! Describe your issue", "en": "Hello! Describe your issue" },
"helpdesk_close_message": { "ru": "Ticket closed. Thanks", "en": "Ticket closed. Thanks" },
"sla_first_reply_hours": 4,
"sla_resolve_hours": 24,
"helpdesk_ticket_types_enabled": true,
"helpdesk_allow_create": true,
"helpdesk_allow_view": true,
"csat_enabled": true,
"csat_message_template": "Rate our support",
"helpdesk_unanswered_hours": 24
}

Ticket type — POST/PUT /v1/helpdesk/ticket-types

name string required

Ticket type name

description string

Type description

sort_order int

Sort order in the list

enabled bool

PUT only — whether the type is enabled

POST /v1/helpdesk/ticket-types
Authorization: Bearer zn_live_...
{
"name": "Bug",
"description": "Bug reports",
"sort_order": 1
}

Canned response — POST /v1/helpdesk/canned-responses

title string required

Canned response title

text string required

Response text

shortcut string

Shortcut for quick insertion

POST /v1/helpdesk/canned-responses
Authorization: Bearer zn_live_...
{
"title": "Greeting",
"text": "Hello! How can we help?",
"shortcut": "/hi"
}

Routing rule — POST /v1/helpdesk/routing-rules

name string required

Rule name

condition object required

Trigger condition, a non-empty object

action object required

Action applied when the rule matches

order_index int

Rule application priority

POST /v1/helpdesk/routing-rules
Authorization: Bearer zn_live_...
{
"name": "Urgent bugs to manager",
"condition": { "ticket_type": "bug" },
"action": { "set_priority": "high" },
"order_index": 1
}

Related sections