Developers
Growth Dept Helpdesk API
Contents
Using the API
Resources
- Account9
- Tickets15
- Messages7
- Customers19
- Users16
- API keys3
- Teams8
- Tags8
- Macros8
- Rules8
- Views14
- Custom fields5
- Satisfaction surveys4
- Integrations9
- Contact forms6
- Events2
- Widgets5
- Jobs5
- Files3
- Search2
- Statistics3
- Metric cards3
- Voice calls7
- Reference1
- AI10
- AI Agent41
- AI Journey19
- Assistant15
- Automation3
- Business hours14
- Calls and texts billing6
- Chat24
- Flows5
- Help center21
- Imports8
- Onsite campaigns11
- Order management2
- Phone numbers7
- Shopify30
- SLA policies5
- SMS13
- Voice18
- Voice of Customer5
The REST API reads and changes everything in a helpdesk: tickets and their messages, customers, agents, teams, tags, macros, rules, views, fields, satisfaction surveys, integrations and events. It takes and returns JSON over HTTPS. Every request acts in one helpdesk, the one its API key belongs to.
The helpdesk's own pages call these same endpoints, so anything an agent can do on screen, a script with a key can do too, within the agent's role.
| Base URL | https://cs.growthdept.ai/api |
| Format | JSON. Send Content-Type: application/json on writes. |
| Times | ISO 8601 in UTC, in fields ending in _datetime. |
| Ids | Integers. Paths ending in a slash work the same as without one. |
| OpenAPI | https://cs.growthdept.ai/api/openapi.json. This page is rendered from it. |
Authentication
Create an API key in the helpdesk under Settings, REST API. A key belongs to one agent in one helpdesk and acts with that agent's role. It is shown once, when you create it, and stored only as a hash, so copy it then. Revoke a key at any time and it stops working on the next request.
Send the agent's email address as the username and the key as the password, with HTTP Basic authentication. Sending the key alone as a Bearer token works too. Either way, the key decides which helpdesk the request reaches; there is no helpdesk name in the URL.
HTTP Basic
curl https://cs.growthdept.ai/api/account \
-u "ana@demostore.example:$HELPDESK_API_KEY"Bearer token
curl https://cs.growthdept.ai/api/account \
-H "Authorization: Bearer $HELPDESK_API_KEY"Each endpoint below names the lowest role that may call it. Roles rank observer-agent, lite-agent, basic-agent, agent, lead-agent, admin; a higher role can do everything a lower one can.
| Role | Adds |
|---|---|
| observer-agent | Read everything: tickets, messages, customers, agents, teams, tags, macros, rules, views, fields, surveys, integrations and events. |
| lite-agent | Work tickets: reply, add notes, tag, assign, snooze, close; create and edit customers; create tags. |
| lead-agent | Manage macros, views and view sections; rename, recolour, merge and delete tags. |
| admin | Manage agents and their roles, teams, rules, fields, satisfaction surveys, integrations, widgets, helpdesk settings and every agent's API keys. |
The app's own pages use the sign-in session instead of a key, with an X-Helpdesk header naming the helpdesk and an X-CSRF-Token header on writes. Scripts and integrations should use a key.
Pagination
List endpoints return an envelope: object is always "list", uri is the request, data holds the objects and meta holds the cursors for the pages either side.
A page of tickets
{
"object": "list",
"uri": "/api/tickets?limit=2",
"data": [ { "id": 4182, ... }, { "id": 4181, ... } ],
"meta": { "prev_cursor": null, "next_cursor": "WyJuZXh0IiwgIjIwMjYtMTEtMDQiLCA0MTgxXQ==" }
}| Parameter | What it does |
|---|---|
| limit | How many objects per page, from 1 to 100. The default is 30. |
| cursor | Where to continue: pass meta.next_cursor for the next page or meta.prev_cursor for the previous one. It is null at either end. |
| order_ | The sort, as <field>:<asc|desc>, such as created_datetime:desc. Each list endpoint below lists the fields it can sort by and its default. |
Pages are read by position in the sort, not by page number, so tickets created while you walk a list never shift the pages you have not read yet. To read everything, keep following next_cursor until it is null.
Errors and limits
Errors come back as JSON with a status code that says what kind of problem it is. error.msg says what went wrong in plain words; for an invalid request, error.data lists the problems with each field.
400 Bad Request
{
"error": {
"msg": "The request has an invalid value.",
"data": { "limit": ["Use a number from 1 to 100."] }
}
}| Status | Meaning |
|---|---|
| 200, 201 | It worked. 201 when something was created. |
| 204 | It worked and there is nothing to return, as after a delete. |
| 400 | The request is not valid. error.data lists the problem with each field. |
| 401 | No API key, or a key that is wrong or revoked. |
| 403 | The key's agent does not have the role this endpoint needs. |
| 404 | Nothing with that id in this helpdesk. |
| 409 | The change conflicts with what is stored, such as a setting group that already exists. |
| 413 | The upload is too large. |
| 429 | Too many calls. Wait the number of seconds in Retry-after. |
Each API key may make 40 calls in a 20-second window. Every response carries X-Helpdesk-Api-Call-Limit with the calls used and the limit, such as 12/40. Past the limit the API answers 429 with Retry-after, the seconds until the window resets.
Webhooks
An HTTP integration calls your URL when something happens to a ticket. Create one in Settings or with POST /api/integrations and type http: give it a URL, a method, a content type, a body and the events to send on.
| Event | Sent when |
|---|---|
| ticket-created | A ticket is opened: by an email arriving, by an agent or through the API. |
| ticket-updated | A ticket's status, assignee, team, tags, priority, fields or other properties change. |
| ticket-message-created | A message or internal note is added to a ticket. |
The URL and the body are templates. Variables in double braces are filled in from the ticket for each delivery, such as {{ticket.id}}, {{ticket.subject}} and {{ticket.status}}.
An HTTP integration
{
"type": "http",
"name": "Order sync webhook",
"http": {
"url": "https://hooks.example.com/helpdesk",
"method": "POST",
"request_content_type": "application/json",
"form": { "ticket_id": "{{ticket.id}}", "status": "{{ticket.status}}" },
"triggers": { "ticket-created": true, "ticket-updated": true, "ticket-message-created": false }
}
}Deliveries are signed, so your server can check they came from your helpdesk, and are retried with a growing delay when your server does not answer with a 2xx status. Your server should answer quickly and do slow work afterwards.
Compatible with Gorgias's REST API
The API follows Gorgias's REST API so that code written for it, including the Growth Dept kit's support tools, works here after two changes: the base URL and the credentials. The Growth Dept kit makes that switch with one setting, SUPPORT_BACKEND=growthdept.
# Before
BASE=https://<your-domain>.gorgias.com/api
# After
BASE=https://cs.growthdept.ai/apiWhat stays the same
| Same as Gorgias's REST API | |
|---|---|
| Paths | Resources live at the same paths under /api/: /api/tickets, /api/tickets/{id}/messages, /api/customers/merge and so on. |
| Fields | Objects use the same field names and value formats, including the _datetime timestamps and the embedded customer, assignee and tag objects. |
| Lists | Lists come in the same envelope, {object, uri, data, meta}, and page with limit, cursor and order_by=<field>:<asc|desc>, with meta.next_cursor and meta.prev_cursor. |
| Errors | Errors use the same status codes and an error object with a message and, for invalid requests, the problem with each field. |
| Sign-in | HTTP Basic with the agent's email as the username and an API key as the password. |
| Webhooks | HTTP integrations take the same settings and the same template variables, such as {{ticket.id}}, and fire on ticket-created, ticket-updated and ticket-message-created. |
What differs
| Here | |
|---|---|
| Base URL | https://cs.growthdept.ai/api for every helpdesk, in place of https://<your-domain>.gorgias.com/api. |
| Helpdesk | There is no subdomain. The API key says which helpdesk a request is for, so a key from the new helpdesk is part of the switch. |
| Bearer keys | Authorization: Bearer <key> works as well as HTTP Basic. |
| Rate-limit header | The calls used in the current window come back in X-Helpdesk-Api-Call-Limit, as used/limit. Each key gets 40 calls per 20 seconds. |
| Not offered | Phone and voice (calls, call events and recordings) are not part of this helpdesk. |
| Reporting | Reporting statistics cover tickets created, replied and closed, one-touch tickets, messages sent and received, messages per ticket, first response time, resolution time and satisfaction. Other scopes, such as automation or voice, are refused with a 400 that lists the scopes on offer. Rates come back from 0 to 1 and times in seconds. |
| Metric feedback | Feedback on a metric card answers 204 with no body, and its comment text is not stored. |
| Added | View sections have their own endpoints, and the whole API is described in an OpenAPI document at /api/openapi.json. |
| Files | Uploaded files are served from cs.growthdept.ai, from links that carry their own access token. |
Gorgias is a trademark of its owner. Growth Dept Helpdesk is not affiliated with it; the name appears here only to describe compatibility.
Account
The helpdesk the key belongs to: its address, name, time zone, currency and setting groups such as business hours. GET /api/account is the quickest way to check a key works.
The AccessLogEntry object · 12 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| created_ | datetime | |
| action | read | |
| object_ | Customer, Ticket, TicketMessage, SatisfactionSurvey, AiDraft, File | What was read. |
| object_ | integer or null | The object read; null for a list or search. |
| count | integer | How many records the response held: 1 for one object, the page size for a list or search, the messages returned for a ticket's messages. |
| route | string | The method and path template, such as GET /api/customers/{id}. Query strings are never kept. |
| via | api_key, session | session for the app's own pages, api_key for the REST API. |
| user | object or null | The agent who read: id, name and email. |
| api_ | object or null | The API key used: id, name and the first characters of the key. |
| platform_ | boolean | True when a Growth Dept admin read the helpdesk's data. |
| ip | string or null | The caller's address, as the hosting platform reported it. |
The Account object · 12 fields
A helpdesk. Gorgias calls it an account.
| Field | Type | Description |
|---|---|---|
| domain | string | The helpdesk's address, as in /app/<domain>. |
| name | string | The helpdesk's name. |
| created_ | datetime or null | |
| deactivated_ | datetime or null | |
| current_ | object | |
| meta | object | |
| settings | array of AccountSetting | |
| status | object | |
| timezone | string | IANA time zone. |
| currency | string | ISO 4217 currency code. |
| language | string | |
| domains | array of string |
The AccountSetting object · 3 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| type | string | Setting group, such as business-hours. |
| data | any | The group's settings. |
The AuditEntry object · 9 fields
| Field | Type | Description |
|---|---|---|
| id | string | a:<n> for account changes, e:<n> for helpdesk events. |
| source | account, helpdesk | |
| created_ | datetime | |
| action | string | |
| object_ | string or null | |
| object_ | integer or string or null | |
| user | object or null | The agent who acted, when known. |
| via | string or null | api_key when the change came through an API key. |
| detail | object or null |
The HelpdeskSettings object · 2 fields
Every helpdesk-level setting type with its current value, defaults filled in.
| Field | Type | Description |
|---|---|---|
| data | object | Setting values by type: business-hours, satisfaction-surveys, ticket-assignment, access, notifications, slas, agent-statuses, auto-merge, auto-split, labs, order-management, analytics. |
| me | object | The calling agent's id and own notification choices. |
List reads of customers' personal data
GET/api/access-logs
Every request that returned customers, tickets, messages, satisfaction surveys, drafted replies, attachments or a customer's Shopify orders, newest first: who read (agent, API key or Growth Dept admin), what (type and id, or a list and how many), the route and the caller's address. Entries hold ids only, never the data. Kept for 365 days. Filter by agent, API key, object, app or API, and time.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| user_ | Only reads by this agent. |
| object_ | Only reads of this kind of object.Customer, Ticket, TicketMessage, SatisfactionSurvey, AiDraft, File |
| object_ | With object_type: reads of one object. |
| viaquery · string | api_key for the REST API, session for the app's pages.api_key, session |
| api_ | Only reads made with this API key. |
| fromquery · datetime | At or after this time. |
| toquery · datetime | At or before this time. |
Response
200 · A page of reads. · list of AccessLogEntry
Request
curl "https://cs.growthdept.ai/api/access-logs?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/access-logs?limit=2",
"data": [
{
"id": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"action": "read",
"object_type": "Ticket",
"object_id": 4182,
"count": 0,
"route": "",
"via": "api_key",
"user": {},
"api_key": {},
"platform_admin": false,
"ip": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Get the helpdesk
GET/api/account
The helpdesk the API key belongs to: its address (domain), company name, plan and settings. Tools use it to check a key works and which helpdesk it reaches.
Response
200 · The helpdesk. · Account
Request
curl "https://cs.growthdept.ai/api/account" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"domain": "demo-store",
"name": "Demo Store",
"created_datetime": "2026-11-04T09:41:12+00:00",
"deactivated_datetime": null,
"current_subscription": {
"plan": "standard",
"status": "open",
"start_datetime": "2026-11-04T09:41:12+00:00",
"trial_start_datetime": null,
"trial_end_datetime": null
},
"meta": {
"company_name": "Demo Store",
"company_domain": null
},
"settings": [
{
"id": 1,
"type": "business-hours",
"data": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "1,2,3,4,5",
"from_time": "09:00",
"to_time": "17:00"
}
]
}
}
],
"status": {
"status": "open"
},
"timezone": "America/Los_Angeles",
"currency": "USD",
"language": "en",
"domains": [
""
]
}List the helpdesk's settings
GET/api/account/settings
Every setting group of the helpdesk (business hours, satisfaction survey, ticket assignment, ...), each with its id, type and data. The nine groups Gorgias always lists are present even before they are saved, with their defaults. Pass type to list one group.
Parameters
| Name | Description |
|---|---|
| typequery · string | Only the setting group of this type, such as business-hours. |
Response
200 · The settings. · list of AccountSetting
Request
curl \
"https://cs.growthdept.ai/api/account/settings?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/account/settings",
"data": [
{
"id": 1,
"type": "business-hours",
"data": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "1,2,3,4,5",
"from_time": "09:00",
"to_time": "17:00"
}
]
}
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Add a setting group
POST/api/account/settings
Stores the data for a setting type the helpdesk does not have yet. Change an existing type with PUT /api/account/settings/{id}.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| typerequired | string | |
| datarequired | any |
Response
201 · The new setting group. · AccountSetting
Request
curl -X POST "https://cs.growthdept.ai/api/account/settings" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "business-hours",
"data": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "1,2,3,4,5",
"from_time": "09:00",
"to_time": "17:00"
}
]
}
}'Response 201
{
"id": 1,
"type": "business-hours",
"data": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "1,2,3,4,5",
"from_time": "09:00",
"to_time": "17:00"
}
]
}
}Read the audit log
GET/api/helpdesk/audit-log
Account changes (sign-in policy, API keys, invites, settings) and helpdesk activity (tickets, rules, macros) newest first. Filter by source, action, object type, agent and time. Page with the next_cursor in meta.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| sourcequery · string | all, account, helpdeskdefault all |
| actionquery · string | |
| object_ | |
| user_ | |
| fromquery · datetime | |
| toquery · datetime | |
| limitquery · string | |
| cursorquery · string |
Response
200 · A page of entries. · list of AuditEntry
Request
curl \
"https://cs.growthdept.ai/api/helpdesk/audit-log?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/helpdesk/audit-log?limit=2",
"data": [
{
"id": "",
"source": "account",
"created_datetime": "2026-11-04T09:41:12+00:00",
"action": "",
"object_type": "Ticket",
"object_id": 4182,
"user": {},
"via": "email",
"detail": {}
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Read the helpdesk's settings
GET/api/helpdesk/settings
All helpdesk-level settings with defaults filled in, and the calling agent's own notification choices. The settings pages read this; change one type with PUT.
Response
200 · The settings. · HelpdeskSettings
Request
curl "https://cs.growthdept.ai/api/helpdesk/settings" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": {},
"me": {}
}Change one setting type
PUT/api/helpdesk/settings
Replaces one setting type's value after checking it. Admins change any type. Any agent can send type notifications with scope me to change only their own notification choices, or type analytics with scope me and data {order, hidden} to choose their own overview figures. Fields the schema does not know are kept.
Body
| Field | Type | Description |
|---|---|---|
| typerequired | business-hours, satisfaction-surveys, ticket-assignment, access, notifications, slas, agent-statuses, auto-merge, auto-split, labs, order-management, analytics | |
| datarequired | any | |
| scope | helpdesk, me |
Response
200 · The type's value after the change. · AccountSetting
Request
curl -X PUT "https://cs.growthdept.ai/api/helpdesk/settings" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "business-hours",
"data": {}
}'Response 200
{
"id": 1,
"type": "business-hours",
"data": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "1,2,3,4,5",
"from_time": "09:00",
"to_time": "17:00"
}
]
}
}Get a setting group
GET/api/account/settings/{id}
One setting group of the helpdesk by its id.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The setting group. · AccountSetting
Request
curl "https://cs.growthdept.ai/api/account/settings/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"type": "business-hours",
"data": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "1,2,3,4,5",
"from_time": "09:00",
"to_time": "17:00"
}
]
}
}Change a setting group
PUT/api/account/settings/{id}
Replaces the data of one setting group. The other groups are left as they are.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| datarequired | any | |
| type | string |
Response
202 · The setting group after the change. · AccountSetting
Request
curl -X PUT "https://cs.growthdept.ai/api/account/settings/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "1,2,3,4,5",
"from_time": "08:00",
"to_time": "18:00"
}
]
}
}'Response 202
{
"id": 1,
"type": "business-hours",
"data": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "1,2,3,4,5",
"from_time": "09:00",
"to_time": "17:00"
}
]
}
}Tickets
A ticket is one conversation with a customer: its messages, status, assignee, team, tags, priority and field values. Writes go through the same code as the app, so rules, webhooks and outgoing email fire the same way whichever made the change.
The Ticket object · 31 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| external_ | string or null | |
| language | string or null | |
| status | open, closed | |
| priority | low, normal, high, critical | |
| channel | string | |
| via | string | |
| from_ | boolean | |
| customer | CustomerSummary or null | |
| assignee_ | UserSummary or null | |
| assignee_ | TeamSummary or null | |
| subject | string or null | |
| summary | string or null | |
| excerpt | string or null | The start of the latest message. |
| integrations | array of any | |
| meta | object or null | |
| tags | array of TagSummary | |
| messages_ | integer | |
| is_ | boolean | |
| spam | boolean | |
| custom_ | object | Ticket field values keyed by field id. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| opened_ | datetime or null | |
| last_ | datetime or null | |
| last_ | datetime or null | |
| last_ | boolean | |
| closed_ | datetime or null | |
| snooze_ | datetime or null | |
| trashed_ | datetime or null |
The TicketDetail object · 40 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| external_ | string or null | |
| language | string or null | |
| status | open, closed | |
| priority | low, normal, high, critical | |
| channel | string | |
| via | string | |
| from_ | boolean | |
| customer | CustomerDetail or null | |
| assignee_ | UserSummary or null | |
| assignee_ | TeamSummary or null | |
| subject | string or null | |
| summary | string or null | |
| excerpt | string or null | The start of the latest message. |
| integrations | array of any | |
| meta | object or null | |
| tags | array of TagSummary | |
| messages_ | integer | |
| is_ | boolean | |
| spam | boolean | |
| custom_ | object | Ticket field values keyed by field id. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| opened_ | datetime or null | |
| last_ | datetime or null | |
| last_ | datetime or null | |
| last_ | boolean | |
| closed_ | datetime or null | |
| snooze_ | datetime or null | |
| trashed_ | datetime or null | |
| requester | CustomerDetail or null | |
| assignee_ | integer or null | |
| assignee_ | integer or null | |
| imported | boolean or null | |
| messages | array of Message | |
| events | array of any | |
| satisfaction_ | object or null | |
| reply_ | object | |
| integration_ | integer or null | The mailbox or channel integration the ticket belongs to. |
The CustomFieldValue object · 3 fields
| Field | Type | Description |
|---|---|---|
| id | integer | The field's id. |
| value | any | The value, typed by the field's definition. |
| field | object | The field's definition. |
List tickets
GET/api/tickets
A page of the helpdesk's tickets, newest first unless order_by says otherwise. Filter by customer, external id, ticket ids, saved view or the rule that acted on them. Deleted tickets are never listed; trashed and spam tickets are, unless trashed=false leaves the trashed ones out. A parameter the list does not take is a 400, as in Gorgias.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc, updated_datetime:asc, updated_datetime:desc, priority_score:asc, priority_score:desc |
| customer_ | Only this customer's tickets. |
| external_ | Only the ticket with this external id. |
| view_ | Only the tickets a saved view shows. |
| ticket_ | Only these ticket ids, comma-separated. |
| rule_ | Only the tickets this rule has acted on. |
| trashedquery · string | false leaves trashed tickets out; true (the default) includes them, as in Gorgias.0, 1, true, false |
Response
200 · A page of tickets. · list of Ticket
Request
curl "https://cs.growthdept.ai/api/tickets?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/tickets?limit=2",
"data": [
{
"id": 4182,
"uri": "/api/tickets/4182/",
"external_id": null,
"language": "en",
"status": "open",
"priority": "normal",
"channel": "email",
"via": "email",
"from_agent": false,
"customer": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"assignee_user": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"assignee_team": {
"id": 3,
"name": "Orders",
"decoration": {
"color": "#2546e8"
}
},
"subject": "Where is order #1042?",
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week.",
"integrations": [],
"meta": {},
"tags": [
{
"id": 12,
"name": "shipping",
"decoration": {
"color": "#2546e8"
}
}
],
"messages_count": 3,
"is_unread": true,
"spam": false,
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"opened_datetime": null,
"last_received_message_datetime": "2026-11-04T09:41:12+00:00",
"last_message_datetime": "2026-11-04T09:41:12+00:00",
"last_sent_message_not_delivered": false,
"closed_datetime": null,
"snooze_datetime": null,
"trashed_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a ticket
POST/api/tickets
Opens a ticket for a customer (by id, or by email, which creates the customer when it is new), with its first messages, tags, assignee and field values. As in Gorgias, a ticket needs at least one message (a customer's with its sender) and opens only on the channels Gorgias lists (api, contact_form, custom-chat, email, facebook-messenger, google-business-messages, help-center, instagram-direct-message, phone, sms, tiktok-shop, whatsapp). A public message an agent writes on the email channel is sent from the helpdesk's mailbox.
Role: lite-agent or higher
Body
| Field | Type | Description |
|---|---|---|
| channel | string | |
| via | string | |
| status | open, closed | |
| priority | low, normal, high, critical | |
| subject | string or null | |
| language | string or null | |
| external_ | string or null | |
| from_ | boolean | |
| spam | boolean | |
| is_ | boolean | |
| assignee_ | object or null | {id} or {email} of an agent, or null to unassign. |
| assignee_ | object or null | |
| tags | array of object | Each {id} or {name}; unknown names are created. |
| meta | object or null | |
| custom_ | array of object or object | |
| opened_ | string or null | |
| closed_ | string or null | |
| snooze_ | string or null | |
| trashed_ | string or null | |
| customer | object or null | {id}, or {email} (a new address creates the customer). |
| messages | array of object | |
| imported | boolean or null | |
| created_ | string or null |
Response
201 · The new ticket, with its messages. · TicketDetail
Request
curl -X POST "https://cs.growthdept.ai/api/tickets" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer": {
"email": "maya.okafor@example.com"
},
"subject": "Where is order #1042?",
"channel": "api",
"via": "api",
"messages": [
{
"channel": "api",
"via": "api",
"from_agent": false,
"sender": {
"email": "maya.okafor@example.com"
},
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?"
}
],
"tags": [
{
"name": "shipping"
}
]
}'Response 201
{
"id": 4182,
"uri": "/api/tickets/4182/",
"external_id": null,
"language": "en",
"status": "open",
"priority": "normal",
"channel": "email",
"via": "email",
"from_agent": false,
"customer": {
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
},
"assignee_user": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"assignee_team": {
"id": 3,
"name": "Orders",
"decoration": {
"color": "#2546e8"
}
},
"subject": "Where is order #1042?",
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week.",
"integrations": [],
"meta": {},
"tags": [
{
"id": 12,
"name": "shipping",
"decoration": {
"color": "#2546e8"
}
}
],
"messages_count": 3,
"is_unread": true,
"spam": false,
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"opened_datetime": null,
"last_received_message_datetime": "2026-11-04T09:41:12+00:00",
"last_message_datetime": "2026-11-04T09:41:12+00:00",
"last_sent_message_not_delivered": false,
"closed_datetime": null,
"snooze_datetime": null,
"trashed_datetime": null,
"requester": {
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
},
"assignee_user_id": 12,
"assignee_team_id": 3,
"imported": false,
"messages": [
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {},
"to": [],
"cc": [],
"bcc": []
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"id": 1
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}
],
"events": [],
"satisfaction_survey": {},
"reply_options": {},
"integration_id": 2
}Get a ticket
GET/api/tickets/{id}
One ticket with its messages (internal notes included), tags, assignee, field values and the customer with their channels. A ticket that was merged into another answers 301 with the new ticket's address in Location.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| relationshipsquery · string or array of string | Related objects to include. Field values are always included; custom_fields is accepted for Gorgias clients. |
Response
200 · The ticket. · TicketDetail
Request
curl "https://cs.growthdept.ai/api/tickets/4182" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 4182,
"uri": "/api/tickets/4182/",
"external_id": null,
"language": "en",
"status": "open",
"priority": "normal",
"channel": "email",
"via": "email",
"from_agent": false,
"customer": {
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
},
"assignee_user": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"assignee_team": {
"id": 3,
"name": "Orders",
"decoration": {
"color": "#2546e8"
}
},
"subject": "Where is order #1042?",
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week.",
"integrations": [],
"meta": {},
"tags": [
{
"id": 12,
"name": "shipping",
"decoration": {
"color": "#2546e8"
}
}
],
"messages_count": 3,
"is_unread": true,
"spam": false,
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"opened_datetime": null,
"last_received_message_datetime": "2026-11-04T09:41:12+00:00",
"last_message_datetime": "2026-11-04T09:41:12+00:00",
"last_sent_message_not_delivered": false,
"closed_datetime": null,
"snooze_datetime": null,
"trashed_datetime": null,
"requester": {
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
},
"assignee_user_id": 12,
"assignee_team_id": 3,
"imported": false,
"messages": [
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {},
"to": [],
"cc": [],
"bcc": []
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"id": 1
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}
],
"events": [],
"satisfaction_survey": {},
"reply_options": {},
"integration_id": 2
}Update a ticket
PUT/api/tickets/{id}
Changes the fields you send and leaves the rest. Send status to close or reopen (reopening also ends a snooze), snooze_datetime to snooze, assignee_user or assignee_team ({id}, or null to unassign), spam, trashed_datetime, tags (replaces the list), custom_fields or customer. The change is applied before the response, which answers 202 as Gorgias does.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| channel | string | |
| via | string | |
| status | open, closed | |
| priority | low, normal, high, critical | |
| subject | string or null | |
| language | string or null | |
| external_ | string or null | |
| from_ | boolean | |
| spam | boolean | |
| is_ | boolean | |
| assignee_ | object or null | {id} or {email} of an agent, or null to unassign. |
| assignee_ | object or null | |
| tags | array of object | Each {id} or {name}; unknown names are created. |
| meta | object or null | |
| custom_ | array of object or object | |
| opened_ | string or null | |
| closed_ | string or null | |
| snooze_ | string or null | |
| trashed_ | string or null | |
| customer | object or null |
Response
202 · The ticket after the change. · TicketDetail
Request
curl -X PUT "https://cs.growthdept.ai/api/tickets/4182" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "closed",
"assignee_user": {
"id": 12
},
"tags": [
{
"name": "shipping"
},
{
"name": "replacement-sent"
}
]
}'Response 202
{
"id": 4182,
"uri": "/api/tickets/4182/",
"external_id": null,
"language": "en",
"status": "open",
"priority": "normal",
"channel": "email",
"via": "email",
"from_agent": false,
"customer": {
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
},
"assignee_user": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"assignee_team": {
"id": 3,
"name": "Orders",
"decoration": {
"color": "#2546e8"
}
},
"subject": "Where is order #1042?",
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week.",
"integrations": [],
"meta": {},
"tags": [
{
"id": 12,
"name": "shipping",
"decoration": {
"color": "#2546e8"
}
}
],
"messages_count": 3,
"is_unread": true,
"spam": false,
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"opened_datetime": null,
"last_received_message_datetime": "2026-11-04T09:41:12+00:00",
"last_message_datetime": "2026-11-04T09:41:12+00:00",
"last_sent_message_not_delivered": false,
"closed_datetime": null,
"snooze_datetime": null,
"trashed_datetime": null,
"requester": {
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
},
"assignee_user_id": 12,
"assignee_team_id": 3,
"imported": false,
"messages": [
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {},
"to": [],
"cc": [],
"bcc": []
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"id": 1
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}
],
"events": [],
"satisfaction_survey": {},
"reply_options": {},
"integration_id": 2
}Delete a ticket
DELETE/api/tickets/{id}
Deletes the ticket. It disappears from every list and its id answers 404 from then on. To keep it but hide it from views, set trashed_datetime instead.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/tickets/4182" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Merge two tickets
PUT/api/tickets/merge
Moves the source ticket's messages and tags into the target and removes the source: its id answers 301 to the target from then on. The target keeps its own status, priority and assignee; send subject to choose which subject survives. The tickets must belong to the same customer and the same mailbox, so API-channel tickets cannot be merged. This cannot be undone.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| target_ | |
| source_ |
Body
| Field | Type | Description |
|---|---|---|
| subject | string or null | The subject the merged ticket keeps. |
| customer | object or null | The customer of the merged ticket: both tickets must have the same one. |
Response
202 · The merged ticket. · TicketDetail
Request
curl -X PUT "https://cs.growthdept.ai/api/tickets/merge" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"subject": "Where is order #1042?",
"customer": {
"id": 1
}
}'Response 202
{
"id": 4182,
"uri": "/api/tickets/4182/",
"external_id": null,
"language": "en",
"status": "open",
"priority": "normal",
"channel": "email",
"via": "email",
"from_agent": false,
"customer": {
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
},
"assignee_user": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"assignee_team": {
"id": 3,
"name": "Orders",
"decoration": {
"color": "#2546e8"
}
},
"subject": "Where is order #1042?",
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week.",
"integrations": [],
"meta": {},
"tags": [
{
"id": 12,
"name": "shipping",
"decoration": {
"color": "#2546e8"
}
}
],
"messages_count": 3,
"is_unread": true,
"spam": false,
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"opened_datetime": null,
"last_received_message_datetime": "2026-11-04T09:41:12+00:00",
"last_message_datetime": "2026-11-04T09:41:12+00:00",
"last_sent_message_not_delivered": false,
"closed_datetime": null,
"snooze_datetime": null,
"trashed_datetime": null,
"requester": {
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
},
"assignee_user_id": 12,
"assignee_team_id": 3,
"imported": false,
"messages": [
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {},
"to": [],
"cc": [],
"bcc": []
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"id": 1
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}
],
"events": [],
"satisfaction_survey": {},
"reply_options": {},
"integration_id": 2
}Search tickets
POST/api/tickets/search
Finds tickets by text and a filter. Every word of search must start a word in the ticket's subject, its customer's name or address or its recent messages; a ticket's id matches too, and so does part of its customer's email. Answers 201, as Gorgias does, with {entity, highlights} items; with_highlights marks the matched words in the subject with <em>.
Parameters
| Name | Description |
|---|---|
| limitquery · string | |
| cursorquery · string | |
| order_ | |
| with_ | |
| track_ |
Body
| Field | Type | Description |
|---|---|---|
| search | string or null | The text to find in subjects, messages and customers. |
| filters | string | A condition in the view language, such as eq(ticket.status, "open"). Send an empty string for none. |
Response
201 · A page of matching tickets. · object
Request
curl -X POST "https://cs.growthdept.ai/api/tickets/search" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"search": null,
"filters": "eq(ticket.status, \"open\") && isEmpty(ticket.assignee_user.id) && containsAll(ticket.tags.name, [\"shipping\"])"
}'Response 201
{}List a ticket's field values
GET/api/tickets/{id}/custom-fields
The values of the ticket's fields, each as {field, prediction, value} with the field's definition.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The values, as {data: [...]}. · object
Request
curl \
"https://cs.growthdept.ai/api/tickets/4182/custom-fields" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 5,
"value": "Where is my order",
"field": {}
}
]
}Replace a ticket's field values
PUT/api/tickets/{id}/custom-fields
Sets the ticket's field values to exactly the list given as [{id, value}], where id is the field's id: fields left out are cleared, and a null value clears that field.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
Any JSON value.
Response
202 · All of the ticket's values after the change. · object
Request
curl -X PUT \
"https://cs.growthdept.ai/api/tickets/4182/custom-fields" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{}List a ticket's tags
GET/api/tickets/{id}/tags
The tags on one ticket, in the order they were added.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The ticket's tags, as {data: [...]}. · object
Request
curl "https://cs.growthdept.ai/api/tickets/4182/tags" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 12,
"uri": "/api/tags/12/",
"name": "shipping",
"description": null,
"decoration": {
"color": "#2546e8"
},
"usage": 142,
"created_datetime": "2026-11-04T09:41:12+00:00",
"deleted_datetime": null
}
]
}Add tags to a ticket
POST/api/tickets/{id}/tags
Adds tags, as {"names": [...]} or {"ids": [...]}. Each tag must already exist (create it with POST /api/tags): a tag that does not is a 400 that names it. Tags the ticket already has are left as they are.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| names | array of string | |
| ids | array of integer or string |
Response
201 · Added. The body is empty, as in Gorgias; GET the tags to see them. · object
Request
curl -X POST "https://cs.growthdept.ai/api/tickets/4182/tags" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"names": [
"shipping",
"carrier-trace"
]
}'Response 201
{}Replace a ticket's tags
PUT/api/tickets/{id}/tags
Sets the ticket's tags to exactly the ones given, as {"names": [...]} or {"ids": [...]}; each must already exist. An empty list is a 400, as in Gorgias: to remove every tag, PUT the ticket with "tags": [].
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| names | array of string | |
| ids | array of integer or string |
Response
202 · Replaced. The body is empty, as in Gorgias. · object
Request
curl -X PUT "https://cs.growthdept.ai/api/tickets/4182/tags" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"names": [
""
],
"ids": [
0
]
}'Response 202
{}Remove tags from a ticket
DELETE/api/tickets/{id}/tags
Removes tags, given in the body as {"names": [...]} or {"ids": [...]}, the same shape as adding them. A tag the ticket does not have is ignored; a tag that does not exist at all is a 400 that names it, as in Gorgias.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| names | array of string | |
| ids | array of integer or string |
Response
204 · Removed.
Request
curl -X DELETE "https://cs.growthdept.ai/api/tickets/4182/tags" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"names": [
""
],
"ids": [
0
]
}'Response 204
(no body)Set one ticket field
PUT/api/tickets/{id}/custom-fields/{fieldId}
Sets one field's value on the ticket. The body is the bare JSON value, such as "Late", 42.5 or true; {"value": ...} works too. null clears it.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| fieldIdrequiredpath · integer | The ticket field's id. |
Body
The value itself, typed by the field's definition.
Response
202 · The field with its new value. · CustomFieldValue
Request
curl -X PUT \
"https://cs.growthdept.ai/api/tickets/4182/custom-fields/5" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{
"id": 5,
"value": "Where is my order",
"field": {}
}Clear one ticket field
DELETE/api/tickets/{id}/custom-fields/{fieldId}
Removes one field's value from the ticket. A value that was never set is a 400, as in Gorgias.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| fieldIdrequiredpath · integer | The ticket field's id. |
Response
204 · Cleared.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/tickets/4182/custom-fields/5" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Messages
Messages are the emails, replies and internal notes on a ticket. A public message from an agent on an email ticket is sent from the ticket's mailbox, in the same thread; internal notes are never sent.
The Message object · 35 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| ticket_ | integer | |
| message_ | string or null | RFC 5322 Message-ID for email. |
| external_ | string or null | |
| public | boolean | False for internal notes. |
| channel | string | email, chat, api, internal-note, ... |
| via | string | How the message reached the helpdesk: email, helpdesk, api, rule, ... |
| source | object | |
| sender | UserSummary | |
| receiver | UserSummary or null | |
| integration_ | integer or null | |
| rule_ | integer or null | |
| from_ | boolean | |
| subject | string or null | |
| body_ | string or null | |
| body_ | string or null | |
| stripped_ | string or null | |
| stripped_ | string or null | |
| stripped_ | string or null | |
| attachments | array of Attachment or null | |
| actions | any | |
| macros | any | |
| intents | any | |
| headers | object or null | |
| meta | object or null | |
| imported | boolean or null | |
| is_ | boolean | |
| last_ | object or null | |
| created_ | datetime or null | |
| processed_ | datetime or null | |
| sent_ | datetime or null | When the message went out; null while it waits to be sent. |
| failed_ | datetime or null | |
| opened_ | datetime or null | |
| deleted_ | datetime or null |
List messages
GET/api/messages
A page of messages across every ticket, or one ticket's with ticket_id. Internal notes are included (public false). Messages of deleted tickets are left out.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| ticket_ | Only this ticket's messages. |
Response
200 · A page of messages. · list of Message
Request
curl "https://cs.growthdept.ai/api/messages?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/messages?limit=2",
"data": [
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {
"name": "Demo Store",
"address": "maya.okafor@example.com"
},
"to": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"cc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"bcc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
]
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"name": "parcel-photo.jpg",
"size": 48213,
"content_type": "image/jpeg",
"public": true,
"extra": {}
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Get a message by id
GET/api/messages/{id}
One message when you know only its id. Its ticket_id and uri name the ticket it belongs to.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The message. · Message
Request
curl "https://cs.growthdept.ai/api/messages/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {
"name": "Demo Store",
"address": "maya.okafor@example.com"
},
"to": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"cc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"bcc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
]
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"name": "parcel-photo.jpg",
"size": 48213,
"content_type": "image/jpeg",
"public": true,
"extra": {}
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}List a ticket's messages
GET/api/tickets/{id}/messages
The ticket's messages and internal notes, oldest first, by page (page and per_page) as Gorgias pages this list. For cursor pages use GET /api/messages?ticket_id=.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| pagequery · integer | Page number, starting at 1.default 1 |
| per_ | Objects per page, from 1 to 100. Default 30. |
| pagequery · string | |
| per_ |
Response
200 · A page of messages. · list of Message
Request
curl \
"https://cs.growthdept.ai/api/tickets/4182/messages?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/tickets/4182/messages",
"data": [
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {
"name": "Demo Store",
"address": "maya.okafor@example.com"
},
"to": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"cc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"bcc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
]
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"name": "parcel-photo.jpg",
"size": 48213,
"content_type": "image/jpeg",
"public": true,
"extra": {}
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Add a message to a ticket
POST/api/tickets/{id}/messages
Replies to the customer, records a message, or adds an internal note (channel internal-note, or public false). As in Gorgias, channel, from_agent and sender are required. A public reply from an agent on the email channel is queued and sent from the ticket's mailbox; sent_datetime is set once it goes out. Send via email to record a message that was already sent; it is never sent again. Macro actions in actions are marked success, except Shopify actions (shopifyCancelLastOrder, shopifyCancelOrder, shopifyDuplicateLastOrder, shopifyEditNoteOfLastOrder, shopifyEditShippingAddressOfLastOrder, shopifyFullRefundLastOrder, shopifyPartialRefundLastOrder, shopifyRefundShippingCostOfLastOrder): those are saved pending and run against the store right after, as the sending agent, and each is then marked success or error with result.message.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| channel | string | email, chat, api, internal-note, ... Defaults to the ticket's channel. |
| via | string | helpdesk (the default for agents) sends email replies; email means the message was already sent and it is only recorded. |
| public | boolean | false makes an internal note. |
| from_ | boolean | |
| sender | object or null | Who wrote it: an agent (from_agent true) or a customer, by id or email. Defaults to you. |
| receiver | object or null | Who it is for. Defaults to the ticket's customer. |
| source | object or null | |
| subject | string or null | |
| body_ | string or null | |
| body_ | string or null | |
| stripped_ | string or null | |
| stripped_ | string or null | |
| stripped_ | string or null | |
| attachments | array of object or null | |
| external_ | string or null | |
| message_ | string or null | |
| integration_ | integer or string | |
| macros | array of object or null | |
| actions | array of any or null | |
| intents | array of any or null | |
| headers | object or null | |
| meta | object or null | |
| mention_ | array of integer or string or null | Agents an internal note @mentions; each is told through a user-mentioned event. |
| imported | boolean or null | |
| created_ | string or null | |
| sent_ | string or null | |
| failed_ | string or null | |
| opened_ | string or null | |
| processed_ | string or null |
Response
201 · The new message. · Message
Request
curl -X POST \
"https://cs.growthdept.ai/api/tickets/4182/messages" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channel": "email",
"via": "api",
"from_agent": true,
"public": true,
"sender": {
"email": "ana@demostore.example"
},
"receiver": {
"email": "maya.okafor@example.com"
},
"body_text": "Hi Maya, your parcel is at the regional hub. We have asked the carrier to trace it and will write again by Thursday."
}'Response 201
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {
"name": "Demo Store",
"address": "maya.okafor@example.com"
},
"to": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"cc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"bcc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
]
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"name": "parcel-photo.jpg",
"size": 48213,
"content_type": "image/jpeg",
"public": true,
"extra": {}
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}Get a message
GET/api/tickets/{id}/messages/{messageId}
One message of a ticket.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| messageIdrequiredpath · integer | The message's id. |
Response
200 · The message. · Message
Request
curl \
"https://cs.growthdept.ai/api/tickets/4182/messages/90311" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {
"name": "Demo Store",
"address": "maya.okafor@example.com"
},
"to": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"cc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"bcc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
]
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"name": "parcel-photo.jpg",
"size": 48213,
"content_type": "image/jpeg",
"public": true,
"extra": {}
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}Update a message
PUT/api/tickets/{id}/messages/{messageId}
Changes a message's text, subject, attachments, metadata or delivery times. A message already sent to the customer is not sent again.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| messageIdrequiredpath · integer | The message's id. |
Body
| Field | Type | Description |
|---|---|---|
| body_ | string or null | |
| body_ | string or null | |
| stripped_ | string or null | |
| stripped_ | string or null | |
| subject | string or null | |
| external_ | string or null | |
| meta | object or null | |
| attachments | array of object or null | |
| sent_ | string or null | |
| failed_ | string or null | |
| opened_ | string or null | |
| last_ | object or null | |
| is_ | boolean |
Response
202 · The message after the change. · Message
Request
curl -X PUT \
"https://cs.growthdept.ai/api/tickets/4182/messages/90311" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?"
}'Response 202
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {
"name": "Demo Store",
"address": "maya.okafor@example.com"
},
"to": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"cc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
],
"bcc": [
{
"name": "Demo Store",
"address": "maya.okafor@example.com"
}
]
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12,
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"meta": {}
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"name": "parcel-photo.jpg",
"size": 48213,
"content_type": "image/jpeg",
"public": true,
"extra": {}
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}Delete a message
DELETE/api/tickets/{id}/messages/{messageId}
Removes a message from its ticket. The ticket's message count, excerpt and last message times are recomputed.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| messageIdrequiredpath · integer | The message's id. |
Response
204 · Deleted.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/tickets/4182/messages/90311" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Customers
Customers are the people who write in, matched by email address. A customer can have several addresses, free-form data from your own systems and customer field values. Deleting a customer removes their messages and files.
The Customer object · 16 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| external_ | string or null | |
| active | boolean | |
| string or null | The preferred email address. | |
| name | string or null | |
| firstname | string or null | |
| lastname | string or null | |
| language | string or null | |
| timezone | string or null | |
| note | string or null | |
| meta | object or null | |
| data | any | Free-form data set through the API. |
| custom_ | object | Customer field values keyed by field id. |
| created_ | datetime or null | |
| updated_ | datetime or null |
The CustomerDetail object · 21 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| external_ | string or null | |
| active | boolean | |
| string or null | The preferred email address. | |
| name | string or null | |
| firstname | string or null | |
| lastname | string or null | |
| language | string or null | |
| timezone | string or null | |
| note | string or null | |
| meta | object or null | |
| data | any | Free-form data set through the API. |
| custom_ | object | Customer field values keyed by field id. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| channels | array of CustomerChannel | |
| integrations | object | Store and app data keyed by integration id. |
| external_ | object | |
| ecommerce_ | object | |
| customer | null |
The CustomerChannel object · 9 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| type | string | email, phone, sms, chat, facebook, instagram, ... |
| address | string | |
| preferred | boolean | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| deleted_ | datetime or null | |
| user | object | |
| customer | object |
List customers
GET/api/customers
A page of the helpdesk's customers. Filter by id, email (any of the customer's addresses), external id, name, language, time zone, a channel's type and address, or a saved customer view. As in Gorgias, id, language and timezone cannot be combined with cursor, limit or order_by.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc, updated_datetime:asc, updated_datetime:desc |
| idquery · string | The customer with this id. |
| emailquery · string | Customers with this email address. |
| external_ | The customer with this external id. |
| namequery · string | Customers whose name contains this. |
| channel_ | With channel_address: the channel type, such as phone. |
| channel_ | Customers with this address on a channel. |
| languagequery · string | |
| timezonequery · string | |
| view_ | Only the customers a saved customer view shows. |
Response
200 · A page of customers. · list of Customer
Request
curl "https://cs.growthdept.ai/api/customers?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/customers?limit=2",
"data": [
{
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a customer
POST/api/customers
Adds a customer with an email address and other channels (phone, sms, chat handles). An address that belongs to another customer is refused; merge the two instead.
Role: lite-agent or higher
Body
| Field | Type | Description |
|---|---|---|
| string or null | ||
| name | string or null | |
| firstname | string or null | |
| lastname | string or null | |
| external_ | string or null | |
| language | string or null | |
| timezone | string or null | |
| note | string or null | |
| meta | object or null | |
| data | any | |
| channels | array of object | |
| active | boolean |
Response
201 · The new customer, with its channels. · CustomerDetail
Request
curl -X POST "https://cs.growthdept.ai/api/customers" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"note": "Prefers email."
}'Response 201
{
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120,
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null,
"user": {
"id": 9120,
"name": "Demo Store"
},
"customer": {
"id": 9120,
"name": "Demo Store"
}
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
}Delete several customers
DELETE/api/customers
Erases the customers given as {ids: [...]}, with their tickets, the messages they sent and their files. Ids that name no customer are skipped, as in Gorgias. This cannot be undone.
Role: lite-agent or higher
Body
| Field | Type | Description |
|---|---|---|
| idsrequired | array of integer or string |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/customers" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
0
]
}'Response 204
(no body)Get a customer
GET/api/customers/{id}
One customer with its channels, field values and store data. A customer merged into another answers 301 with the address of the one it became in Location.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The customer. · CustomerDetail
Request
curl "https://cs.growthdept.ai/api/customers/7311" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120,
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null,
"user": {
"id": 9120,
"name": "Demo Store"
},
"customer": {
"id": 9120,
"name": "Demo Store"
}
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
}Update a customer
PUT/api/customers/{id}
Changes the fields you send. A new email becomes the preferred email channel; channels, when sent, replace the customer's list. As in Gorgias, a body with nothing to change, a channel type it does not list, a language that is not an ISO 639-1 code or an unknown time zone is a 400, and an email that belongs to another customer is a 409.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| string or null | ||
| name | string or null | |
| firstname | string or null | |
| lastname | string or null | |
| external_ | string or null | |
| language | string or null | |
| timezone | string or null | |
| note | string or null | |
| meta | object or null | |
| data | any | |
| channels | array of object | |
| active | boolean |
Response
202 · The customer after the change. · CustomerDetail
Request
curl -X PUT "https://cs.growthdept.ai/api/customers/7311" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "maya.okafor@example.com",
"name": "Demo Store",
"firstname": "Maya"
}'Response 202
{
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120,
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null,
"user": {
"id": 9120,
"name": "Demo Store"
},
"customer": {
"id": 9120,
"name": "Demo Store"
}
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
}Delete a customer
DELETE/api/customers/{id}
Erases the customer: its tickets with their messages, the messages it sent on other tickets, their attachments and its field values. Use it for data deletion requests; it cannot be undone.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/customers/7311" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Merge two customers (POST)
POST/api/customers/merge
Moves everything the source customer has (tickets, messages, channels, field values) onto the target and removes the source. Pass source_id and target_id in the query or the body; other body fields (name, email, ...) are then set on the merged customer.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| source_ | |
| target_ |
Body
| Field | Type | Description |
|---|---|---|
| string or null | ||
| name | string or null | |
| firstname | string or null | |
| lastname | string or null | |
| external_ | string or null | |
| language | string or null | |
| timezone | string or null | |
| note | string or null | |
| meta | object or null | |
| data | any | |
| channels | array of object | |
| active | boolean | |
| source_ | integer or string | |
| target_ | integer or string |
Response
202 · The merged customer. · CustomerDetail
Request
curl -X POST "https://cs.growthdept.ai/api/customers/merge" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "maya.okafor@example.com",
"name": "Demo Store",
"firstname": "Maya"
}'Response 202
{
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120,
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null,
"user": {
"id": 9120,
"name": "Demo Store"
},
"customer": {
"id": 9120,
"name": "Demo Store"
}
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
}Merge two customers
PUT/api/customers/merge
Moves everything the source customer has (tickets, messages, channels, field values) onto the target and removes the source. Pass source_id and target_id in the query or the body; other body fields (name, email, ...) are then set on the merged customer.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| source_ | |
| target_ |
Body
| Field | Type | Description |
|---|---|---|
| string or null | ||
| name | string or null | |
| firstname | string or null | |
| lastname | string or null | |
| external_ | string or null | |
| language | string or null | |
| timezone | string or null | |
| note | string or null | |
| meta | object or null | |
| data | any | |
| channels | array of object | |
| active | boolean | |
| source_ | integer or string | |
| target_ | integer or string |
Response
202 · The merged customer. · CustomerDetail
Request
curl -X PUT "https://cs.growthdept.ai/api/customers/merge" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "maya.okafor@example.com",
"name": "Demo Store",
"firstname": "Maya"
}'Response 202
{
"id": 7311,
"uri": "/api/customers/7311/",
"external_id": null,
"active": true,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"language": "en",
"timezone": "America/Los_Angeles",
"note": null,
"meta": {},
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
]
},
"custom_fields": {
"5": "Where is my order"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"channels": [
{
"id": 9120,
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null,
"user": {
"id": 9120,
"name": "Demo Store"
},
"customer": {
"id": 9120,
"name": "Demo Store"
}
}
],
"integrations": [],
"external_data": {},
"ecommerce_data": {},
"customer": null
}Search customers
POST/api/customers/search
Finds customers whose name, email, other channel address or external id contains the text. order_by is _score:desc (best match first, the default), updated_datetime:desc or updated_datetime:asc. with_highlights marks the matched part of the name and email with <em>.
Parameters
| Name | Description |
|---|---|
| limitquery · string | |
| order_ | |
| with_ |
Body
| Field | Type | Description |
|---|---|---|
| search | string or null | Part of a name, email address or external id. Empty lists customers, most recently updated first. |
Response
200 · A page of matching customers. · object
Request
curl -X POST "https://cs.growthdept.ai/api/customers/search" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"search": null
}'Response 200
{}List a customer's channels
GET/api/customers/{id}/channels
The customer's email addresses, phone numbers and other handles, preferred ones first.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The channels. · list of CustomerChannel
Request
curl \
"https://cs.growthdept.ai/api/customers/7311/channels?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/customers/7311/channels",
"data": [
{
"id": 9120,
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null,
"user": {
"id": 9120,
"name": "Demo Store"
},
"customer": {
"id": 9120,
"name": "Demo Store"
}
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Add a channel to a customer
POST/api/customers/{id}/channels
Adds an address (type and address, optionally preferred). An address another customer has is refused.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| typerequired | string | |
| addressrequired | string | |
| preferred | boolean |
Response
201 · The channel. · CustomerChannel
Request
curl -X POST \
"https://cs.growthdept.ai/api/customers/7311/channels" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "email",
"address": "maya.okafor@example.com"
}'Response 201
{
"id": 9120,
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null,
"user": {
"id": 9120,
"name": "Demo Store"
},
"customer": {
"id": 9120,
"name": "Demo Store"
}
}List a customer's field values
GET/api/customers/{id}/custom-fields
The values of the customer's fields, each as {field, prediction, value} with the field's definition.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The values, as {data: [...]}. · object
Request
curl \
"https://cs.growthdept.ai/api/customers/7311/custom-fields" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 5,
"value": "Where is my order",
"field": {}
}
]
}Replace a customer's field values
PUT/api/customers/{id}/custom-fields
Sets the customer's field values to exactly the list given as [{id, value}], where id is the field's id: fields left out are cleared, and a null value clears that field.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
Any JSON value.
Response
202 · All of the customer's values after the change. · object
Request
curl -X PUT \
"https://cs.growthdept.ai/api/customers/7311/custom-fields" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{}Set a customer's data
PUT/api/customers/{id}/data
Replaces the customer's free-form data with the body's data field (any JSON). Integrations use it to show their own information beside tickets.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| datarequired | any |
Response
202 · Stored. The body is empty, as in Gorgias. · object
Request
curl -X PUT "https://cs.growthdept.ai/api/customers/7311/data" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"orders": [
{
"name": "#1042",
"total": "64.00",
"currency": "USD",
"status": "in_transit"
}
],
"loyalty_tier": "Gold"
}
}'Response 202
{}Get a customer channel
GET/api/customers/{id}/channels/{channelId}
One of the customer's channels.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| channelIdrequiredpath · integer | The channel's id. |
Response
200 · The channel. · CustomerChannel
Request
curl \
"https://cs.growthdept.ai/api/customers/7311/channels/9120" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 9120,
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null,
"user": {
"id": 9120,
"name": "Demo Store"
},
"customer": {
"id": 9120,
"name": "Demo Store"
}
}Update a customer channel
PUT/api/customers/{id}/channels/{channelId}
Changes a channel's address, type or whether it is preferred.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| channelIdrequiredpath · integer | The channel's id. |
Body
| Field | Type | Description |
|---|---|---|
| type | string | |
| address | string | |
| preferred | boolean |
Response
202 · The channel after the change. · CustomerChannel
Request
curl -X PUT \
"https://cs.growthdept.ai/api/customers/7311/channels/9120" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true
}'Response 202
{
"id": 9120,
"type": "email",
"address": "maya.okafor@example.com",
"preferred": true,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null,
"user": {
"id": 9120,
"name": "Demo Store"
},
"customer": {
"id": 9120,
"name": "Demo Store"
}
}Remove a customer channel
DELETE/api/customers/{id}/channels/{channelId}
Removes an address from the customer. If it was the preferred email, the next email address becomes preferred.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| channelIdrequiredpath · integer | The channel's id. |
Response
204 · Removed.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/customers/7311/channels/9120" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Set one customer field
PUT/api/customers/{id}/custom-fields/{fieldId}
Sets one field's value on the customer. The body is the bare JSON value, such as "VIP", 3 or true; {"value": ...} works too. null clears it.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| fieldIdrequiredpath · integer | The customer field's id. |
Body
The value itself, typed by the field's definition.
Response
202 · The field with its new value. · CustomFieldValue
Request
curl -X PUT \
"https://cs.growthdept.ai/api/customers/7311/custom-fields/5" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{
"id": 5,
"value": "Where is my order",
"field": {}
}Clear one customer field
DELETE/api/customers/{id}/custom-fields/{fieldId}
Removes one field's value from the customer. A value that was never set is a 400, as in Gorgias.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| fieldIdrequiredpath · integer | The customer field's id. |
Response
204 · Cleared.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/customers/7311/custom-fields/5" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Users
Agents are the people and bots who work in the helpdesk, each with a role. Gorgias's API calls them users, and so do these paths.
The CustomAvailabilityStatusList object · 1 fields
| Field | Type | Description |
|---|---|---|
| data | array of CustomAvailabilityStatus |
The CustomAvailabilityStatus object · 9 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| name | string | Shown in the account menu and next to the agent's name. At most 30 characters. |
| description | string or null | At most 70 characters. |
| duration_ | integer or null | Minutes after which an agent in this status is available again (5 to 1440); null to stay until changed. |
| enabled | boolean | Switched-off statuses are not offered; agents already in one keep it. |
| position | integer | Order in the menu, lowest first. |
| created_ | datetime or null | |
| updated_ | datetime or null |
The User object · 20 fields
An agent. Gorgias calls agents users.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| string | ||
| name | string or null | |
| firstname | string or null | |
| lastname | string or null | |
| active | boolean | |
| bio | string or null | |
| country | string or null | |
| language | string or null | |
| timezone | string or null | |
| external_ | string or null | |
| meta | object or null | |
| role | object | |
| has_ | boolean | |
| has_ | boolean | |
| client_ | string or null | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| deactivated_ | datetime or null |
The AgentAvailability object · 5 fields
| Field | Type | Description |
|---|---|---|
| user_ | integer | The agent's id. |
| availability | available, busy, offline | busy means away, with the reason in availability_reason. |
| availability_ | string or null | The status's name, or a reason typed by an older client. |
| status_ | integer or null | The custom availability status the agent picked, if any. |
| availability_ | datetime or null | When the status ends and the agent is available again, for a status with a duration. |
The HelpdeskInvite object · 7 fields
An open invite to join the helpdesk's organization.
| Field | Type | Description |
|---|---|---|
| id | string | |
| string | ||
| role | string | Organization role: admin, member or viewer. |
| agent_ | integer or null | The agent profile waiting for this person. |
| agent_ | string or null | The helpdesk role they get when they accept. |
| created_ | datetime | |
| expires_ | datetime |
The TwoFactorStatus object · 2 fields
| Field | Type | Description |
|---|---|---|
| required | boolean | The organization requires two-factor for password sign-ins. |
| users | object | Agent id to whether that agent's account has two-factor on. |
List agent statuses
GET/api/custom-availability-statuses
The unavailable statuses this helpdesk offers, in menu order, switched-off ones included. The list is under data, as Gorgias's app reads it.
Parameters
| Name | Description |
|---|---|
| enabledquery · string | true: only statuses agents can pick now.true, false |
Response
200 · Every status, under data. · CustomAvailabilityStatusList
Request
curl \
"https://cs.growthdept.ai/api/custom-availability-statuses" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"description": null,
"duration_minutes": null,
"enabled": false,
"position": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
]
}Create an agent status
POST/api/custom-availability-statuses
Adds a status agents can pick when they step away. Names are unique ignoring case, and available, away and offline are taken by the built-in statuses. At most 30 per helpdesk. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| name | string | The status's name, at most 30 characters. |
| description | string or null | Optional, at most 70 characters. |
| duration_ | integer or null | Minutes after which the agent is available again, 5 to 1440; null to stay until changed. |
| enabled | boolean | Whether agents can pick it. On by default. |
| position | integer | Order in the menu; new statuses go last. |
Response
201 · The new status. · CustomAvailabilityStatus
Request
curl -X POST \
"https://cs.growthdept.ai/api/custom-availability-statuses" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"description": null,
"duration_minutes": null
}'Response 201
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"description": null,
"duration_minutes": null,
"enabled": false,
"position": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}List agents
GET/api/users
A page of the helpdesk's agents (Gorgias calls them users), bots included, by name unless order_by says otherwise. Deactivated agents are listed with active false.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default name:asc.created_datetime:asc, created_datetime:desc, name:asc, name:desc, email:asc, email:desc, role.name:asc, role.name:desc |
| emailquery · string | The agent with this email. |
| external_ | |
| rolesquery · string or array of string | Only these roles, comma-separated, such as admin,agent. |
| searchquery · string | Agents whose name or email contains this. |
| available_ | true lists available agents before busy and offline ones on each page.0, 1, true, false |
Response
200 · A page of agents. · list of User
Request
curl "https://cs.growthdept.ai/api/users?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/users?limit=2",
"data": [
{
"id": 12,
"uri": "/api/users/12/",
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"active": true,
"bio": null,
"country": null,
"language": "en",
"timezone": "America/Los_Angeles",
"external_id": null,
"meta": {},
"role": {
"name": "agent"
},
"has_password": false,
"has_2fa_enabled": true,
"client_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Add an agent
POST/api/users
Adds an agent with an email, name and role. The agent can be assigned tickets and given API keys at once; it can sign in once a person with that email joins the organization (invite them from Settings, Users).
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| emailrequired | string | |
| name | string or null | |
| firstname | string or null | |
| lastname | string or null | |
| role | admin, lead-agent, agent, basic-agent, lite-agent, observer-agent, bot or object | |
| bio | string or null | |
| country | string or null | |
| language | string or null | |
| timezone | string or null | |
| external_ | string or null | |
| meta | object or null |
Response
201 · The new agent. · User
Request
curl -X POST "https://cs.growthdept.ai/api/users" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "maya.okafor@example.com"
}'Response 201
{
"id": 12,
"uri": "/api/users/12/",
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"active": true,
"bio": null,
"country": null,
"language": "en",
"timezone": "America/Los_Angeles",
"external_id": null,
"meta": {},
"role": {
"name": "agent"
},
"has_password": false,
"has_2fa_enabled": true,
"client_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Get an agent status
GET/api/custom-availability-statuses/{id}
One unavailable status.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The status's id. |
Response
200 · The status. · CustomAvailabilityStatus
Request
curl \
"https://cs.growthdept.ai/api/custom-availability-statuses/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"description": null,
"duration_minutes": null,
"enabled": false,
"position": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Update an agent status
PUT/api/custom-availability-statuses/{id}
Renames a status or changes its description, duration, order or switch. Agents already in it keep it; a new duration applies the next time someone picks it. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The status's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | The status's name, at most 30 characters. |
| description | string or null | Optional, at most 70 characters. |
| duration_ | integer or null | Minutes after which the agent is available again, 5 to 1440; null to stay until changed. |
| enabled | boolean | Whether agents can pick it. On by default. |
| position | integer | Order in the menu; new statuses go last. |
Response
200 · The status after the change. · CustomAvailabilityStatus
Request
curl -X PUT \
"https://cs.growthdept.ai/api/custom-availability-statuses/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"description": null,
"duration_minutes": null
}'Response 200
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"description": null,
"duration_minutes": null,
"enabled": false,
"position": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Delete an agent status
DELETE/api/custom-availability-statuses/{id}
Deletes a status. Agents in it stay away under its name until they change their status or its time runs out. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The status's id. |
Response
204 · Deleted.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/custom-availability-statuses/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)List agents' availability
GET/api/helpdesk/availability
Every active agent's current status, away reason, the status they picked and when it ends, for the availability page and assignment.
Response
200 · Each agent's status. · list of AgentAvailability
Request
curl \
"https://cs.growthdept.ai/api/helpdesk/availability?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/helpdesk/availability",
"data": [
{
"user_id": 12,
"availability": "available",
"availability_reason": null,
"status_id": null,
"availability_until": "2026-11-04T09:41:12+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Set an agent's availability
PUT/api/helpdesk/availability
Sets one agent's status. Anyone can set their own; changing another agent needs an admin. Send status_id to pick one of the helpdesk's statuses: the agent is away under its name and, when it has a duration, available again when the time is up. The reason is kept only while the agent is away. Only available agents count as online for live chat.
Body
| Field | Type | Description |
|---|---|---|
| user_ | integer | The agent, or 0 for yourself. |
| availability | available, busy, offline | Required unless status_id is given. |
| availability_ | string or null | A reason for busy, when no status_id is given. |
| status_ | integer or null | One of the helpdesk's switched-on statuses (GET /api/custom-availability-statuses). Sets busy with the status's name, and its end time when it has a duration. |
Response
200 · The agent's status after the change. · AgentAvailability
Request
curl -X PUT \
"https://cs.growthdept.ai/api/helpdesk/availability" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": 12
}'Response 200
{
"user_id": 12,
"availability": "available",
"availability_reason": null,
"status_id": null,
"availability_until": "2026-11-04T09:41:12+00:00"
}List open invites
GET/api/helpdesk/invites
Invites that have not been accepted, withdrawn or expired, with the helpdesk role each person will get when they accept.
Role: admin or higher
Response
200 · The open invites. · list of HelpdeskInvite
Request
curl \
"https://cs.growthdept.ai/api/helpdesk/invites?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/helpdesk/invites",
"data": [
{
"id": "",
"email": "maya.okafor@example.com",
"role": "",
"agent_id": null,
"agent_role": null,
"created_at": "2026-11-04T09:41:12+00:00",
"expires_at": "2026-11-04T09:41:12+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Invite an agent
POST/api/helpdesk/invites
Creates an invite for one email address and the agent profile it will attach to, with the helpdesk role and teams chosen, and emails the link when email is on. The link is returned once, and message says whether the email went out, so it can be passed on by hand if not. Inviting an admin needs an organization admin or owner.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| emailrequired | string | |
| name | string or null | |
| role | admin, lead-agent, agent, basic-agent, lite-agent, observer-agent | |
| team_ | array of integer |
Response
201 · The invite link and the waiting agent profile. · object
Request
curl -X POST "https://cs.growthdept.ai/api/helpdesk/invites" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "maya.okafor@example.com"
}'Response 201
{}List agents' two-factor state
GET/api/helpdesk/two-factor
For each agent who can sign in, whether their account uses an authenticator app, and whether the organization requires one.
Role: admin or higher
Response
200 · Two-factor state by agent. · TwoFactorStatus
Request
curl "https://cs.growthdept.ai/api/helpdesk/two-factor" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"required": false,
"users": {}
}Get an agent
GET/api/users/{id}
One agent by id. GET /api/users/0 returns the agent the API key or session belongs to.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The agent's id, or 0 for yourself. |
Response
200 · The agent. · User
Request
curl "https://cs.growthdept.ai/api/users/12" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 12,
"uri": "/api/users/12/",
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"active": true,
"bio": null,
"country": null,
"language": "en",
"timezone": "America/Los_Angeles",
"external_id": null,
"meta": {},
"role": {
"name": "agent"
},
"has_password": false,
"has_2fa_enabled": true,
"client_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Update an agent
PUT/api/users/{id}
Changes an agent's name, bio, language, time zone, external id or metadata. Agents may change their own profile; changing someone else, a role or whether an agent is active needs an admin. The helpdesk always keeps at least one active admin.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The agent's id, or 0 for yourself. |
Body
| Field | Type | Description |
|---|---|---|
| string | ||
| name | string or null | |
| firstname | string or null | |
| lastname | string or null | |
| role | admin, lead-agent, agent, basic-agent, lite-agent, observer-agent, bot or object | |
| bio | string or null | |
| country | string or null | |
| language | string or null | |
| timezone | string or null | |
| external_ | string or null | |
| meta | object or null | |
| active | boolean |
Response
202 · The agent after the change. · User
Request
curl -X PUT "https://cs.growthdept.ai/api/users/12" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "maya.okafor@example.com",
"name": "Demo Store",
"firstname": "Maya"
}'Response 202
{
"id": 12,
"uri": "/api/users/12/",
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"active": true,
"bio": null,
"country": null,
"language": "en",
"timezone": "America/Los_Angeles",
"external_id": null,
"meta": {},
"role": {
"name": "agent"
},
"has_password": false,
"has_2fa_enabled": true,
"client_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Remove an agent
DELETE/api/users/{id}
Deactivates the agent and revokes its API keys. Tickets it worked keep it as their assignee, so their history still reads correctly.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The agent's id, or 0 for yourself. |
Response
204 · Removed.
Request
curl -X DELETE "https://cs.growthdept.ai/api/users/12" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Withdraw an invite
DELETE/api/helpdesk/invites/{id}
Stops an open invite link from working and removes the agent profile that was waiting for it.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · string | The invite's id. |
Response
204 · The invite was withdrawn.
Request
curl -X DELETE "https://cs.growthdept.ai/api/helpdesk/invites/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)API keys
Each API key belongs to one agent and acts with that agent's role. The full key is returned once, when it is created; after that only its first characters are shown. A revoked key stops working on the next request.
The ApiKey object · 8 fields
| Field | Type | Description |
|---|---|---|
| id | string | |
| name | string | |
| prefix | string | The first characters of the key, to tell keys apart. |
| key | string | The full key. Returned once, when the key is created. |
| user_ | integer | |
| created_ | datetime or null | |
| last_ | datetime or null | |
| revoked_ | datetime or null |
List an agent's API keys
GET/api/users/{id}/api-keys
The agent's keys, newest first, with when each was last used. The keys themselves are never shown again after they are made. Agents see their own keys; admins see anyone's.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The agent's id, or 0 for yourself. |
Response
200 · The keys. · list of ApiKey
Request
curl \
"https://cs.growthdept.ai/api/users/12/api-keys?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/users/12/api-keys",
"data": [
{
"id": "",
"name": "Demo Store",
"prefix": "7c1e0b",
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"user_id": 12,
"created_datetime": "2026-11-04T09:41:12+00:00",
"last_used_datetime": null,
"revoked_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Make an API key
POST/api/users/{id}/api-keys
Makes a key for the agent and returns it once, in key. Store it then: only its first characters are kept for display. Keys are made from the app while signed in (Settings, REST API), not with another key.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The agent's id, or 0 for yourself. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | A label, such as the tool that will use the key. |
Response
201 · The new key, including the key itself. · ApiKey
Request
curl -X POST "https://cs.growthdept.ai/api/users/12/api-keys" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store"
}'Response 201
{
"id": "",
"name": "Demo Store",
"prefix": "7c1e0b",
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"user_id": 12,
"created_datetime": "2026-11-04T09:41:12+00:00",
"last_used_datetime": null,
"revoked_datetime": null
}Revoke an API key
DELETE/api/users/{id}/api-keys/{keyId}
Stops the key working at once. Agents can revoke their own keys; admins can revoke anyone's.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The agent's id, or 0 for yourself. |
| keyIdrequiredpath · string | The key's id (a uuid). |
Response
204 · Revoked.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/users/12/api-keys/k8f2a61c" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Teams
Teams group agents. Tickets can be assigned to a team as well as, or instead of, a person.
The Team object · 9 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| name | string | |
| description | string or null | |
| decoration | object or null | Emoji and colour. |
| default_ | integer or null | The mailbox the team's replies go out from. |
| members | array of object | |
| created_ | datetime or null | |
| updated_ | datetime or null |
List teams
GET/api/teams
The helpdesk's teams with their members.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc, name:asc, name:desc |
Response
200 · A page of teams. · list of Team
Request
curl "https://cs.growthdept.ai/api/teams?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/teams?limit=2",
"data": [
{
"id": 3,
"uri": "/api/teams/3/",
"name": "Orders",
"description": null,
"decoration": {
"color": "#2546e8"
},
"default_email_integration_id": null,
"members": [
{
"id": 3,
"name": "Orders",
"email": "maya.okafor@example.com",
"meta": {}
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a team
POST/api/teams
Adds a team with a name, optional description and decoration (emoji, colour) and members given as [{id}].
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| description | string or null | |
| decoration | object or null | |
| default_ | integer or string | The mailbox the team's replies go out from. |
| members | array of object |
Response
201 · The new team. · Team
Request
curl -X POST "https://cs.growthdept.ai/api/teams" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Returns",
"members": [
{
"id": 12
},
{
"id": 15
}
]
}'Response 201
{
"id": 3,
"uri": "/api/teams/3/",
"name": "Orders",
"description": null,
"decoration": {
"color": "#2546e8"
},
"default_email_integration_id": null,
"members": [
{
"id": 3,
"name": "Orders",
"email": "maya.okafor@example.com",
"meta": {}
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Get a team
GET/api/teams/{id}
One team with its members.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The team. · Team
Request
curl "https://cs.growthdept.ai/api/teams/3" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 3,
"uri": "/api/teams/3/",
"name": "Orders",
"description": null,
"decoration": {
"color": "#2546e8"
},
"default_email_integration_id": null,
"members": [
{
"id": 3,
"name": "Orders",
"email": "maya.okafor@example.com",
"meta": {}
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Update a team
PUT/api/teams/{id}
Changes the team's name, description or decoration. members, when sent as [{id}], replaces the member list.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| description | string or null | |
| decoration | object or null | |
| default_ | integer or string | The mailbox the team's replies go out from. |
| members | array of object |
Response
202 · The team after the change. · Team
Request
curl -X PUT "https://cs.growthdept.ai/api/teams/3" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"description": null,
"decoration": {
"color": "#2546e8"
}
}'Response 202
{
"id": 3,
"uri": "/api/teams/3/",
"name": "Orders",
"description": null,
"decoration": {
"color": "#2546e8"
},
"default_email_integration_id": null,
"members": [
{
"id": 3,
"name": "Orders",
"email": "maya.okafor@example.com",
"meta": {}
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Delete a team
DELETE/api/teams/{id}
Deletes the team. Tickets assigned to it lose the team assignment; their agent assignment stays.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/teams/3" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)List a team's members
GET/api/teams/{id}/members
The agents in one team.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The members. · list of User
Request
curl \
"https://cs.growthdept.ai/api/teams/3/members?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/teams/3/members",
"data": [
{
"id": 12,
"uri": "/api/users/12/",
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"active": true,
"bio": null,
"country": null,
"language": "en",
"timezone": "America/Los_Angeles",
"external_id": null,
"meta": {},
"role": {
"name": "agent"
},
"has_password": false,
"has_2fa_enabled": true,
"client_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Add agents to a team
POST/api/teams/{id}/members
Adds the agents given as {ids: [...]}. Agents already in the team are left as they are.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| idsrequired | array of integer or string |
Response
201 · The team's members after the change. · list of User
Request
curl -X POST \
"https://cs.growthdept.ai/api/teams/3/members?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
0
]
}'Response 201
{
"object": "list",
"uri": "/api/teams/3/members",
"data": [
{
"id": 12,
"uri": "/api/users/12/",
"email": "ana@demostore.example",
"name": "Ana Ruiz",
"firstname": "Ana",
"lastname": "Ruiz",
"active": true,
"bio": null,
"country": null,
"language": "en",
"timezone": "America/Los_Angeles",
"external_id": null,
"meta": {},
"role": {
"name": "agent"
},
"has_password": false,
"has_2fa_enabled": true,
"client_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Remove agents from a team
DELETE/api/teams/{id}/members
Removes the agents given as {ids: [...]} from the team.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| idsrequired | array of integer or string |
Response
204 · Removed.
Request
curl -X DELETE "https://cs.growthdept.ai/api/teams/3/members" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
0
]
}'Response 204
(no body)Macros
Macros are saved replies with actions. Their text can use template variables, filled in for each ticket when the macro is applied.
The Macro object · 11 fields
A saved reply with ticket changes.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| external_ | string or null | |
| name | string | |
| intent | string or null | |
| language | string or null | |
| actions | array of object | What the macro does, in order. |
| usage | integer | How many times agents have used it. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| archived_ | datetime or null |
The MacroApplication object · 8 fields
| Field | Type | Description |
|---|---|---|
| reply | object or null | The drafted reply: body_text, body_html and attachments. |
| patch | object | Ticket fields the macro changes. |
| addTags | array of string | |
| removeTags | array of string | |
| customFields | array of object | |
| internalNotes | array of object | |
| forwards | array of object | |
| actions | array of object |
List macros
GET/api/macros
Macros, most used first unless order_by says otherwise. search matches every word you give in the name, the reply text or the tags the macro adds. tags and languages keep macros that add one of the tags or are written in one of the languages. order_by=relevance and number_predictions need ticket_id: the macros that fit that ticket come first. Archived macros are left out; archived=true lists only them.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default usage:desc.created_datetime:asc, created_datetime:desc, updated_datetime:asc, updated_datetime:desc, name:asc, name:desc, usage:asc, usage:desc, language:asc, language:desc |
| searchquery · string | Words in the macro's name, reply text or tags. Every word must appear. |
| archivedquery · string | Archived or active macros only.0, 1, true, false |
| languagesquery · string or array of string | Only macros written in these languages, comma-separated, such as en,fr. |
| tagsquery · string or array of string | Only macros that add one of these tags, comma-separated. |
| ticket_ | The ticket the macros are for; needed for relevance ordering and predictions. |
| message_ | A message of that ticket. Accepted so Gorgias clients keep working. |
| number_ | How many macros to put first because they fit the ticket (needs ticket_id). |
Response
200 · A page of macros. · list of Macro
Request
curl "https://cs.growthdept.ai/api/macros?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/macros?limit=2",
"data": [
{
"id": 41,
"uri": "/api/macros/41/",
"external_id": null,
"name": "Shipping delay",
"intent": null,
"language": "en",
"actions": [
{
"name": "Shipping delay",
"title": null,
"type": "email",
"arguments": {}
}
],
"usage": 142,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a macro
POST/api/macros
Creates a macro. Each action is checked: setResponseText needs a body, setStatus a status, and so on. Replies can use template variables such as {{ticket.customer.firstname}}.
Role: lead-agent or higher
Body
Any JSON value.
Response
201 · The new macro. · Macro
Request
curl -X POST "https://cs.growthdept.ai/api/macros" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Shipping delay",
"actions": [
{
"name": "setResponseText",
"title": "Reply",
"type": "user",
"arguments": {
"body_text": "Hi {{ticket.customer.firstname}}, thanks for waiting. Your order is with the carrier and we have asked them to trace it."
}
},
{
"name": "addTags",
"title": "Add tags",
"type": "user",
"arguments": {
"tags": "shipping"
}
}
]
}'Response 201
{
"id": 41,
"uri": "/api/macros/41/",
"external_id": null,
"name": "Shipping delay",
"intent": null,
"language": "en",
"actions": [
{
"name": "Shipping delay",
"title": null,
"type": "email",
"arguments": {}
}
],
"usage": 142,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null
}Get a macro
GET/api/macros/{id}
One macro with its actions.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The macro's id. |
Response
200 · The macro. · Macro
Request
curl "https://cs.growthdept.ai/api/macros/41" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 41,
"uri": "/api/macros/41/",
"external_id": null,
"name": "Shipping delay",
"intent": null,
"language": "en",
"actions": [
{
"name": "Shipping delay",
"title": null,
"type": "email",
"arguments": {}
}
],
"usage": 142,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null
}Change a macro
PUT/api/macros/{id}
Changes the fields sent. actions replaces the whole list. archived: true archives the macro and false restores it.
Role: lead-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The macro's id. |
Body
Any JSON value.
Response
202 · The macro after the change. · Macro
Request
curl -X PUT "https://cs.growthdept.ai/api/macros/41" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{
"id": 41,
"uri": "/api/macros/41/",
"external_id": null,
"name": "Shipping delay",
"intent": null,
"language": "en",
"actions": [
{
"name": "Shipping delay",
"title": null,
"type": "email",
"arguments": {}
}
],
"usage": 142,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null
}Delete a macro
DELETE/api/macros/{id}
Deletes a macro for good. Archive it instead to keep its history.
Role: lead-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The macro's id. |
Response
204 · The macro was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/macros/41" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Archive macros
PUT/api/macros/archive
Archives the macros listed in ids. Archived macros are hidden from the composer and keep their usage count. Answers 207 with a status per id: archived, already_archived or not_found.
Role: lead-agent or higher
Body
| Field | Type | Description |
|---|---|---|
| idsrequired | array of number or string |
Response
207 · One result per id. · object
Request
curl -X PUT "https://cs.growthdept.ai/api/macros/archive" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
0
]
}'Response 207
{
"data": {
"data": [
{
"id": 1,
"status": "open"
}
]
}
}Restore archived macros
PUT/api/macros/unarchive
Makes the archived macros listed in ids available again. Answers 207 with a status per id: unarchived, already_not_archived or not_found.
Role: lead-agent or higher
Body
| Field | Type | Description |
|---|---|---|
| idsrequired | array of number or string |
Response
207 · One result per id. · object
Request
curl -X PUT "https://cs.growthdept.ai/api/macros/unarchive" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
0
]
}'Response 207
{
"data": {
"data": [
{
"id": 1,
"status": "open"
}
]
}
}Preview a macro on a ticket
POST/api/macros/{id}/apply
Shows what the macro would do to a ticket without changing it: the drafted reply with its variables filled in, the tags it adds and removes, and the fields it sets. Send the reply as a message with macros: [{id}] to use it; that counts one use.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The macro's id. |
Body
| Field | Type | Description |
|---|---|---|
| ticket_ | integer |
Response
200 · The reply and changes the macro makes. · MacroApplication
Request
curl -X POST "https://cs.growthdept.ai/api/macros/41/apply" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ticket_id": 4182
}'Response 200
{
"reply": {},
"patch": {},
"addTags": [
""
],
"removeTags": [
""
],
"customFields": [
{}
],
"internalNotes": [
{}
],
"forwards": [
{}
],
"actions": [
{
"name": "Demo Store",
"title": null,
"type": "email",
"arguments": {}
}
]
}Rules
Rules run on ticket events, in priority order, and act on the ticket. Their code uses the filter expression language for conditions and a fixed list of actions; a rule the helpdesk cannot run is refused when you save it.
The Rule object · 13 fields
When something happens to a ticket, if conditions match, take actions.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| name | string | |
| description | string or null | |
| type | user, system, managed | |
| event_ | string | Comma-separated: ticket-created, ticket-updated, ticket-message-created. |
| code | string | The rule in the expression language: if blocks and Action(...) calls. |
| code_ | object or null | The parsed code (an ESTree Program). |
| settings | object or null | |
| priority | integer | Rules with a higher priority run first. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| deactivated_ | datetime or null |
List rules
GET/api/rules
Rules, newest first unless order_by=created_datetime:asc (the only two orders, as in Gorgias; sort by priority to see the order they run in). search keeps the rules whose name contains the text.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| searchquery · string | Only rules whose name contains this. |
Response
200 · A page of rules. · list of Rule
Request
curl "https://cs.growthdept.ai/api/rules?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/rules?limit=2",
"data": [
{
"id": 7,
"uri": "/api/rules/7/",
"name": "Tag shipping questions",
"description": null,
"type": "user",
"event_types": "ticket-created",
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"code_ast": {},
"settings": {},
"priority": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a rule
POST/api/rules
Creates a rule from code (if blocks and Action(...) calls), code_ast, or structured (the editor's form, which generates the code). Conditions and actions are checked before the rule is saved. New rules go to the top of the order unless priority is given.
Role: admin or higher
Body
Any JSON value.
Response
201 · The new rule. · Rule
Request
curl -X POST "https://cs.growthdept.ai/api/rules" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Tag shipping questions",
"event_types": "ticket-created",
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"priority": 1
}'Response 201
{
"id": 7,
"uri": "/api/rules/7/",
"name": "Tag shipping questions",
"description": null,
"type": "user",
"event_types": "ticket-created",
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"code_ast": {},
"settings": {},
"priority": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Get a rule
GET/api/rules/{id}
One rule with its code and parsed code.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The rule's id. |
Response
200 · The rule. · Rule
Request
curl "https://cs.growthdept.ai/api/rules/7" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 7,
"uri": "/api/rules/7/",
"name": "Tag shipping questions",
"description": null,
"type": "user",
"event_types": "ticket-created",
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"code_ast": {},
"settings": {},
"priority": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Change a rule
PUT/api/rules/{id}
Changes the fields sent. active: false (or a deactivated_datetime) turns the rule off; active: true turns it back on.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The rule's id. |
Body
Any JSON value.
Response
202 · The rule after the change. · Rule
Request
curl -X PUT "https://cs.growthdept.ai/api/rules/7" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{
"id": 7,
"uri": "/api/rules/7/",
"name": "Tag shipping questions",
"description": null,
"type": "user",
"event_types": "ticket-created",
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"code_ast": {},
"settings": {},
"priority": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Delete a rule
DELETE/api/rules/{id}
Deletes a rule. Its past runs stay in the ticket timelines.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The rule's id. |
Response
204 · The rule was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/rules/7" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Set rule priorities
POST/api/rules/priorities
Sets the priority of the rules you list, like PUT, and answers with every rule in the helpdesk in the order they run (highest priority first, then oldest), as a plain array. Rules you leave out keep their priority.
Role: admin or higher
Body
Any JSON value.
Response
201 · Every rule, in run order. · array of Rule
Request
curl -X POST "https://cs.growthdept.ai/api/rules/priorities" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"priorities": [
{
"id": 7,
"priority": 2
},
{
"id": 9,
"priority": 1
}
]
}'Response 201
[
{
"id": 7,
"uri": "/api/rules/7/",
"name": "Tag shipping questions",
"description": null,
"type": "user",
"event_types": "ticket-created",
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"code_ast": {},
"settings": {},
"priority": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
]Reorder rules
PUT/api/rules/priorities
Sets the priority of several rules at once. Rules with a higher priority run first.
Role: admin or higher
Body
Any JSON value.
Response
200 · The rules that changed, in run order. · list of Rule
Request
curl -X PUT \
"https://cs.growthdept.ai/api/rules/priorities?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 200
{
"object": "list",
"uri": "/api/rules/priorities",
"data": [
{
"id": 7,
"uri": "/api/rules/7/",
"name": "Tag shipping questions",
"description": null,
"type": "user",
"event_types": "ticket-created",
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"code_ast": {},
"settings": {},
"priority": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Tickets a rule ran on
GET/api/rules/{id}/affected-tickets
The last 100 tickets the rule has run on, newest run first, with when it last ran on each and how many times. A rule that has not run yet has an empty list.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The rule's id. |
Response
200 · The tickets. · object
Request
curl \
"https://cs.growthdept.ai/api/rules/7/affected-tickets" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{}
]
}Views
Views are saved filters over tickets or customers, stored as expressions such as eq(ticket.status, "open"). A view's items are what it shows right now.
The ViewSection object · 8 fields
A group of views in the sidebar.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| name | string | |
| private | boolean | |
| decoration | object or null | |
| display_ | integer | |
| created_ | datetime or null | |
| updated_ | datetime or null |
The View object · 22 fields
A saved list of tickets or customers.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| name | string | |
| slug | string | |
| type | ticket-list, customer-list | |
| category | system, user, team | |
| visibility | public, private, shared | public: every agent. private: its owner. shared: its owner, shared_with_users and members of shared_with_teams. |
| filters | string | The filter expression, for example eq(ticket.status, "open") && isEmpty(ticket.assignee_user.id). |
| filters_ | object or null | The parsed filter (an ESTree Program). |
| search | string or null | Words the items must also match. |
| order_ | string | The field items are sorted by. |
| order_ | asc, desc | |
| fields | array of string | Columns shown in the list. |
| decoration | object or null | Emoji and colour. |
| section_ | integer or null | |
| shared_ | array of integer | |
| shared_ | array of integer | |
| display_ | integer | |
| owner_ | integer or null | The agent who created the view. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| deactivated_ | datetime or null |
The ViewCount object · 4 fields
| Field | Type | Description |
|---|---|---|
| id | integer | The view's id. |
| count | integer | Items in the view, up to the cap. |
| capped | boolean | True when the view holds more than 10,000 items. |
| error | string or null | Set when the view's filter could not be read. |
The ViewItems object · 2 fields
| Field | Type | Description |
|---|---|---|
| data | array of object | Tickets (or customers) in list form. |
| meta | object |
List view sections
GET/api/view-sections
The sidebar sections the caller can see: every shared section and the caller's private ones.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:desc |
Response
200 · A page of sections. · list of ViewSection
Request
curl \
"https://cs.growthdept.ai/api/view-sections?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/view-sections?limit=2",
"data": [
{
"id": 2,
"uri": "/api/view-sections/2/",
"name": "Orders team",
"private": false,
"decoration": {
"color": "#2546e8"
},
"display_order": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a view section
POST/api/view-sections
Creates a section. private is required, as in Gorgias, and is fixed once the section exists. Agents can create private sections; shared ones need a lead agent or admin.
Role: lite-agent or higher
Body
Any JSON value.
Response
201 · The new section. · ViewSection
Request
curl -X POST "https://cs.growthdept.ai/api/view-sections" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 201
{
"id": 2,
"uri": "/api/view-sections/2/",
"name": "Orders team",
"private": false,
"decoration": {
"color": "#2546e8"
},
"display_order": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}List views
GET/api/views
The views the caller can see: every public view, the caller's private views and views shared with the caller or one of their teams.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| categoryquery · string | system, user, team |
Response
200 · A page of views. · list of View
Request
curl "https://cs.growthdept.ai/api/views?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/views?limit=2",
"data": [
{
"id": 25,
"uri": "/api/views/25/",
"name": "Unassigned shipping",
"slug": "unassigned-shipping",
"type": "ticket-list",
"category": "system",
"visibility": "shared",
"filters": "eq(ticket.status, \"open\") && isEmpty(ticket.assignee_user.id) && containsAll(ticket.tags.name, [\"shipping\"])",
"filters_ast": {},
"search": null,
"order_by": "last_message_datetime",
"order_dir": "desc",
"fields": [
""
],
"decoration": {
"color": "#2546e8"
},
"section_id": 2,
"shared_with_users": [
0
],
"shared_with_teams": [
0
],
"display_order": 1,
"owner_user_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a view
POST/api/views
Creates a view. Agents can create private views; public and shared views need a lead agent or admin. The filter is checked when the view is saved.
Role: lite-agent or higher
Body
Any JSON value.
Response
201 · The new view. · View
Request
curl -X POST "https://cs.growthdept.ai/api/views" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Unassigned shipping",
"type": "ticket-list",
"filters": "eq(ticket.status, \"open\") && isEmpty(ticket.assignee_user.id) && containsAll(ticket.tags.name, [\"shipping\"])",
"order_by": "last_message_datetime",
"order_dir": "asc",
"visibility": "shared",
"shared_with_teams": [
3
]
}'Response 201
{
"id": 25,
"uri": "/api/views/25/",
"name": "Unassigned shipping",
"slug": "unassigned-shipping",
"type": "ticket-list",
"category": "system",
"visibility": "shared",
"filters": "eq(ticket.status, \"open\") && isEmpty(ticket.assignee_user.id) && containsAll(ticket.tags.name, [\"shipping\"])",
"filters_ast": {},
"search": null,
"order_by": "last_message_datetime",
"order_dir": "desc",
"fields": [
""
],
"decoration": {
"color": "#2546e8"
},
"section_id": 2,
"shared_with_users": [
0
],
"shared_with_teams": [
0
],
"display_order": 1,
"owner_user_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Get a view section
GET/api/view-sections/{id}
One sidebar section, when the caller can see it.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The section's id. |
Response
200 · The section. · ViewSection
Request
curl "https://cs.growthdept.ai/api/view-sections/2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 2,
"uri": "/api/view-sections/2/",
"name": "Orders team",
"private": false,
"decoration": {
"color": "#2546e8"
},
"display_order": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Change a view section
PUT/api/view-sections/{id}
Renames, reorders or re-decorates a section, or makes it private or shared.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The section's id. |
Body
Any JSON value.
Response
202 · The section after the change. · ViewSection
Request
curl -X PUT "https://cs.growthdept.ai/api/view-sections/2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{
"id": 2,
"uri": "/api/view-sections/2/",
"name": "Orders team",
"private": false,
"decoration": {
"color": "#2546e8"
},
"display_order": 1,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Delete a view section
DELETE/api/view-sections/{id}
Deletes a section. Its views stay and are no longer in a section.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The section's id. |
Response
204 · The section was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/view-sections/2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Get a view
GET/api/views/{id}
One view, when the caller can see it.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The view's id. |
Response
200 · The view. · View
Request
curl "https://cs.growthdept.ai/api/views/25" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 25,
"uri": "/api/views/25/",
"name": "Unassigned shipping",
"slug": "unassigned-shipping",
"type": "ticket-list",
"category": "system",
"visibility": "shared",
"filters": "eq(ticket.status, \"open\") && isEmpty(ticket.assignee_user.id) && containsAll(ticket.tags.name, [\"shipping\"])",
"filters_ast": {},
"search": null,
"order_by": "last_message_datetime",
"order_dir": "desc",
"fields": [
""
],
"decoration": {
"color": "#2546e8"
},
"section_id": 2,
"shared_with_users": [
0
],
"shared_with_teams": [
0
],
"display_order": 1,
"owner_user_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Change a view
PUT/api/views/{id}
Changes the fields sent and leaves the rest. Built-in views can be renamed, reordered and moved between sections; their filters stay fixed.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The view's id. |
Body
Any JSON value.
Response
202 · The view after the change. · View
Request
curl -X PUT "https://cs.growthdept.ai/api/views/25" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{
"id": 25,
"uri": "/api/views/25/",
"name": "Unassigned shipping",
"slug": "unassigned-shipping",
"type": "ticket-list",
"category": "system",
"visibility": "shared",
"filters": "eq(ticket.status, \"open\") && isEmpty(ticket.assignee_user.id) && containsAll(ticket.tags.name, [\"shipping\"])",
"filters_ast": {},
"search": null,
"order_by": "last_message_datetime",
"order_dir": "desc",
"fields": [
""
],
"decoration": {
"color": "#2546e8"
},
"section_id": 2,
"shared_with_users": [
0
],
"shared_with_teams": [
0
],
"display_order": 1,
"owner_user_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Delete a view
DELETE/api/views/{id}
Deletes a view the caller manages. Built-in views cannot be deleted.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The view's id. |
Response
204 · The view was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/views/25" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Count items in views
GET/api/views/counts
How many items each view holds for the caller, for the sidebar. Pass ids=1,2,3 for chosen views, or nothing for every active view the caller can see (up to 100). Counts stop at 10,000.
Parameters
| Name | Description |
|---|---|
| idsquery · string or array of string | View ids, comma-separated. |
Response
200 · One count per view. · list of ViewCount
Request
curl \
"https://cs.growthdept.ai/api/views/counts?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/views/counts",
"data": [
{
"id": 1,
"count": 0,
"capped": false,
"error": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Count items in many views
POST/api/views/counts
The same as GET /api/views/counts, with the view ids in the body as {"ids": [...]}, for long lists.
Body
| Field | Type | Description |
|---|---|---|
| idsrequired | array of number or string |
Response
200 · One count per view. · list of ViewCount
Request
curl -X POST \
"https://cs.growthdept.ai/api/views/counts?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ids": [
0
]
}'Response 200
{
"object": "list",
"uri": "/api/views/counts",
"data": [
{
"id": 1,
"count": 0,
"capped": false,
"error": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}List a view's items
GET/api/views/{id}/items
The tickets (or customers) in a view, in the view's order, a page at a time. meta.next_items is the path of the next page.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The view's id. |
| limitquery · string | |
| cursorquery · string | |
| directionquery · string | next, prev |
| order_ | |
| ignored_ |
Response
200 · A page of items. · ViewItems
Request
curl "https://cs.growthdept.ai/api/views/25/items" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{}
],
"meta": {
"next_items": null,
"prev_items": null,
"current_cursor": null,
"next_cursor": null,
"prev_cursor": null
}
}Preview a view's items
PUT/api/views/{id}/items
Lists the items an unsaved view would hold. Send {"view": {...}} with the filters, type, search and order to try; id 0 previews a new view, another id starts from that view.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The view's id. |
| limitquery · string | |
| cursorquery · string | |
| directionquery · string | next, prev |
| order_ | |
| ignored_ |
Body
| Field | Type | Description |
|---|---|---|
| view | object |
Response
202 · A page of items. · ViewItems
Request
curl -X PUT "https://cs.growthdept.ai/api/views/25/items" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"view": {}
}'Response 202
{
"data": [
{}
],
"meta": {
"next_items": null,
"prev_items": null,
"current_cursor": null,
"next_cursor": null,
"prev_cursor": null
}
}Custom fields
Fields you define for tickets and customers: text, numbers, yes or no, and dropdowns. Set their values on each ticket or customer.
The CustomField object · 14 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| external_ | string or null | |
| object_ | Ticket, Customer | |
| label | string | |
| description | string or null | |
| priority | integer | |
| required | boolean | |
| requirement_ | visible, required, conditional | |
| managed_ | string or null | |
| definition | object | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| deactivated_ | datetime or null |
List ticket or customer fields
GET/api/custom-fields
The fields of one object type (object_type=Ticket or Customer, any letter case, required as in Gorgias), highest priority first; order_by takes priority:asc or priority:desc. search keeps the fields whose label contains the text; archived=true lists only turned-off fields.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default priority:desc.priority:asc, priority:desc |
| object_ | |
| searchquery · string | Only fields whose label contains this. |
| archivedquery · string | 0, 1, true, false |
Response
200 · A page of fields. · list of CustomField
Request
curl \
"https://cs.growthdept.ai/api/custom-fields?limit=2&object_type=Ticket" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/custom-fields?limit=2",
"data": [
{
"id": 5,
"uri": "/api/custom-fields/5/",
"external_id": null,
"object_type": "Ticket",
"label": "Reason for contact",
"description": null,
"priority": 1,
"required": false,
"requirement_type": "visible",
"managed_type": null,
"definition": {
"data_type": "text",
"input_settings": {}
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a field
POST/api/custom-fields
Creates a ticket or customer field. definition.data_type is text, number, boolean or date; a dropdown lists its choices in definition.input_settings.choices.
Role: admin or higher
Body
Any JSON value.
Response
201 · The new field. · CustomField
Request
curl -X POST "https://cs.growthdept.ai/api/custom-fields" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 201
{
"id": 5,
"uri": "/api/custom-fields/5/",
"external_id": null,
"object_type": "Ticket",
"label": "Reason for contact",
"description": null,
"priority": 1,
"required": false,
"requirement_type": "visible",
"managed_type": null,
"definition": {
"data_type": "text",
"input_settings": {}
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Change several fields
PUT/api/custom-fields
Changes several fields at once, for example to reorder them: send a list of objects, each with an id and the fields to change. As in Gorgias, no two fields of one object type may end up with the same priority: swapping priorities in one request is fine, taking a priority another field keeps is a 400 on that item.
Role: admin or higher
Body (array of object)
Any JSON value.
Response
202 · The fields after the change. · list of CustomField
Request
curl -X PUT \
"https://cs.growthdept.ai/api/custom-fields?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{}
]'Response 202
{
"object": "list",
"uri": "/api/custom-fields",
"data": [
{
"id": 5,
"uri": "/api/custom-fields/5/",
"external_id": null,
"object_type": "Ticket",
"label": "Reason for contact",
"description": null,
"priority": 1,
"required": false,
"requirement_type": "visible",
"managed_type": null,
"definition": {
"data_type": "text",
"input_settings": {}
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Get a field
GET/api/custom-fields/{id}
One ticket or customer field with its definition.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The field's id. |
Response
200 · The field. · CustomField
Request
curl "https://cs.growthdept.ai/api/custom-fields/5" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 5,
"uri": "/api/custom-fields/5/",
"external_id": null,
"object_type": "Ticket",
"label": "Reason for contact",
"description": null,
"priority": 1,
"required": false,
"requirement_type": "visible",
"managed_type": null,
"definition": {
"data_type": "text",
"input_settings": {}
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Change a field
PUT/api/custom-fields/{id}
Changes the fields sent. active: false (or a deactivated_datetime) turns the field off; its values are kept. The data type cannot change.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The field's id. |
Body
Any JSON value.
Response
202 · The field after the change. · CustomField
Request
curl -X PUT "https://cs.growthdept.ai/api/custom-fields/5" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{
"id": 5,
"uri": "/api/custom-fields/5/",
"external_id": null,
"object_type": "Ticket",
"label": "Reason for contact",
"description": null,
"priority": 1,
"required": false,
"requirement_type": "visible",
"managed_type": null,
"definition": {
"data_type": "text",
"input_settings": {}
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Satisfaction surveys
One survey per ticket, sent by email after the ticket closes when surveys are on. The score is 1 to 5, with an optional comment.
The SatisfactionSurvey object · 11 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| ticket_ | integer | |
| customer_ | integer or null | |
| score | integer or null | 1 to 5. |
| body_ | string or null | The customer's comment. |
| meta | object or null | |
| created_ | datetime or null | |
| should_ | datetime or null | |
| sent_ | datetime or null | |
| scored_ | datetime or null |
List satisfaction surveys
GET/api/satisfaction-surveys
Surveys waiting to go out, sent and answered, newest first. Filter by ticket_id.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| ticket_ | Only this ticket's survey. |
Response
200 · A page of surveys. · list of SatisfactionSurvey
Request
curl \
"https://cs.growthdept.ai/api/satisfaction-surveys?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/satisfaction-surveys?limit=2",
"data": [
{
"id": 880,
"uri": "/api/satisfaction-surveys/880/",
"ticket_id": 4182,
"customer_id": 7311,
"score": 5,
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"meta": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"should_send_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"scored_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a satisfaction survey
POST/api/satisfaction-surveys
Creates the survey for a ticket (one per ticket). With should_send_datetime it goes out at that time, while surveys are on for the ticket's channel; with sent_datetime it is recorded as already sent. A score from 1 to 5 needs scored_datetime, and records the answer. customer_id defaults to the ticket's customer.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| ticket_ | integer or string | The ticket the survey is about. Required when creating. |
| customer_ | integer or string | The customer asked. Required when creating. |
| score | integer or null | 1 to 5, or null. Needs scored_datetime. |
| body_ | string or null | The customer's comment. Needs a score. |
| meta | object or null | |
| created_ | string or null | |
| should_ | string or null | When the survey goes out. Only for a ticket that could get one: email, chat, contact form or help center, with a message from the customer and a reply from an agent, 250 characters or more. |
| sent_ | string or null | When it went out; set it to record a survey sent elsewhere. |
| scored_ | string or null | When the customer answered. Required with score, and needs sent_datetime. |
Response
201 · The new survey. · SatisfactionSurvey
Request
curl -X POST \
"https://cs.growthdept.ai/api/satisfaction-surveys" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ticket_id": 4182,
"customer_id": 7311,
"score": 5
}'Response 201
{
"id": 880,
"uri": "/api/satisfaction-surveys/880/",
"ticket_id": 4182,
"customer_id": 7311,
"score": 5,
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"meta": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"should_send_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"scored_datetime": null
}Get a satisfaction survey
GET/api/satisfaction-surveys/{id}
One survey: its ticket and customer, when it is due or went out, and the score and comment once the customer answers.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The survey's id. |
Response
200 · The survey. · SatisfactionSurvey
Request
curl \
"https://cs.growthdept.ai/api/satisfaction-surveys/880" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 880,
"uri": "/api/satisfaction-surveys/880/",
"ticket_id": 4182,
"customer_id": 7311,
"score": 5,
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"meta": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"should_send_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"scored_datetime": null
}Change a satisfaction survey
PUT/api/satisfaction-surveys/{id}
Changes the fields sent. Record an answer with score (1 to 5) and scored_datetime, and the comment in body_text; setting a score records a satisfaction-survey-responded event and runs the rules that listen for it. A new should_send_datetime reschedules a survey that has not gone out.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The survey's id. |
Body
| Field | Type | Description |
|---|---|---|
| ticket_ | integer or string | The ticket the survey is about. Required when creating. |
| customer_ | integer or string | The customer asked. Required when creating. |
| score | integer or null | 1 to 5, or null. Needs scored_datetime. |
| body_ | string or null | The customer's comment. Needs a score. |
| meta | object or null | |
| created_ | string or null | |
| should_ | string or null | When the survey goes out. Only for a ticket that could get one: email, chat, contact form or help center, with a message from the customer and a reply from an agent, 250 characters or more. |
| sent_ | string or null | When it went out; set it to record a survey sent elsewhere. |
| scored_ | string or null | When the customer answered. Required with score, and needs sent_datetime. |
Response
202 · The survey after the change. · SatisfactionSurvey
Request
curl -X PUT \
"https://cs.growthdept.ai/api/satisfaction-surveys/880" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ticket_id": 4182,
"customer_id": 7311,
"score": 5
}'Response 202
{
"id": 880,
"uri": "/api/satisfaction-surveys/880/",
"ticket_id": 4182,
"customer_id": 7311,
"score": 5,
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"meta": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"should_send_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"scored_datetime": null
}Integrations
Connected mailboxes and HTTP integrations. Mailboxes are connected in the app with Google; HTTP integrations can be managed here. Tokens are never returned.
The Integration object · 16 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| type | string | http, gmail, resend (a forwarded support address), email, shopify, ... |
| name | string | |
| description | string or null | |
| decoration | object or null | |
| meta | object | |
| http | object or null | For type http: url, method, headers, request_content_type, response_content_type, form, triggers. |
| user | object or null | |
| managed | boolean | |
| application_ | string or null | |
| business_ | integer or null | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| deactivated_ | datetime or null | |
| locked_ | datetime or null |
The HttpIntegrationTest object · 8 fields
| Field | Type | Description |
|---|---|---|
| ok | boolean | The receiver answered with a 2xx status. |
| status | integer or null | |
| duration_ | integer | |
| response_ | string or null | The first 2,000 characters of the response body. |
| error | string or null | |
| signed | boolean | |
| delivery_ | string | |
| request | object | What was sent. Header values other than content type and the helpdesk's own headers are masked. |
The WebhookDelivery object · 12 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| integration_ | integer | |
| event_ | integer or null | |
| event_ | string | |
| object_ | string or null | |
| object_ | integer or null | |
| attempt | integer | |
| status | succeeded, failed, refused | |
| status_ | integer or null | |
| error | string or null | |
| duration_ | integer or null | |
| created_ | datetime or null |
List integrations
GET/api/integrations
Every integration of the helpdesk: mailboxes, stores and HTTP integrations. type=http lists one kind (a type outside Gorgias's list is a 400); purpose (support or marketing) goes only with type=email. Header values of HTTP integrations are shown to admins only.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| typequery · string | |
| purposequery · string | With type=email: support or marketing mailboxes.support, marketing |
Response
200 · A page of integrations. · list of Integration
Request
curl \
"https://cs.growthdept.ai/api/integrations?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/integrations?limit=2",
"data": [
{
"id": 2,
"uri": "/api/integrations/2/",
"type": "http",
"name": "Order sync webhook",
"description": null,
"decoration": {
"color": "#2546e8"
},
"meta": {},
"http": {},
"user": {},
"managed": false,
"application_id": null,
"business_hours_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null,
"locked_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create an HTTP integration
POST/api/integrations
Creates an outbound webhook. http.url, header values and the strings in http.form can use template variables such as {{ticket.id}} and {{message.body_text}}. The response includes http.signing_secret, shown only this once; every request carries an X-Helpdesk-Signature header made with it.
Role: admin or higher
Body
Any JSON value.
Response
201 · The new integration, with its signing secret. · Integration
Request
curl -X POST "https://cs.growthdept.ai/api/integrations" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "http",
"name": "Order sync webhook",
"http": {
"url": "https://hooks.example.com/helpdesk",
"method": "POST",
"request_content_type": "application/json",
"form": {
"ticket_id": "{{ticket.id}}",
"status": "{{ticket.status}}"
},
"triggers": {
"ticket-created": true,
"ticket-updated": true,
"ticket-message-created": false
}
}
}'Response 201
{
"id": 2,
"uri": "/api/integrations/2/",
"type": "http",
"name": "Order sync webhook",
"description": null,
"decoration": {
"color": "#2546e8"
},
"meta": {},
"http": {},
"user": {},
"managed": false,
"application_id": null,
"business_hours_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null,
"locked_datetime": null
}Get an integration
GET/api/integrations/{id}
One integration. Header values of HTTP integrations are shown to admins only. include_shopify_integration and include_review_providers ask for a store's linked integrations, so for anything but a Shopify store they answer 404, as in Gorgias.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The integration's id. |
| include_ | For a Shopify store: include its review apps.0, 1, true, false |
| include_ | For a review app: include the store it belongs to.0, 1, true, false |
Response
200 · The integration. · Integration
Request
curl "https://cs.growthdept.ai/api/integrations/2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 2,
"uri": "/api/integrations/2/",
"type": "http",
"name": "Order sync webhook",
"description": null,
"decoration": {
"color": "#2546e8"
},
"meta": {},
"http": {},
"user": {},
"managed": false,
"application_id": null,
"business_hours_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null,
"locked_datetime": null
}Change an integration
PUT/api/integrations/{id}
Changes the fields sent. For HTTP integrations, http fields not sent keep their values. active: true turns an integration back on and clears its failure count.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The integration's id. |
Body
Any JSON value.
Response
202 · The integration after the change. · Integration
Request
curl -X PUT "https://cs.growthdept.ai/api/integrations/2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 202
{
"id": 2,
"uri": "/api/integrations/2/",
"type": "http",
"name": "Order sync webhook",
"description": null,
"decoration": {
"color": "#2546e8"
},
"meta": {},
"http": {},
"user": {},
"managed": false,
"application_id": null,
"business_hours_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null,
"locked_datetime": null
}Delete an HTTP integration
DELETE/api/integrations/{id}
Deletes an HTTP integration and its delivery history. Mailboxes and stores are disconnected from their own settings pages.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The integration's id. |
Response
204 · The integration was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/integrations/2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Test unsaved HTTP integration settings
POST/api/helpdesk/integrations/test
Sends one request built from the settings in the body (URL, method, headers, body template) with a made-up sample ticket, and reports the status, timing and the start of the response. Unsaved settings have no signing secret, so the request is not signed.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| event_ | ticket-created, ticket-updated, ticket-message-created | |
| httprequired | object |
Response
200 · What the receiver answered. · HttpIntegrationTest
Request
curl -X POST \
"https://cs.growthdept.ai/api/helpdesk/integrations/test" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"http": {
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"method": "GET",
"headers": {},
"request_content_type": "",
"response_content_type": "",
"form": {},
"triggers": {}
}
}'Response 200
{
"ok": false,
"status": null,
"duration_ms": 0,
"response_excerpt": null,
"error": null,
"signed": false,
"delivery_id": "",
"request": {}
}List webhook deliveries
GET/api/integrations/{id}/deliveries
Each attempt to deliver an event to an HTTP integration, newest first: the event, the attempt number, the HTTP status or the error, and how long it took.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The integration's id. |
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
Response
200 · A page of delivery attempts. · list of WebhookDelivery
Request
curl \
"https://cs.growthdept.ai/api/integrations/2/deliveries?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/integrations/2/deliveries?limit=2",
"data": [
{
"id": 1,
"integration_id": 2,
"event_id": null,
"event_type": "",
"object_type": "Ticket",
"object_id": 4182,
"attempt": 0,
"status": "succeeded",
"status_code": null,
"error": null,
"duration_ms": null,
"created_datetime": "2026-11-04T09:41:12+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Replace a webhook signing secret
POST/api/integrations/{id}/signing-secret
Makes a new signing secret for an HTTP integration and returns it once in http.signing_secret. Requests are signed with the new secret from now on.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The integration's id. |
Response
200 · The integration with its new secret. · Integration
Request
curl -X POST \
"https://cs.growthdept.ai/api/integrations/2/signing-secret" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 2,
"uri": "/api/integrations/2/",
"type": "http",
"name": "Order sync webhook",
"description": null,
"decoration": {
"color": "#2546e8"
},
"meta": {},
"http": {},
"user": {},
"managed": false,
"application_id": null,
"business_hours_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null,
"locked_datetime": null
}Send a test request for an HTTP integration
POST/api/helpdesk/integrations/{id}/test
Renders the integration's URL, headers and body with a made-up sample ticket, sends one request and reports the status, timing and the start of the response. Private and local network addresses are refused.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| event_ | ticket-created, ticket-updated, ticket-message-created |
Response
200 · What the receiver answered. · HttpIntegrationTest
Request
curl -X POST \
"https://cs.growthdept.ai/api/helpdesk/integrations/1/test" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_type": "ticket-created"
}'Response 200
{
"ok": false,
"status": null,
"duration_ms": 0,
"response_excerpt": null,
"error": null,
"signed": false,
"delivery_id": "",
"request": {}
}Contact forms
Forms the helpdesk publishes on its own site. Each submission opens a ticket on the contact_form channel, and agents answer it by email from the form's mailbox. Admins create and change forms; the submit address takes posts from the form's own page and iframe, with spam checks and limits per address.
The ContactForm object · 14 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| public_ | string | The random id in the form's public address. |
| name | string | The form's name, shown to agents. |
| language | en, fr, de, es | The language of the form's labels and of the tickets it opens. |
| integration_ | integer or null | The mailbox that answers submissions. |
| mailbox | object or null | The mailbox that answers submissions, with active false once it is disconnected. |
| settings | object | What the public form shows. |
| url | string | The hosted form. |
| embed_ | string | The form without page margins, for an iframe. |
| script_ | string | A script that adds the form's iframe where the script tag stands. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| deleted_ | datetime or null |
The ContactFormSubmitted object · 1 fields
| Field | Type | Description |
|---|---|---|
| ok | true |
List contact forms
GET/api/contact-forms
The helpdesk's contact forms, newest first, with the mailbox that answers each and the addresses to publish it at. Deleted forms are left out.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc, name:asc, name:desc |
Response
200 · A page of contact forms. · list of ContactForm
Request
curl \
"https://cs.growthdept.ai/api/contact-forms?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/contact-forms?limit=2",
"data": [
{
"id": 1,
"uri": "/api/",
"public_id": "",
"name": "Demo Store",
"language": "en",
"integration_id": 2,
"mailbox": {
"id": 1,
"type": "gmail",
"address": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"settings": {
"title": null,
"intro": null,
"subjects": [
""
],
"allow_other": false,
"name_field": "optional",
"order_number": "off",
"attachments": false,
"accent": "",
"thank_you": null
},
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"embed_url": "",
"script_url": "",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a contact form
POST/api/contact-forms
Creates a form with a new random public address. name is required. language (en, fr, de or es) sets the form's labels and starting subjects; integration_id names the Gmail or forwarding mailbox that answers submissions.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| name | string | The form's name, shown to agents. |
| language | en, fr, de, es | The language of the form's labels and the tickets it opens. |
| integration_ | integer or string | The mailbox that answers submissions: a Gmail mailbox or a forwarding mailbox in this helpdesk. null for none. |
| settings | object | What the form shows. Fields sent replace the stored ones; others stay. |
Response
201 · The new form. · ContactForm
Request
curl -X POST "https://cs.growthdept.ai/api/contact-forms" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"language": "en",
"integration_id": 2
}'Response 201
{
"id": 1,
"uri": "/api/",
"public_id": "",
"name": "Demo Store",
"language": "en",
"integration_id": 2,
"mailbox": {
"id": 1,
"type": "gmail",
"address": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"settings": {
"title": null,
"intro": null,
"subjects": [
""
],
"allow_other": false,
"name_field": "optional",
"order_number": "off",
"attachments": false,
"accent": "",
"thank_you": null
},
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"embed_url": "",
"script_url": "",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null
}Get a contact form
GET/api/contact-forms/{id}
One contact form with its settings, mailbox and public addresses.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The contact form's id. |
Response
200 · The form. · ContactForm
Request
curl "https://cs.growthdept.ai/api/contact-forms/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"uri": "/api/",
"public_id": "",
"name": "Demo Store",
"language": "en",
"integration_id": 2,
"mailbox": {
"id": 1,
"type": "gmail",
"address": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"settings": {
"title": null,
"intro": null,
"subjects": [
""
],
"allow_other": false,
"name_field": "optional",
"order_number": "off",
"attachments": false,
"accent": "",
"thank_you": null
},
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"embed_url": "",
"script_url": "",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null
}Change a contact form
PUT/api/contact-forms/{id}
Changes the fields sent. Fields inside settings replace the stored ones and the rest stay; subjects replaces the whole list, in the order given.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The contact form's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | The form's name, shown to agents. |
| language | en, fr, de, es | The language of the form's labels and the tickets it opens. |
| integration_ | integer or string | The mailbox that answers submissions: a Gmail mailbox or a forwarding mailbox in this helpdesk. null for none. |
| settings | object | What the form shows. Fields sent replace the stored ones; others stay. |
Response
202 · The form after the change. · ContactForm
Request
curl -X PUT "https://cs.growthdept.ai/api/contact-forms/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"language": "en",
"integration_id": 2
}'Response 202
{
"id": 1,
"uri": "/api/",
"public_id": "",
"name": "Demo Store",
"language": "en",
"integration_id": 2,
"mailbox": {
"id": 1,
"type": "gmail",
"address": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"settings": {
"title": null,
"intro": null,
"subjects": [
""
],
"allow_other": false,
"name_field": "optional",
"order_number": "off",
"attachments": false,
"accent": "",
"thank_you": null
},
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"embed_url": "",
"script_url": "",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null
}Delete a contact form
DELETE/api/contact-forms/{id}
Stops the form taking messages: its address then says the form is no longer in use. Tickets it opened stay.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The contact form's id. |
Response
204 · The form was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/contact-forms/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Send a contact form
POST/api/forms/{helpdesk}/{public_id}
What the hosted form, its iframe and its script embed post to: multipart/form-data with name, email, subject (or subject_other), order_number, message, up to 3 attachments and the page token _t from the form page. It opens a ticket on the contact_form channel. With Accept: application/json it answers {"ok": true} or an error with each field's problem; otherwise it redirects back to the form page.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The form's public id. |
Body (multipart/form-data)
The form's fields and files.
Response
200 · The message was received. · ContactFormSubmitted
Request
curl -X POST "https://cs.growthdept.ai/api/forms/1/1" \
-F "file=@parcel-photo.jpg"Response 200
{
"ok": true
}Events
A record of what happened in the helpdesk. Events carry ids and the fields that changed, never message text.
The Event object · 9 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| type | string | ticket-created, ticket-updated, ticket-message-created, ... |
| object_ | string | Ticket, TicketMessage, Customer, User, ... |
| object_ | integer or null | |
| user_ | integer or null | The agent who acted; null for customers and the system. |
| context | string or null | Events caused by the same request share a context. |
| data | object or null | What changed. Never message text. |
| created_ | datetime or null |
List events
GET/api/events
What has happened in the helpdesk, newest first: tickets created and changed, messages added, customers, agents, tags and teams changed. Filter by the object (object_type and object_id; an object that does not exist is a 400), event types, acting agents (user_ids) or time (created_datetime[gte], [gt], [lte], [lt]).
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| object_ | The kind of object: Ticket, TicketMessage, Customer, User, Team, Tag, CustomField, Macro, Rule, View, Widget, Integration, SatisfactionSurvey and the other types Gorgias lists. |
| object_ | With object_type: one object's events. |
| typesquery · string or array of string | Event types, comma-separated, such as ticket-created,ticket-updated. |
| user_ | Only events these agents caused, comma-separated agent ids. |
| created_ | Not a value: use created_datetime[gte], [gt], [lte] or [lt]. |
| created_ | Only events at or after this time. |
| created_ | Only events after this time. |
| created_ | Only events at or before this time. |
| created_ | Only events before this time. |
Response
200 · A page of events. · list of Event
Request
curl "https://cs.growthdept.ai/api/events?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/events?limit=2",
"data": [
{
"id": 553201,
"uri": "/api/events/553201/",
"type": "ticket-created",
"object_type": "Ticket",
"object_id": 4182,
"user_id": 12,
"context": "4b9e1f20-6c1d-4f0e-9a7b-3d2c1b0a9f8e",
"data": {
"status": {
"old": "open",
"new": "closed"
}
},
"created_datetime": "2026-11-04T09:41:12+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Get an event
GET/api/events/{id}
One event by its id: what happened, to which object, and which agent caused it.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The event. · Event
Request
curl "https://cs.growthdept.ai/api/events/553201" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 553201,
"uri": "/api/events/553201/",
"type": "ticket-created",
"object_type": "Ticket",
"object_id": 4182,
"user_id": 12,
"context": "4b9e1f20-6c1d-4f0e-9a7b-3d2c1b0a9f8e",
"data": {
"status": {
"old": "open",
"new": "closed"
}
},
"created_datetime": "2026-11-04T09:41:12+00:00"
}Widgets
Widgets lay out an integration's data in the ticket and customer sidebars.
The Widget object · 11 fields
How one integration's data is laid out in a sidebar.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| type | bigcommerce, custom, customer_external_data, http, magento2, recharge, shopify, smile, standalone, yotpo, klaviyo, stripe, woocommerce | |
| context | ticket, customer, user | The sidebar it shows in. |
| integration_ | integer or null | The integration whose data it lays out. |
| app_ | string or null | The app whose data it lays out, for app widgets. |
| order | integer | Position in the sidebar, lowest first. |
| template | object or null | The layout, a tree such as {"type": "wrapper", "widgets": [...]}. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| deactivated_ | datetime or null | Set when the widget is hidden. |
List widgets
GET/api/widgets
The sidebar layouts for each integration's data, newest first; order_by=order:asc gives them in sidebar order. Filter by integration_id or app_id.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc, order:asc, order:desc |
| integration_ | Only this integration's widgets. |
| app_ | Only this app's widgets. |
Response
200 · A page of widgets. · list of Widget
Request
curl "https://cs.growthdept.ai/api/widgets?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/widgets?limit=2",
"data": [
{
"id": 4,
"uri": "/api/widgets/4/",
"type": "bigcommerce",
"context": "ticket",
"integration_id": 2,
"app_id": null,
"order": 1,
"template": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a widget
POST/api/widgets
Adds a sidebar layout. type and template are required; context is ticket (the default), customer or user, and order sets its position.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| type | bigcommerce, custom, customer_external_data, http, magento2, recharge, shopify, smile, standalone, yotpo, klaviyo, stripe, woocommerce | |
| context | ticket, customer, user | |
| integration_ | integer or string | |
| app_ | string or null | |
| order | integer | |
| template | object | |
| deactivated_ | string or null |
Response
201 · The new widget. · Widget
Request
curl -X POST "https://cs.growthdept.ai/api/widgets" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "bigcommerce",
"context": "ticket",
"integration_id": 2
}'Response 201
{
"id": 4,
"uri": "/api/widgets/4/",
"type": "bigcommerce",
"context": "ticket",
"integration_id": 2,
"app_id": null,
"order": 1,
"template": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Get a widget
GET/api/widgets/{id}
One widget with its template.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The widget's id. |
Response
200 · The widget. · Widget
Request
curl "https://cs.growthdept.ai/api/widgets/4" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 4,
"uri": "/api/widgets/4/",
"type": "bigcommerce",
"context": "ticket",
"integration_id": 2,
"app_id": null,
"order": 1,
"template": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Change a widget
PUT/api/widgets/{id}
Changes the fields sent. template replaces the whole layout; deactivated_datetime hides the widget without deleting it.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The widget's id. |
Body
| Field | Type | Description |
|---|---|---|
| type | bigcommerce, custom, customer_external_data, http, magento2, recharge, shopify, smile, standalone, yotpo, klaviyo, stripe, woocommerce | |
| context | ticket, customer, user | |
| integration_ | integer or string | |
| app_ | string or null | |
| order | integer | |
| template | object | |
| deactivated_ | string or null |
Response
202 · The widget after the change. · Widget
Request
curl -X PUT "https://cs.growthdept.ai/api/widgets/4" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "bigcommerce",
"context": "ticket",
"integration_id": 2
}'Response 202
{
"id": 4,
"uri": "/api/widgets/4/",
"type": "bigcommerce",
"context": "ticket",
"integration_id": 2,
"app_id": null,
"order": 1,
"template": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deactivated_datetime": null
}Delete a widget
DELETE/api/widgets/{id}
Deletes the widget. The integration and its data stay.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The widget's id. |
Response
204 · The widget was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/widgets/4" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Jobs
Jobs change or export many objects in the background. Start one, then check its status until it is done.
The Job object · 17 fields
A change applied to many tickets in the background.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| type | applyMacro, deleteTicket, exportTicket, importMacro, exportMacro, updateTicket, exportTicketDrilldown, exportConvertCampaignSalesDrilldown | updateTicket, applyMacro and deleteTicket run here. |
| status | scheduled, pending, running, done, errored, fatal_errored, cancel_requested, canceled | errored: finished, but some tickets could not be changed. fatal_errored: the job could not run; info.error says why. |
| params | object | What to change (updates, macro_id, apply_and_close) and which tickets (ticket_ids, view_id or view). |
| meta | object or null | Whatever the client sent as meta, returned as is. |
| info | object | |
| user_ | integer or null | The agent who started it; the job acts as them. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| scheduled_ | datetime or null | |
| started_ | datetime or null | |
| ended_ | datetime or null | |
| locked_ | datetime or null | Set while a run is working on it. |
| cancel_ | datetime or null | |
| cancelled_ | datetime or null | |
| failed_ | datetime or null |
List jobs
GET/api/jobs
Bulk changes started in this helpdesk, newest first, with their status and progress. Filter by status or type.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| statusquery · string | scheduled, pending, running, done, errored, fatal_errored, cancel_requested, canceled |
| typequery · string | applyMacro, deleteTicket, exportTicket, importMacro, exportMacro, updateTicket, exportTicketDrilldown, exportConvertCampaignSalesDrilldown |
Response
200 · A page of jobs. · list of Job
Request
curl "https://cs.growthdept.ai/api/jobs?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/jobs?limit=2",
"data": [
{
"id": 61,
"uri": "/api/jobs/61/",
"type": "applyMacro",
"status": "scheduled",
"params": {},
"meta": {},
"info": {
"iteration_over": false,
"progress_count": 0,
"progress_cursor": 0,
"total": null,
"succeeded": 0,
"failed": 0,
"errors": [
{
"ticket_id": 4182,
"error": ""
}
],
"error": ""
},
"user_id": 12,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"scheduled_datetime": "2026-11-04T09:41:12+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null,
"locked_datetime": null,
"cancel_requested_datetime": "2026-11-04T09:41:12+00:00",
"cancelled_datetime": "2026-11-04T09:41:12+00:00",
"failed_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Start a job
POST/api/jobs
Changes many tickets in the background, as you. type updateTicket applies params.updates (status, priority, assignee_user, assignee_team, tags to replace the list, add_tags, remove_tags, snooze_datetime, trashed_datetime, spam, is_unread, custom_fields); applyMacro applies params.macro_id, and closes each ticket too with apply_and_close; deleteTicket deletes them. Name the tickets with params.ticket_ids (up to 10,000), params.view_id, or params.view with filters for an unsaved view. Set scheduled_datetime to start later. Follow its progress with GET /api/jobs/{id}.
Role: lite-agent or higher
Body
| Field | Type | Description |
|---|---|---|
| typerequired | applyMacro, deleteTicket, exportTicket, importMacro, exportMacro, updateTicket, exportTicketDrilldown, exportConvertCampaignSalesDrilldown | |
| paramsrequired | object | |
| meta | object or null | |
| scheduled_ | string or null |
Response
201 · The new job. · Job
Request
curl -X POST "https://cs.growthdept.ai/api/jobs" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "updateTicket",
"params": {
"ticket_ids": [
4182,
4176
],
"updates": {
"status": "closed"
}
}
}'Response 201
{
"id": 61,
"uri": "/api/jobs/61/",
"type": "applyMacro",
"status": "scheduled",
"params": {},
"meta": {},
"info": {
"iteration_over": false,
"progress_count": 0,
"progress_cursor": 0,
"total": null,
"succeeded": 0,
"failed": 0,
"errors": [
{
"ticket_id": 4182,
"error": ""
}
],
"error": ""
},
"user_id": 12,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"scheduled_datetime": "2026-11-04T09:41:12+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null,
"locked_datetime": null,
"cancel_requested_datetime": "2026-11-04T09:41:12+00:00",
"cancelled_datetime": "2026-11-04T09:41:12+00:00",
"failed_datetime": null
}Get a job
GET/api/jobs/{id}
One job with its status and progress: info.progress_count tickets done of info.total, how many failed and why for the first few.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The job's id. |
Response
200 · The job. · Job
Request
curl "https://cs.growthdept.ai/api/jobs/61" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 61,
"uri": "/api/jobs/61/",
"type": "applyMacro",
"status": "scheduled",
"params": {},
"meta": {},
"info": {
"iteration_over": false,
"progress_count": 0,
"progress_cursor": 0,
"total": null,
"succeeded": 0,
"failed": 0,
"errors": [
{
"ticket_id": 4182,
"error": ""
}
],
"error": ""
},
"user_id": 12,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"scheduled_datetime": "2026-11-04T09:41:12+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null,
"locked_datetime": null,
"cancel_requested_datetime": "2026-11-04T09:41:12+00:00",
"cancelled_datetime": "2026-11-04T09:41:12+00:00",
"failed_datetime": null
}Change a job
PUT/api/jobs/{id}
Changes the fields sent. params and scheduled_datetime can change until the job starts; meta at any time. status cancel_requested stops the job.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The job's id. |
Body
| Field | Type | Description |
|---|---|---|
| params | object | |
| meta | object or null | |
| scheduled_ | string or null | |
| status | scheduled, pending, running, done, errored, fatal_errored, cancel_requested, canceled |
Response
202 · The job after the change. · Job
Request
curl -X PUT "https://cs.growthdept.ai/api/jobs/61" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"params": {
"ticket_ids": [
0
],
"view_id": 25,
"view": {
"filters": "eq(ticket.status, \"open\") && isEmpty(ticket.assignee_user.id) && containsAll(ticket.tags.name, [\"shipping\"])",
"search": null,
"type": "email"
},
"macro_id": 0,
"apply_and_close": false,
"updates": {
"status": "open",
"priority": "normal",
"assignee_user": {
"id": 1,
"email": "maya.okafor@example.com"
},
"assignee_team": {
"id": 1
},
"tags": [
""
],
"add_tags": [
""
],
"remove_tags": [
""
],
"snooze_datetime": null,
"trashed_datetime": null,
"spam": false,
"is_unread": true,
"custom_fields": [
{
"id": 1,
"value": "Where is my order"
}
]
}
},
"meta": {},
"scheduled_datetime": null
}'Response 202
{
"id": 61,
"uri": "/api/jobs/61/",
"type": "applyMacro",
"status": "scheduled",
"params": {},
"meta": {},
"info": {
"iteration_over": false,
"progress_count": 0,
"progress_cursor": 0,
"total": null,
"succeeded": 0,
"failed": 0,
"errors": [
{
"ticket_id": 4182,
"error": ""
}
],
"error": ""
},
"user_id": 12,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"scheduled_datetime": "2026-11-04T09:41:12+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null,
"locked_datetime": null,
"cancel_requested_datetime": "2026-11-04T09:41:12+00:00",
"cancelled_datetime": "2026-11-04T09:41:12+00:00",
"failed_datetime": null
}Cancel a job
DELETE/api/jobs/{id}
Stops a job. One that has not started is canceled at once; a running one stops after the ticket it is on. Tickets it already changed stay changed.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The job's id. |
Response
204 · The job is canceled or will stop shortly.
Request
curl -X DELETE "https://cs.growthdept.ai/api/jobs/61" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Files
Upload attachments, up to 25 MB each, then put the returned URL in a message's attachments.
The UploadedFile object · 4 fields
| Field | Type | Description |
|---|---|---|
| url | string | Where the file is served; put it in a message's attachments. |
| name | string | |
| size | integer | Bytes. |
| content_ | string |
Upload files
POST/api/upload
Stores the files of a multipart/form-data body (up to 25 MB each) and returns, for each, the url to put in a message's attachments. Each file is named after its form field, as Gorgias does, or after its file name when the field is called file. type is attachment (the default), public_attachment, profile_picture or widget_picture; the two picture types take exactly one file. As in Gorgias, a request with no file stores nothing and answers an empty list.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| typequery · string | What the files are for: attachment (the default), public_attachment, profile_picture or widget_picture.attachment, public_attachment, profile_picture, widget_picture |
Body (multipart/form-data)
One or more files; each field name becomes the file's name.
Response
201 · One entry per file. · array of UploadedFile
Request
curl -X POST "https://cs.growthdept.ai/api/upload" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-F "file=@parcel-photo.jpg"Response 201
[
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"name": "parcel-photo.jpg",
"size": 48213,
"content_type": "image/jpeg"
}
]Download a file
GET/api/files/{id}/{token}
Serves an uploaded file. The link works without signing in, because its token is random and unguessable; anyone with the link can open the file.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| tokenrequiredpath · string | The file's access token, from its url. |
Response
200 · The file's bytes.
Request
curl "https://cs.growthdept.ai/api/files/1/7Qm2xk9Lr4"Response 200
(no body)Download a file by its resource name
GET/api/{file_type}/download/{domain_hash}/{resource_name}
Redirects (307) to an uploaded file of this helpdesk. resource_name is the file's access token, the last part of its url, and may be followed by a dot or dash and a file name. The helpdesk comes from your credentials, so domain_hash is accepted for compatibility and not checked. A token that is not one of this helpdesk's files is a 404.
Parameters
| Name | Description |
|---|---|
| file_ | One of attachment, public_attachment, profile_picture, widget_picture. |
| domain_ | Any value; not checked. |
| resource_ | The file's access token. |
Response
307 · A redirect to the file; the Location header holds its link.
Request
curl \
"https://cs.growthdept.ai/api/attachment/download/demo-store/4f1c9a7e2b6d0e8f3a5c7b9d1e2f4a6c8b0d" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 307
(no body)Search
Full-text search over tickets and customers.
Search with query parameters
GET/api/search
The same search as POST /api/search, with type, query and size in the query string, for links and simple clients. Answers 200.
Parameters
| Name | Description |
|---|---|
| typerequiredquery · string | agent, customer, customer_profile, customer_channel, customer_channel_email, customer_channel_phone, customers_by_phone, integration, team, tag, ticket |
| queryquery · string | |
| sizequery · string |
Response
200 · The best matches, up to size. · list of object
Request
curl \
"https://cs.growthdept.ai/api/search?limit=2&type=agent" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/search",
"data": [
{}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Search
POST/api/search
Type-ahead search. agent, team, tag and integration match names (and addresses); customer and customer_profile match names, emails, channel addresses and external ids; the customer_channel types match addresses; customers_by_phone finds customers by phone number. ticket, an addition to Gorgias's types, searches ticket subjects, message text and customers' names and addresses, and finds a ticket by its id. Answers 201 as Gorgias does.
Body
| Field | Type | Description |
|---|---|---|
| typerequired | agent, customer, customer_profile, customer_channel, customer_channel_email, customer_channel_phone, customers_by_phone, integration, team, tag, ticket | What to search: agent, customer, customer_profile, customer_channel, customer_channel_email, customer_channel_phone, customers_by_phone, integration, team, tag, or ticket. |
| query | string | The text to match, anywhere in the name or address. |
| size | integer or string | How many results, 1 to 100. Default 10. |
Response
201 · The best matches, up to size. · list of object
Request
curl -X POST "https://cs.growthdept.ai/api/search?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "order 1042",
"type": "ticket",
"size": 10
}'Response 201
{
"object": "list",
"uri": "/api/search",
"data": [
{}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Statistics
Report figures for a period: tickets created, replied and closed, messages, first response and resolution times, and satisfaction, grouped by channel, agent, team, tag, hour, day, week or month. They come from the same calculations as the app's analytics, so rates and averages are always worked out from totals. The older named statistics answer in their own chart and table shapes, or as CSV.
The Statistic object · 2 fields
| Field | Type | Description |
|---|---|---|
| data | object | The statistic. Figures: data is a list (or, for the total-* statistics, one object) of {name, type, value, delta}, where delta is the percent change from the previous period. Charts: label, legend and data {axes: {x: [day start in epoch seconds]}, lines: [{name, data}]}. Tables: label and data {axes: {x: [{name, type}]}, lines: [[{type, value}]]}. |
| meta | object |
Query reporting statistics
POST/api/reporting/stats
Ticket and message counts, first response and resolution times, and satisfaction for a period, optionally grouped by channel, agent, team, tag and time (hour, day, week or month). Scopes: tickets-created, tickets-replied, tickets-closed, one-touch-tickets, messages-sent, messages-received, messages-per-ticket, first-response-time, resolution-time, satisfaction-surveys. Other scopes, measures, dimensions and filters are refused with a 400 that lists what is available. Rates and averages are worked out from each row's own totals. The period is two filters, periodStart (afterDate) and periodEnd (beforeDate, which includes the second it names), read in the query's time zone.
Parameters
| Name | Description |
|---|---|
| limitquery · string | How many rows to return, from 1 to 10000. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
Body
| Field | Type | Description |
|---|---|---|
| queryrequired | object |
Response
200 · A page of rows. · list of ReportingStatsRow
Request
curl -X POST \
"https://cs.growthdept.ai/api/reporting/stats?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": {
"scope": "tickets-created",
"measures": [
"ticketCount"
],
"dimensions": [
"channel"
],
"filters": [
{
"member": "periodStart",
"operator": "afterDate",
"values": [
"2026-11-01T00:00:00.000"
]
},
{
"member": "periodEnd",
"operator": "beforeDate",
"values": [
"2026-11-04T23:59:59.000"
]
}
],
"timezone": "America/Los_Angeles"
}
}'Response 200
{
"object": "list",
"uri": "/api/reporting/stats?",
"data": [
{
"channel": "email",
"ticketCount": 9
},
{
"channel": "contact_form",
"ticketCount": 3
}
],
"meta": {
"scope": "tickets-created",
"prev_cursor": null,
"next_cursor": null,
"total": 2,
"offset": 0,
"limit": 30
}
}Get a named statistic
POST/api/stats/{name}
One of the older named statistics for a period, with the same figures as the app's reports: overview, total-tickets-created, total-tickets-replied, total-tickets-closed, total-messages-sent, total-messages-received, satisfaction-surveys, support-volume, first-response-time, resolution-time, tickets-per-tag, tickets-created-per-channel, tickets-closed-per-agent. Figures carry their percent change from the previous period of the same length. Days follow the helpdesk's time zone. An unknown name is a 404 that lists the names.
Parameters
| Name | Description |
|---|---|
| namerequiredpath · string | The statistic: overview, total-tickets-created, total-tickets-replied, total-tickets-closed, total-messages-sent, total-messages-received, satisfaction-surveys, support-volume, first-response-time, resolution-time, tickets-per-tag, tickets-created-per-channel, tickets-closed-per-agent. |
Body
| Field | Type | Description |
|---|---|---|
| filtersrequired | object |
Response
201 · The statistic and the period it covers. · Statistic
Request
curl -X POST "https://cs.growthdept.ai/api/stats/overview" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"period": {
"start_datetime": "2026-10-06T00:00:00-07:00",
"end_datetime": "2026-11-05T00:00:00-08:00"
},
"channels": [
"email"
]
}
}'Response 201
{
"data": {
"data": [
{
"name": "total_new_tickets",
"type": "number",
"value": 75,
"delta": 12
},
{
"name": "total_replied_tickets",
"type": "number",
"value": 69,
"delta": 8
},
{
"name": "total_closed_tickets",
"type": "number",
"value": 71,
"delta": -3
}
]
},
"meta": {
"start_datetime": "2026-10-06T07:00:00+00:00",
"end_datetime": "2026-11-05T08:00:00+00:00",
"previous_start_datetime": "2026-09-06T06:00:00+00:00",
"previous_end_datetime": "2026-10-06T07:00:00+00:00"
}
}Download a named statistic
POST/api/stats/{name}/download
The same statistic as POST /api/stats/{name}, as a CSV file with a header row. Names: overview, total-tickets-created, total-tickets-replied, total-tickets-closed, total-messages-sent, total-messages-received, satisfaction-surveys, support-volume, first-response-time, resolution-time, tickets-per-tag, tickets-created-per-channel, tickets-closed-per-agent.
Parameters
| Name | Description |
|---|---|
| namerequiredpath · string | The statistic's name. |
Body
| Field | Type | Description |
|---|---|---|
| filtersrequired | object |
Response
201 · The statistic as CSV.
Request
curl -X POST \
"https://cs.growthdept.ai/api/stats/overview/download" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"period": {
"start_datetime": "2026-10-06T00:00:00-07:00",
"end_datetime": "2026-11-05T00:00:00-08:00"
}
}
}'Response 201
(no body)Metric cards
The definition of each figure in the reports: what it counts, its formula, other names for it, and the reporting query that returns it. Feedback that a definition is wrong or unclear is kept as an event in the helpdesk.
The MetricCard object · 12 fields
| Field | Type | Description |
|---|---|---|
| slug | string | The card's id, such as median-first-response-time. |
| category | support-performance, quality, ticket-insights | |
| title | string | |
| status | published, deprecated | |
| definition_ | string | When the definition last changed. |
| public | object | |
| api | object | The POST /api/reporting/stats query that returns the figure. |
| aliases | array of string | Other names people use for the figure. |
| related | array of object | |
| replaces | array of string | Slugs of older cards this one replaces. |
| used_ | array of string | The analytics reports that show the figure. |
| used_ | array of string | Links to those reports in the app. |
List metric cards
GET/api/metric-cards
The definition of every figure in the analytics reports: what it counts, its formula, how it is worked out, other names for it, and the reporting query that returns it. The answer is {data: [...]}, without paging.
Parameters
| Name | Description |
|---|---|
| categoryquery · string | Only cards in this category: support-performance, quality, ticket-insights.support-performance, quality, ticket-insights |
| statusquery · string | Only cards with this status.published, deprecated |
| qquery · string | Words that must all appear in the card's slug, title, definition, formula or other names. |
| includequery · string | deprecated: list deprecated cards as well.deprecated |
Response
200 · The matching cards. · object
Request
curl "https://cs.growthdept.ai/api/metric-cards" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"slug": "unassigned-shipping",
"category": "support-performance",
"title": "",
"status": "published",
"definition_revised_at": "",
"public": {
"definition": "",
"formula": "",
"computation_logic": [
""
]
},
"api": {
"scope": "",
"measures": [
""
],
"dimensions": [
""
],
"filters": [
{
"member": "",
"values": []
}
]
},
"aliases": [
""
],
"related": [
{
"slug": "unassigned-shipping",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"replaces": [
""
],
"used_in_reports": [
""
],
"used_in_reports_links": [
""
]
}
]
}Get a metric card
GET/api/metric-cards/{slug}
One metric definition by its slug. An unknown slug is a 404 whose error.data.did_you_mean lists close slugs.
Parameters
| Name | Description |
|---|---|
| slugrequiredpath · string | The card's slug, such as median-first-response-time. |
Response
200 · The card. · MetricCard
Request
curl \
"https://cs.growthdept.ai/api/metric-cards/median-first-response-time" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"slug": "unassigned-shipping",
"category": "support-performance",
"title": "",
"status": "published",
"definition_revised_at": "",
"public": {
"definition": "",
"formula": "",
"computation_logic": [
""
]
},
"api": {
"scope": "",
"measures": [
""
],
"dimensions": [
""
],
"filters": [
{
"member": "",
"values": [
""
]
}
]
},
"aliases": [
""
],
"related": [
{
"slug": "unassigned-shipping",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"replaces": [
""
],
"used_in_reports": [
""
],
"used_in_reports_links": [
""
]
}Disagree with a metric definition
POST/api/metric-cards/{slug}/feedback
Records that a definition is unclear, its formula looks wrong or it misses a case, as a metric-card-feedback event in the helpdesk (GET /api/events) with the slug, the kind of disagreement, the category and the comment's length. The comment's text is not stored, because events never hold free text.
Parameters
| Name | Description |
|---|---|
| slugrequiredpath · string | The card's slug. |
Body
| Field | Type | Description |
|---|---|---|
| disagreement_ | definition_unclear, formula_seems_wrong, edge_case_missing, other | What is wrong with the definition. |
| metric_ | string | The card's category, such as support-performance. |
| comment | string | More detail, in your words. |
Response
201 · The feedback was recorded; id names the record, as Gorgias answers. · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/metric-cards/median-first-response-time/feedback" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"disagreement_type": "edge_case_missing",
"metric_category": "support-performance",
"comment": "Should a ticket merged into another one still count here?"
}'Response 201
{}Voice calls
Calls, call events and recordings, at the paths Gorgias's API uses: each call with its direction, outcome and times, what happened during it (menu choices, queueing, agents rung, holds, transfers, voicemail), and the audio and transcript of recordings and voicemails.
The VoiceCallEvent object · 8 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| call_ | integer | |
| ticket_ | integer or null | |
| type | string | incoming, flow_step, menu_choice, queued, ringing_agent, agent_missed, agent_declined, answered, recording_started, hold, resumed, transferred, voicemail_left, transcribed, ended, ... |
| user_ | integer or null | |
| queue_ | integer or null | |
| data | object | |
| created_ | datetime or null |
The VoiceCallRecording object · 10 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| call_ | integer | |
| ticket_ | integer or null | |
| type | call, voicemail | |
| url | string or null | The audio file; anyone with the link can play it. |
| duration | integer or null | |
| transcription | string or null | |
| transcription_ | none, pending, done, skipped, failed | |
| started_ | datetime or null | |
| created_ | datetime or null |
The VoiceCall object · 24 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| ticket_ | integer or null | |
| integration_ | integer or null | The voice line. |
| phone_ | integer or null | |
| customer_ | integer or null | |
| direction | inbound, outbound | |
| phone_ | string | |
| phone_ | string | |
| status | ringing, in_flow, queued, connected, ended | |
| outcome | answered, missed, abandoned, cancelled, voicemail, forwarded, sms, rejected, no_answer, busy, failed, null or null | |
| queue_ | integer or null | |
| user_ | integer or null | The agent who answered or placed the call. |
| initiated_ | integer or null | |
| started_ | datetime or null | |
| queued_ | datetime or null | |
| answered_ | datetime or null | |
| ended_ | datetime or null | |
| wait_ | integer or null | Seconds in the queue. |
| talk_ | integer or null | Seconds connected to an agent. |
| duration | integer or null | Seconds from first ring to hangup. |
| recording | boolean | |
| on_ | boolean | |
| created_ | datetime or null | |
| updated_ | datetime or null |
List voice call events
GET/api/phone/voice-call-events
What happened on calls: the flow's steps, menu choices, queueing, agents rung and who answered, holds, transfers, recordings, voicemails and the end. call_id or ticket_id narrows the list.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| call_ | Only this call's events. |
| ticket_ | Only events of calls on this ticket. |
Response
200 · A page of events. · list of VoiceCallEvent
Request
curl \
"https://cs.growthdept.ai/api/phone/voice-call-events?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/phone/voice-call-events?limit=2",
"data": [
{
"id": 1,
"call_id": 0,
"ticket_id": 4182,
"type": "email",
"user_id": 12,
"queue_id": null,
"data": {},
"created_datetime": "2026-11-04T09:41:12+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}List call recordings and voicemails
GET/api/phone/voice-call-recordings
Recordings of calls and voicemails, newest first, each with its audio file and transcript. call_id or ticket_id narrows the list.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| call_ | Only this call's recordings. |
| ticket_ | Only recordings on this ticket. |
Response
200 · A page of recordings. · list of VoiceCallRecording
Request
curl \
"https://cs.growthdept.ai/api/phone/voice-call-recordings?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/phone/voice-call-recordings?limit=2",
"data": [
{
"id": 1,
"call_id": 0,
"ticket_id": 4182,
"type": "call",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"duration": null,
"transcription": null,
"transcription_status": "none",
"started_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}List voice calls
GET/api/phone/voice-calls
The helpdesk's calls, inbound and outbound, newest first. ticket_id lists one ticket's calls.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
| ticket_ | Only calls on this ticket. |
Response
200 · A page of calls. · list of VoiceCall
Request
curl \
"https://cs.growthdept.ai/api/phone/voice-calls?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/phone/voice-calls?limit=2",
"data": [
{
"id": 1,
"ticket_id": 4182,
"integration_id": 2,
"phone_number_id": null,
"customer_id": 7311,
"direction": "inbound",
"phone_number_source": "",
"phone_number_destination": "",
"status": "ringing",
"outcome": "answered",
"queue_id": null,
"user_id": 12,
"initiated_by_user_id": null,
"started_datetime": "2026-11-04T09:41:12+00:00",
"queued_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null,
"wait_time": null,
"talk_time": null,
"duration": null,
"recording": false,
"on_hold": false,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Get a voice call event
GET/api/phone/voice-call-events/{id}
One voice call event with its type, agent, queue and details.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The event's id. |
Response
200 · The event. · VoiceCallEvent
Request
curl \
"https://cs.growthdept.ai/api/phone/voice-call-events/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"call_id": 0,
"ticket_id": 4182,
"type": "email",
"user_id": 12,
"queue_id": null,
"data": {},
"created_datetime": "2026-11-04T09:41:12+00:00"
}Get a voice call recording
GET/api/phone/voice-call-recordings/{id}
One recording or voicemail, with its audio file and transcript.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The recording's id. |
Response
200 · The voice call recording. · VoiceCallRecording
Request
curl \
"https://cs.growthdept.ai/api/phone/voice-call-recordings/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"call_id": 0,
"ticket_id": 4182,
"type": "call",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"duration": null,
"transcription": null,
"transcription_status": "none",
"started_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00"
}Delete a voice call recording
DELETE/api/phone/voice-call-recordings/{id}
Deletes the recording's audio and transcript. The call itself stays on its ticket.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The recording's id. |
Response
204 · The recording was deleted.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/phone/voice-call-recordings/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Get a voice call
GET/api/phone/voice-calls/{id}
One call with its direction, numbers, outcome and times.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The call's id. |
Response
200 · The voice call. · VoiceCall
Request
curl "https://cs.growthdept.ai/api/phone/voice-calls/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"ticket_id": 4182,
"integration_id": 2,
"phone_number_id": null,
"customer_id": 7311,
"direction": "inbound",
"phone_number_source": "",
"phone_number_destination": "",
"status": "ringing",
"outcome": "answered",
"queue_id": null,
"user_id": 12,
"initiated_by_user_id": null,
"started_datetime": "2026-11-04T09:41:12+00:00",
"queued_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null,
"wait_time": null,
"talk_time": null,
"duration": null,
"recording": false,
"on_hold": false,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Reference
The machine-readable description of everything on this page.
Get the OpenAPI document
GET/api/openapi.json
The OpenAPI 3.1 description of this API, built from the routes themselves. The API reference on the website is rendered from it.
Response
200 · The OpenAPI document. · object
Request
curl "https://cs.growthdept.ai/api/openapi.json"Response 200
{
"openapi": "3.1.0",
"info": {
"title": "Growth Dept Helpdesk REST API",
"version": "1"
},
"paths": {
"/api/account": {
"get": {
"summary": "Get the helpdesk"
}
}
}
}AI
Support intelligence for a ticket: its triage score with the reasons behind it, macros ranked for the latest customer message, promises made earlier in the thread, and drafted replies. Drafting is off until the helpdesk turns it on and Growth Dept has a model provider set; nothing here sends a message.
The AiSettings object · 4 fields
The helpdesk's triage vocabulary and drafting switch.
| Field | Type | Description |
|---|---|---|
| triage | object | Keyword and tag signals, VIP and high-value tags, channel points and targets, the wait clock and band thresholds. |
| drafting | object | enabled, voice_notes, redraft, auto_draft. |
| drafting_ | AiDraftingState | |
| built_ | array of object |
The AiTriage object · 14 fields
A ticket's triage score and the reasons it is made of.
| Field | Type | Description |
|---|---|---|
| ticket_ | integer | |
| score | integer | 0 to 100. |
| band | urgent, high, normal, low | |
| reasons | array of AiTriageReason | |
| awaiting_ | boolean | True when the customer's message is the newest word on the thread. |
| awaiting_ | datetime or null | The customer message we owe a reply to. |
| wait_ | integer or null | Minutes the customer has waited, on the wait clock. |
| wait_ | business, calendar | |
| sla_ | datetime or null | When the next reply is due. |
| sla_ | string or null | What set the target: policy:<name>, channel:<channel> or band:<band>. |
| overdue | boolean | |
| noise | boolean | Spam, trash or machine mail. |
| computed_ | datetime or null | |
| uri | string |
The AiDraft object · 17 fields
A reply drafted for a person to review. Never sent automatically.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| ticket_ | integer | |
| status | ready, used, discarded, superseded | |
| body_ | string | The drafted reply. |
| confidence | number or null | |
| needs_ | boolean | |
| notes | string or null | What to check before sending. |
| placeholders | array of string | |
| sources | object | |
| provider | string | |
| model | string | |
| thread_ | datetime or null | |
| current | boolean | False when a person wrote on the ticket after the draft was made. |
| trigger | agent, redraft, auto, ai_agent | ai_agent: the helpdesk's AI agent wrote it with its own model. |
| author | object or null | The AI agent that wrote the draft, for ai_agent drafts. |
| created_ | datetime or null | |
| uri | string |
The AiCommitments object · 2 fields
What the team already promised on a ticket.
| Field | Type | Description |
|---|---|---|
| ticket_ | integer | |
| data | array of AiCommitment |
The AiDraftEnvelope object · 4 fields
| Field | Type | Description |
|---|---|---|
| ticket_ | integer | |
| drafting | AiDraftingState | |
| draft | AiDraft or null | |
| ai_ | object | The helpdesk's AI agent; when linked it can leave drafts even while built-in drafting is off. |
The AiMacroSuggestions object · 3 fields
Macros ranked against the latest customer message.
| Field | Type | Description |
|---|---|---|
| ticket_ | integer | |
| keywords | array of string | |
| data | array of AiMacroSuggestion |
Get the helpdesk's triage and drafting settings
GET/api/ai/settings
The triage vocabulary (which tags and phrases add or remove points, which tags mark a VIP or high-value customer, points and reply targets per live channel, the wait clock and band thresholds), the drafting switch, whether drafting is actually available, and the built-in phrase signals with their default points.
Response
200 · The settings. · AiSettings
Request
curl "https://cs.growthdept.ai/api/ai/settings" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"triage": {},
"drafting": {},
"drafting_state": {
"enabled": false,
"reason": "no_provider",
"provider": "",
"model": "",
"message": ""
},
"built_in_signals": [
{
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"label": "Reason for contact",
"points": 0
}
]
}Change the helpdesk's triage and drafting settings
PUT/api/ai/settings
Send the fields to change under triage and drafting; fields you leave out keep their values. Turning drafting on lets the helpdesk ask for drafts, which sends ticket text to the model provider; it still needs a provider connected by Growth Dept. Open tickets are rescored with the new settings by the next job run, usually within two minutes.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| triage | object | |
| drafting | object |
Response
200 · The settings after the change. · AiSettings
Request
curl -X PUT "https://cs.growthdept.ai/api/ai/settings" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"triage": {},
"drafting": {}
}'Response 200
{
"triage": {},
"drafting": {},
"drafting_state": {
"enabled": false,
"reason": "no_provider",
"provider": "",
"model": "",
"message": ""
},
"built_in_signals": [
{
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"label": "Reason for contact",
"points": 0
}
]
}Get triage scores for many tickets
GET/api/ai/triage
Triage for up to 100 tickets at once, for a list or a view page. Missing or stale scores are computed first. Tickets that do not exist in this helpdesk are left out. To sort a list by score, call GET /api/tickets with order_by=priority_score:desc.
Parameters
| Name | Description |
|---|---|
| ticket_ | Ticket ids, comma-separated; up to 100. |
Response
200 · The tickets' triage, in the order asked for. · list of AiTriage
Request
curl \
"https://cs.growthdept.ai/api/ai/triage?limit=2&ticket_ids=" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/ai/triage",
"data": [
{
"ticket_id": 4182,
"score": 5,
"band": "urgent",
"reasons": [
{
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"label": "Reason for contact",
"points": 0
}
],
"awaiting_reply": false,
"awaiting_since": "2026-11-04T09:41:12+00:00",
"wait_minutes": null,
"wait_clock": "business",
"sla_due_datetime": "2026-11-04T09:41:12+00:00",
"sla_source": null,
"overdue": false,
"noise": false,
"computed_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Get a drafted reply
GET/api/ai/drafts/{id}
One draft, with what it was written from (message, ticket and macro ids) and whether it is still current.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The draft. · AiDraft
Request
curl "https://cs.growthdept.ai/api/ai/drafts/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"ticket_id": 4182,
"status": "ready",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"confidence": null,
"needs_review": false,
"notes": null,
"placeholders": [
""
],
"sources": {
"thread_message_ids": [
0
],
"note_message_ids": [
0
],
"customer_tickets": [
{
"id": 1,
"subject": "Where is order #1042?",
"status": "open"
}
],
"macros": [
{
"id": 1,
"name": "Demo Store",
"used": false
}
],
"similar": [
{
"ticket_id": 4182,
"subject": "Where is order #1042?",
"customer_message_id": 0,
"reply_message_id": 0,
"used": false
}
],
"skills": [
{
"id": 1,
"name": "Demo Store",
"used": false
}
],
"commitments": [
""
]
},
"provider": "",
"model": "",
"thread_through": "2026-11-04T09:41:12+00:00",
"current": false,
"trigger": "agent",
"author": {
"id": 1,
"name": "Demo Store"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}Mark a draft used or discarded
PUT/api/ai/drafts/{id}
status used records that a person put the draft into the composer; discarded throws it away. Only a draft that is ready or in use can change. The draft is never sent from here: the reply goes out when the person sends it from the composer.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| statusrequired | used, discarded | used or discarded. |
Response
200 · The draft after the change. · AiDraft
Request
curl -X PUT "https://cs.growthdept.ai/api/ai/drafts/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"status": "used"
}'Response 200
{
"id": 1,
"ticket_id": 4182,
"status": "ready",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"confidence": null,
"needs_review": false,
"notes": null,
"placeholders": [
""
],
"sources": {
"thread_message_ids": [
0
],
"note_message_ids": [
0
],
"customer_tickets": [
{
"id": 1,
"subject": "Where is order #1042?",
"status": "open"
}
],
"macros": [
{
"id": 1,
"name": "Demo Store",
"used": false
}
],
"similar": [
{
"ticket_id": 4182,
"subject": "Where is order #1042?",
"customer_message_id": 0,
"reply_message_id": 0,
"used": false
}
],
"skills": [
{
"id": 1,
"name": "Demo Store",
"used": false
}
],
"commitments": [
""
]
},
"provider": "",
"model": "",
"thread_through": "2026-11-04T09:41:12+00:00",
"current": false,
"trigger": "agent",
"author": {
"id": 1,
"name": "Demo Store"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}List what the team promised on a ticket
GET/api/ai/tickets/{id}/commitments
Promises found in the team's own replies on the ticket: a replacement, a refund, store credit, a code, a prepaid label, an exception, or something we said we would do. Each comes with the sentence that made it. Sentences that refuse or ask a question are not promises. Replies from rules, bots and auto-responders are ignored, and so are internal notes.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The promises, oldest first; one per kind, the newest wording. · AiCommitments
Request
curl \
"https://cs.growthdept.ai/api/ai/tickets/1/commitments" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"ticket_id": 4182,
"data": [
{
"kind": "replacement",
"label": "Reason for contact",
"quote": "",
"message_id": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"who": ""
}
]
}Get a ticket's drafted reply
GET/api/ai/tickets/{id}/draft
Whether drafting is on for this helpdesk, and the newest draft on the ticket that is ready or in use (null when there is none). current is false when someone wrote on the ticket after the draft was made. When drafting is off, drafting.enabled is false and drafting.message says why.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The drafting state and the draft. · AiDraftEnvelope
Request
curl "https://cs.growthdept.ai/api/ai/tickets/1/draft" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"ticket_id": 4182,
"drafting": {
"enabled": false,
"reason": "no_provider",
"provider": "",
"model": "",
"message": ""
},
"draft": {
"id": 1,
"ticket_id": 4182,
"status": "ready",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"confidence": null,
"needs_review": false,
"notes": null,
"placeholders": [
""
],
"sources": {
"thread_message_ids": [],
"note_message_ids": [],
"customer_tickets": [],
"macros": [],
"similar": [],
"skills": [],
"commitments": []
},
"provider": "",
"model": "",
"thread_through": "2026-11-04T09:41:12+00:00",
"current": false,
"trigger": "agent",
"author": {
"id": 1,
"name": "Demo Store"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
},
"ai_agent": {
"linked": false,
"agent_id": null,
"name": "Demo Store"
}
}Draft a reply for a ticket
POST/api/ai/tickets/{id}/draft
With an empty body: drafts a reply to the newest customer message from the thread (people only: rule, bot and auto-reply messages are left out), the helpdesk's active skills that fit the message, the customer's other tickets, the helpdesk's macros and replies a person sent on earlier tickets like this one. Teammates' internal notes are given to the drafter as background it must not repeat. The drafter is told to assert nothing those sources do not establish and to mark any missing fact with a placeholder the agent fills in before sending. Answers 409 when drafting is off for this helpdesk or no customer has written yet.
With body_text: stores a reply the helpdesk's AI agent wrote with its own model, for a person to review. Only the AI agent's own API key may do this (403 for anyone else; people write in the composer). skill_ids names the active skills it followed.
Either way the draft replaces any earlier ready draft on the ticket, and nothing is sent: a person inserts the draft into the composer and sends it.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| body_ | string | |
| notes | string or null | |
| confidence | number or null | |
| skill_ | array of integer |
Response
201 · The new draft, with the drafting state. · AiDraftEnvelope
Request
curl -X POST "https://cs.growthdept.ai/api/ai/tickets/1/draft" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"notes": null,
"confidence": null
}'Response 201
{
"ticket_id": 4182,
"drafting": {
"enabled": false,
"reason": "no_provider",
"provider": "",
"model": "",
"message": ""
},
"draft": {
"id": 1,
"ticket_id": 4182,
"status": "ready",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"confidence": null,
"needs_review": false,
"notes": null,
"placeholders": [
""
],
"sources": {
"thread_message_ids": [],
"note_message_ids": [],
"customer_tickets": [],
"macros": [],
"similar": [],
"skills": [],
"commitments": []
},
"provider": "",
"model": "",
"thread_through": "2026-11-04T09:41:12+00:00",
"current": false,
"trigger": "agent",
"author": {
"id": 1,
"name": "Demo Store"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
},
"ai_agent": {
"linked": false,
"agent_id": null,
"name": "Demo Store"
}
}Suggest macros for a ticket
GET/api/ai/tickets/{id}/macro-suggestions
The helpdesk's macros ranked against the ticket's latest customer message, with full-text search over each macro's name and reply text, weighted by how often the team uses it. No model is involved. Archived macros are never suggested. The list is empty when nothing matches or no customer has written yet.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| limitquery · string | How many macros, 1 to 10 (default 5). |
Response
200 · Suggested macros, best first. · AiMacroSuggestions
Request
curl \
"https://cs.growthdept.ai/api/ai/tickets/1/macro-suggestions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"ticket_id": 4182,
"keywords": [
""
],
"data": [
{
"id": 1,
"name": "Demo Store",
"score": 5,
"usage": 142
}
]
}Get a ticket's triage score
GET/api/ai/tickets/{id}/triage
The ticket's 0 to 100 priority score, its band (urgent, high, normal, low) and every reason that makes it up, with points. Scores come from the helpdesk's own data and rules, not a model. A score older than the ticket's last change, or older than ten minutes, is recomputed before it is returned.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The ticket's triage. · AiTriage
Request
curl "https://cs.growthdept.ai/api/ai/tickets/1/triage" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"ticket_id": 4182,
"score": 5,
"band": "urgent",
"reasons": [
{
"code": "if (containsAny(message.body_text, [\"where is\", \"tracking\"])) { Action(\"addTags\", { tags: \"shipping\" }) }",
"label": "Reason for contact",
"points": 0
}
],
"awaiting_reply": false,
"awaiting_since": "2026-11-04T09:41:12+00:00",
"wait_minutes": null,
"wait_clock": "business",
"sla_due_datetime": "2026-11-04T09:41:12+00:00",
"sla_source": null,
"overdue": false,
"noise": false,
"computed_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}AI Agent
The helpdesk's AI Agent: skills (how the team handles returns, order status, address changes and the rest, in if/then steps that drafted replies follow), skill templates, what the AI agent may do, and linking the AI agent's own account and key. Skills the AI agent writes start as drafts a lead agent or admin switches on, and its edits to an active skill are kept as proposals until a person accepts them. With its own key the AI agent can also leave a written draft on a ticket for a person to send. Custom actions are the helpdesk's own: steps that run in order on a ticket (helpdesk changes, Shopify order actions and HTTP calls to other apps through saved apps and reusable steps), with information to collect, conditions, the customer's agreement and an event log of every run.
The AiActionApp object · 14 fields
An outside app that action steps call.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| name | string | |
| description | string | |
| base_ | string | |
| auth_ | none, header, bearer, basic | |
| auth_ | string or null | |
| auth_ | string or null | |
| secret_ | boolean | A key, token or password is saved. It is never returned. |
| needs_ | boolean | |
| docs_ | string or null | |
| steps_ | integer | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| uri | string |
The AiActionStep object · 16 fields
A reusable HTTP step.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| app_ | integer or null | |
| app_ | string or null | |
| name | string | |
| description | string | |
| method | GET, POST, PUT, PATCH, DELETE | |
| url | string | A path on the app, or a full https URL; {{variables}} allowed in the path and query. |
| headers | array of object | |
| body | string | A JSON template. |
| inputs | array of AiActionInput | |
| outputs | array of object | |
| used_ | array of object | |
| created_ | integer or null | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| uri | string |
The AiAgent object · 10 fields
| Field | Type | Description |
|---|---|---|
| name | string | |
| linked | boolean | |
| agent | object or null | |
| keys | array of object | |
| linked_ | string or null | |
| skills | draft, active | |
| actions | object | |
| channels | object | Whether the AI agent works on each channel: email, chat, contact_form, sms, phone, other. |
| skill_ | object | |
| you | object |
The AiCustomAction object · 24 fields
An action the helpdesk built: steps in order, with the information to collect and the conditions.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| key | string | custom.<id>: the key skills use. |
| custom | boolean | |
| app | string | |
| name | string | |
| description | string | Not shown to customers. Says when to use the action and when not. |
| mode | on, ask, off | |
| kind | read, change, customer, money | |
| apps | array of string | |
| customer_ | boolean | The customer must agree before it runs. |
| based_ | string or null | The built-in action it was customized from. |
| inputs | array of AiActionInput | |
| conditions | AiActionConditions | |
| steps | array of AiActionStepRef | |
| status | in_use, not_in_use, off, needs_setup, failing | |
| problems | array of string | |
| used_ | array of object | |
| last_ | object or null | |
| created_ | object or null | |
| created_ | boolean | |
| updated_ | object or null | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| uri | string |
The AiSkill object · 22 fields
How the helpdesk wants a situation handled, for the drafter and the AI agent to follow.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| name | string | |
| when_ | string | The situations the skill is for, in the team's words. Drafting matches tickets against it. |
| intents | array of string | |
| instructions | string | The steps, plain text. "If ..., then ..." steps work best; [BRACKETS] mark facts still to fill in. |
| actions | array of string | |
| use_ | boolean | False: the drafter follows the steps and the conversation only, without macros or earlier replies. |
| status | draft, active, archived | |
| source | person, ai_agent, generated | Who wrote it: a person, the AI agent, or generated from earlier replies. |
| template_ | string or null | |
| replaces_ | integer or null | Set on a proposed change to an active skill. |
| pending_ | boolean | A draft waiting for a person. |
| generation | object or null | Counts only, for generated skills. |
| version | integer | |
| created_ | object or null | |
| updated_ | object or null | |
| activated_ | object or null | |
| activated_ | datetime or null | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| archived_ | datetime or null | |
| uri | string |
The AiActionRun object · 16 fields
One run of a custom action, with each step's outcome: the event log.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| action_ | integer | |
| action_ | string or null | |
| ticket_ | integer or null | |
| skill | object or null | |
| run_ | object or null | |
| by_ | boolean | |
| dry_ | boolean | |
| status | success, error, refused | |
| customer_ | boolean | |
| inputs | object | |
| steps | array of object | |
| error | string or null | |
| created_ | datetime or null | |
| finished_ | datetime or null | |
| uri | string |
The AiActionStepTest object · 8 fields
What a test request sent and got back.
| Field | Type | Description |
|---|---|---|
| ok | boolean | |
| http_ | integer or null | |
| error | string or null | |
| request | object | |
| response | any | The app's answer: JSON, or {text} when it is not JSON. |
| outputs | object | Each output's value read from the answer. |
| ms | integer | |
| order_ | string or null |
The AiQuestion object · 19 fields
A question a person asked the AI agent from the app, and its answer.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| chat_ | integer or null | The chat this turn belongs to. |
| mode | ask_first, auto | ask_first: propose changes and wait for Approve. auto: make them within the agent's rules. |
| kind | question, approval, rejection, routine | approval and rejection are a person's decision on the agent's last proposal; routine is a scheduled run. |
| proposal | boolean | The answer proposes changes and waits for the person's decision. |
| decision | approved, rejected, null or null | |
| decided_ | datetime or null | |
| asked_ | object | |
| text | string | |
| page | string or null | The app path the person asked from. |
| ticket_ | integer or null | The ticket they were on, if any. |
| status | pending, answering, answered, failed, cancelled | |
| answer | string or null | |
| failure | string or null | Why the AI agent could not answer, in plain words. |
| answered_ | integer or null | |
| claimed_ | datetime or null | |
| answered_ | datetime or null | |
| created_ | datetime or null | |
| uri | string |
List action apps
GET/api/ai/action-apps
Outside apps that action steps call: base URL, how the helpdesk signs in, and whether a key is saved (never the key itself). The helpdesk and the connected Shopify store are built in and not listed here.
Response
200 · The apps. · object
Request
curl "https://cs.growthdept.ai/api/ai/action-apps" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"name": "Demo Store",
"description": "",
"base_url": "",
"auth_kind": "none",
"auth_header": null,
"auth_username": null,
"secret_saved": false,
"needs_secret": false,
"docs_url": null,
"steps_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}
]
}Add an action app
POST/api/ai/action-apps
Adds an outside app for action steps: a name, its https base URL and how to sign in. auth_kind header sends the key in the header named auth_header (X-Api-Key, for example); bearer sends Authorization: Bearer; basic sends auth_username and the secret as a password. secret is stored encrypted and never returned. The URL must reach the public internet. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| description | string | |
| base_ | string | |
| auth_ | none, header, bearer, basic | |
| auth_ | string or null | |
| auth_ | string or null | |
| secret | string or null | The API key, token or password. Write-only: it is never returned. |
| docs_ | string or null |
Response
201 · The app. · AiActionApp
Request
curl -X POST "https://cs.growthdept.ai/api/ai/action-apps" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"base_url": ""
}'Response 201
{
"id": 1,
"name": "Demo Store",
"description": "",
"base_url": "",
"auth_kind": "none",
"auth_header": null,
"auth_username": null,
"secret_saved": false,
"needs_secret": false,
"docs_url": null,
"steps_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}List reusable steps
GET/api/ai/action-steps
The Steps library: HTTP requests on an app or a full URL that custom actions add by id, with the actions that use each one. The helpdesk and Shopify steps are built in (GET /api/ai/actions and the editor list them).
Response
200 · The steps. · object
Request
curl "https://cs.growthdept.ai/api/ai/action-steps" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"app_id": null,
"app_name": null,
"name": "Demo Store",
"description": "",
"method": "GET",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [
{
"name": "Demo Store",
"value": ""
}
],
"body": "",
"inputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"type": "string",
"description": "",
"required": false
}
],
"outputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"path": ""
}
],
"used_by": [
{
"id": 1,
"name": "Demo Store",
"mode": ""
}
],
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}
]
}Create a reusable step
POST/api/ai/action-steps
Creates an HTTP step. With app_id, url is the path after the app's base URL and the app signs the request in; without, url is a full https address. {{variables}} work in the path, query, header values and body: inputs.<key> for the step's inputs, plus ticket.*, customer.* and order.* from the run. outputs read values from the JSON answer by dotted path, for the next steps as steps.<n>.<key>. The AI agent can create steps; admins otherwise.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| app_ | integer or null | |
| namerequired | string | |
| description | string | |
| method | GET, POST, PUT, PATCH, DELETE | |
| urlrequired | string | |
| headers | array of object | |
| body | string | |
| inputs | array of object | |
| outputs | array of object |
Response
201 · The step. · AiActionStep
Request
curl -X POST "https://cs.growthdept.ai/api/ai/action-steps" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}'Response 201
{
"id": 1,
"app_id": null,
"app_name": null,
"name": "Demo Store",
"description": "",
"method": "GET",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [
{
"name": "Demo Store",
"value": ""
}
],
"body": "",
"inputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"type": "string",
"description": "",
"required": false
}
],
"outputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"path": ""
}
],
"used_by": [
{
"id": 1,
"name": "Demo Store",
"mode": ""
}
],
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}List AI agent actions
GET/api/ai/actions
The actions library: what the helpdesk's AI agent can do, the built-in actions app by app (helpdesk, Shopify) and then the helpdesk's own (custom: true, key custom.<id>, GET /api/ai/custom-actions/{id} for the steps). Each has this helpdesk's mode: on (it may do it when a skill says so, or for a custom action when its description fits), ask (it proposes it in an internal note and a person does it) or off. status says whether an active skill uses it (in_use), it is off, it needs setting up (problems lists what), or its last run failed. Skills name the actions they use. The server refuses the AI agent's own calls for a public reply, a close, snooze, priority, team or tag change, a Shopify order action, or a custom action unless its mode is on.
Response
200 · The actions. · object
Request
curl "https://cs.growthdept.ai/api/ai/actions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"app": "helpdesk",
"custom": false,
"id": 1,
"name": "Demo Store",
"description": "",
"kind": "read",
"mode": "on",
"modes": [
""
],
"default": "",
"apps": [
""
],
"status": "in_use",
"problems": [
""
],
"used_in": [
{
"id": 1,
"name": "Demo Store",
"status": "draft"
}
]
}
]
}Get the AI agent
GET/api/ai/agent
The helpdesk's AI agent: its name and agent account, whether it is linked, its live API keys (prefixes only), whether its skills start as drafts (skills: draft) or it may switch them on (active), the mode of each action (built-in keys and custom.<id> for the helpdesk's own actions), skill counts, and what you yourself may do (you.are_ai_agent, you.can_activate_skills, you.may_send_replies). The AI agent reads this to know its limits.
Response
200 · The AI agent. · AiAgent
Request
curl "https://cs.growthdept.ai/api/ai/agent" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"name": "Demo Store",
"linked": false,
"agent": {
"id": 1,
"email": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"keys": [
{
"id": "",
"name": "Demo Store",
"prefix": "7c1e0b",
"created_datetime": "2026-11-04T09:41:12+00:00",
"last_used_datetime": null
}
],
"linked_datetime": null,
"skills": "draft",
"actions": [],
"channels": {},
"skill_counts": {
"active": 0,
"draft": 0,
"pending_approval": 0,
"archived": 0
},
"you": {
"are_ai_agent": false,
"can_activate_skills": false,
"may_send_replies": false
}
}Change what the AI agent may do
PUT/api/ai/agent
Admins only. name renames it. skills: "active" lets it switch on its own skills (default "draft": a person switches them on). actions sets the mode of actions by key; each action lists the modes it offers. channels switches the AI agent on or off per channel (email, chat, contact_form, sms, phone, other); its drafts and custom action runs on a ticket from a channel that is off are refused. Fields you leave out keep their value.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| skills | draft, active | |
| actions | object | |
| channels | object |
Response
202 · The AI agent. · AiAgent
Request
curl -X PUT "https://cs.growthdept.ai/api/ai/agent" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"skills": "draft",
"actions": []
}'Response 202
{
"name": "Demo Store",
"linked": false,
"agent": {
"id": 1,
"email": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"keys": [
{
"id": "",
"name": "Demo Store",
"prefix": "7c1e0b",
"created_datetime": "2026-11-04T09:41:12+00:00",
"last_used_datetime": null
}
],
"linked_datetime": null,
"skills": "draft",
"actions": [],
"channels": {},
"skill_counts": {
"active": 0,
"draft": 0,
"pending_approval": 0,
"archived": 0
},
"you": {
"are_ai_agent": false,
"can_activate_skills": false,
"may_send_replies": false
}
}List custom actions
GET/api/ai/custom-actions
The actions this helpdesk built, with their steps, inputs, conditions, mode and status. GET /api/ai/actions lists them beside the built-in actions.
Response
200 · The custom actions. · object
Request
curl "https://cs.growthdept.ai/api/ai/custom-actions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"custom": false,
"app": "",
"name": "Demo Store",
"description": "",
"mode": "on",
"kind": "read",
"apps": [
""
],
"customer_confirmation": false,
"based_on": null,
"inputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"type": "string",
"description": "",
"required": false
}
],
"conditions": {
"match": "none",
"items": []
},
"steps": [
{
"kind": "helpdesk",
"op": "",
"step_id": 0,
"step_name": null,
"label": "Reason for contact",
"args": {},
"when": {
"id": 1
}
}
],
"status": "in_use",
"problems": [
""
],
"used_in": [
{
"id": 1,
"name": "Demo Store",
"status": "open"
}
],
"last_run": {
"status": "open",
"datetime": ""
},
"created_by": {
"id": 1,
"name": "Demo Store"
},
"created_by_ai_agent": false,
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}
]
}Create a custom action
POST/api/ai/custom-actions
Creates an action from steps that run in order: helpdesk changes (kind helpdesk), Shopify order actions (kind shopify) and reusable HTTP steps from the Steps library (kind step, step_id). name and description are how the AI agent decides when the action applies; they are never shown to customers. inputs is the information to collect from the customer first; conditions say when it may run. customer_confirmation (default on when a step reaches the customer or moves money) makes every run wait for the customer's yes. mode defaults to ask. The AI agent can create actions too: they are saved with mode off for a person to read and switch on. Admins otherwise.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| description | string | |
| mode | on, ask, off | |
| customer_ | boolean | |
| based_ | string or null | |
| inputs | array of object | |
| conditions | object | |
| stepsrequired | array of object |
Response
201 · The new action. · AiCustomAction
Request
curl -X POST "https://cs.growthdept.ai/api/ai/custom-actions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"steps": [
{}
]
}'Response 201
{
"id": 1,
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"custom": false,
"app": "",
"name": "Demo Store",
"description": "",
"mode": "on",
"kind": "read",
"apps": [
""
],
"customer_confirmation": false,
"based_on": null,
"inputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"type": "string",
"description": "",
"required": false
}
],
"conditions": {
"match": "none",
"items": [
{
"variable": "",
"operator": "is",
"value": ""
}
]
},
"steps": [
{
"kind": "helpdesk",
"op": "",
"step_id": 0,
"step_name": null,
"label": "Reason for contact",
"args": {},
"when": {
"id": 1
}
}
],
"status": "in_use",
"problems": [
""
],
"used_in": [
{
"id": 1,
"name": "Demo Store",
"status": "open"
}
],
"last_run": {
"status": "open",
"datetime": ""
},
"created_by": {
"id": 1,
"name": "Demo Store"
},
"created_by_ai_agent": false,
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}List skill templates
GET/api/ai/skill-templates
Starting points for common store situations (order status, returns, damaged items, cancellations, address changes and more), written in steps with [BRACKETS] where the helpdesk's own policy goes. Create a skill from one with POST /api/ai/skills, passing its fields and template_key, then fill in the brackets before switching it on.
Response
200 · The templates. · object
Request
curl "https://cs.growthdept.ai/api/ai/skill-templates" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"name": "Demo Store",
"when_to_use": "",
"intents": [
""
],
"actions": [
""
],
"use_knowledge": false,
"instructions": ""
}
]
}List skills
GET/api/ai/skills
The helpdesk's AI Agent skills: how the team wants situations handled, which the built-in drafter and the AI agent follow when they are active. Archived skills are left out unless status=archived. pending_approval=true lists drafts waiting for a person: ones the AI agent or an import wrote, and changes proposed to active skills (replaces_skill_id).
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default name:asc.created_datetime:asc, created_datetime:desc, updated_datetime:asc, updated_datetime:desc, name:asc, name:desc |
| statusquery · string | Only skills with this status.draft, active, archived |
| sourcequery · string | Only skills written this way.person, ai_agent, generated |
| pending_ | Only drafts waiting for a person.0, 1, true, false |
| searchquery · string | Words in the name, when to use or the steps. Every word must appear. |
Response
200 · A page of skills. · list of AiSkill
Request
curl "https://cs.growthdept.ai/api/ai/skills?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/ai/skills?limit=2",
"data": [
{
"id": 1,
"name": "Demo Store",
"when_to_use": "",
"intents": [
""
],
"instructions": "",
"actions": [
""
],
"use_knowledge": false,
"status": "draft",
"source": "person",
"template_key": null,
"replaces_skill_id": null,
"pending_approval": false,
"generation": {},
"version": 0,
"created_by": {
"id": 1,
"name": "Demo Store"
},
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null,
"uri": "/api/"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a skill
POST/api/ai/skills
Creates a skill: a name, when to use it, the macro intents it covers, the steps (plain text; "If ..., then ..." steps work best), the actions it uses (GET /api/ai/actions) and whether the drafter may add its own knowledge. status=active switches it on at once, which needs a lead agent or an admin. A skill the AI agent writes starts as a draft for a person to switch on, unless the helpdesk lets it switch on its own skills; when a requested active skill was saved as a draft, the response has status draft and pending_approval true. template_key records the template it started from (GET /api/ai/skill-templates).
Role: agent or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| when_ | string | |
| intents | array of discount/request, exchange/request, exchange/status, feedback, feedback/negative, feedback/positive, order/cancel, order/change, order/damaged, order/wrong, other/no_reply, other/question, other/thanks, product/question, product/recommendation, refund/request, refund/status, return/request, return/status, shipping/change, shipping/delivery-issue, shipping/policy, shipping/status, stock/request, subscription/cancel, subscription/change | |
| instructionsrequired | string | |
| actions | array of string | |
| use_ | boolean | |
| status | draft, active | |
| template_ | string or null | |
| source | generated | |
| generation | object or null |
Response
201 · The new skill. · AiSkill
Request
curl -X POST "https://cs.growthdept.ai/api/ai/skills" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"instructions": ""
}'Response 201
{
"id": 1,
"name": "Demo Store",
"when_to_use": "",
"intents": [
""
],
"instructions": "",
"actions": [
""
],
"use_knowledge": false,
"status": "draft",
"source": "person",
"template_key": null,
"replaces_skill_id": null,
"pending_approval": false,
"generation": {},
"version": 0,
"created_by": {
"id": 1,
"name": "Demo Store"
},
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null,
"uri": "/api/"
}Get an action app
GET/api/ai/action-apps/{id}
One app, without its key.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The app. · AiActionApp
Request
curl "https://cs.growthdept.ai/api/ai/action-apps/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"name": "Demo Store",
"description": "",
"base_url": "",
"auth_kind": "none",
"auth_header": null,
"auth_username": null,
"secret_saved": false,
"needs_secret": false,
"docs_url": null,
"steps_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Update an action app
PUT/api/ai/action-apps/{id}
Changes the fields you send. secret replaces the saved key; null removes it. Leaving secret out keeps it. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| description | string | |
| base_ | string | |
| auth_ | none, header, bearer, basic | |
| auth_ | string or null | |
| auth_ | string or null | |
| secret | string or null | Replaces the saved key; null removes it; leave it out to keep it. |
| docs_ | string or null |
Response
202 · The app. · AiActionApp
Request
curl -X PUT "https://cs.growthdept.ai/api/ai/action-apps/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"description": "",
"base_url": ""
}'Response 202
{
"id": 1,
"name": "Demo Store",
"description": "",
"base_url": "",
"auth_kind": "none",
"auth_header": null,
"auth_username": null,
"secret_saved": false,
"needs_secret": false,
"docs_url": null,
"steps_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Remove an action app
DELETE/api/ai/action-apps/{id}
Removes the app and erases its key. Refused while a step uses it. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Removed.
Request
curl -X DELETE "https://cs.growthdept.ai/api/ai/action-apps/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Get an action run
GET/api/ai/action-runs/{id}
One entry of a custom action's event log, with each step's request, answer and outputs. Lead agents and admins.
Role: lead-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The run. · AiActionRun
Request
curl "https://cs.growthdept.ai/api/ai/action-runs/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"action_id": 0,
"action_name": null,
"ticket_id": 4182,
"skill": {
"id": 1,
"name": "Demo Store"
},
"run_by": {
"id": 1,
"name": "Demo Store"
},
"by_ai_agent": false,
"dry_run": false,
"status": "success",
"customer_confirmed": false,
"inputs": {},
"steps": [
{
"index": 0,
"kind": "",
"name": "Demo Store",
"status": "success",
"detail": null,
"error": null,
"http_status": null,
"outputs": {},
"request": {
"method": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [
""
],
"body_excerpt": null
},
"response_excerpt": null,
"ms": null
}
],
"error": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"finished_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}Get a reusable step
GET/api/ai/action-steps/{id}
One step, with the actions that use it.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The step. · AiActionStep
Request
curl "https://cs.growthdept.ai/api/ai/action-steps/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"app_id": null,
"app_name": null,
"name": "Demo Store",
"description": "",
"method": "GET",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [
{
"name": "Demo Store",
"value": ""
}
],
"body": "",
"inputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"type": "string",
"description": "",
"required": false
}
],
"outputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"path": ""
}
],
"used_by": [
{
"id": 1,
"name": "Demo Store",
"mode": ""
}
],
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Update a reusable step
PUT/api/ai/action-steps/{id}
Changes the fields you send. Every action that adds the step uses the new version at once. The AI agent may change a step only while no switched-on action uses it.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| app_ | integer or null | |
| name | string | |
| description | string | |
| method | GET, POST, PUT, PATCH, DELETE | |
| url | string | |
| headers | array of object | |
| body | string | |
| inputs | array of object | |
| outputs | array of object |
Response
202 · The step. · AiActionStep
Request
curl -X PUT "https://cs.growthdept.ai/api/ai/action-steps/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"app_id": null,
"name": "Demo Store",
"description": ""
}'Response 202
{
"id": 1,
"app_id": null,
"app_name": null,
"name": "Demo Store",
"description": "",
"method": "GET",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [
{
"name": "Demo Store",
"value": ""
}
],
"body": "",
"inputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"type": "string",
"description": "",
"required": false
}
],
"outputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"path": ""
}
],
"used_by": [
{
"id": 1,
"name": "Demo Store",
"mode": ""
}
],
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Delete a reusable step
DELETE/api/ai/action-steps/{id}
Deletes the step. Refused while an action adds it. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/ai/action-steps/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Test a step before saving it
POST/api/ai/action-steps/test
The same as POST /api/ai/action-steps/{id}/test for a step that is not saved yet: send it as step. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| steprequired | object | |
| values | object | |
| ticket_ | integer or null |
Response
200 · What was sent and what came back. · AiActionStepTest
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/action-steps/test" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"step": {
"app_id": null,
"name": "Demo Store",
"description": "",
"method": "GET",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [
{
"name": "Demo Store",
"value": ""
}
],
"body": "",
"inputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"type": "string",
"description": "",
"required": false
}
],
"outputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"path": ""
}
]
}
}'Response 200
{
"ok": false,
"http_status": null,
"error": null,
"request": {
"method": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [
""
],
"body_excerpt": null
},
"response": {},
"outputs": {},
"ms": 0,
"order_note": null
}Link the AI agent
POST/api/ai/agent/link
Admins only. Creates the AI agent's account in this helpdesk (an agent with role bot and no sign-in; email defaults to haylee@agents.growthdept.ai and is only an identifier) or reactivates it, and makes it a new API key. The key is in the response once: give it to the agent (HTTP Basic with the agent's email and the key). rotate=true revokes its earlier keys first. Everything the agent does with the key is recorded under its name.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| string | ||
| rotate | boolean |
Response
201 · The agent account and its new key. · object
Request
curl -X POST "https://cs.growthdept.ai/api/ai/agent/link" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"email": "maya.okafor@example.com",
"rotate": false
}'Response 201
{}Unlink the AI agent
DELETE/api/ai/agent/link
Admins only. Revokes the AI agent's API keys and deactivates its account. Its drafts, notes and skills stay, marked with its name.
Role: admin or higher
Response
200 · What was revoked. · object
Request
curl -X DELETE "https://cs.growthdept.ai/api/ai/agent/link" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}List Ask Haylee questions
GET/api/ai/agent/questions
For a person: their own questions to the AI agent, newest first, with the answers. For the AI agent's key: the questions waiting for an answer, oldest first (open=false lists every recent question instead), each with its chat (title, kind chat or routine, and up to 10 earlier turns as history). mode says whether the person wants a proposal first (ask_first) or the change made (auto); kind approval or rejection is a person's decision on the agent's last proposal. A question the agent claimed but did not answer within 10 minutes shows as pending again.
Parameters
| Name | Description |
|---|---|
| openquery · string | AI agent only: false lists all recent questions, not just the waiting ones.0, 1, true, false |
| limitquery · string | At most this many (1 to 100, default 30). |
Response
200 · The questions. · object
Request
curl "https://cs.growthdept.ai/api/ai/agent/questions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
]
}Ask Haylee a question
POST/api/ai/agent/questions
Asks the helpdesk's AI agent a question or a request from the app ("how many tickets are waiting on returns?", "write a macro for late deliveries"). The agent, which runs on the brand's own machine, picks it up within about a minute and answers through the API; poll GET .../questions/{id} for the answer. page and ticket_id say where the person was. Answers 409 when no AI agent is linked or the person already has 5 questions waiting.
Body
| Field | Type | Description |
|---|---|---|
| textrequired | string | |
| page | string or null | |
| ticket_ | integer or null | |
| chat_ | integer or null | Continue this chat; a new chat starts when it is left out. |
| mode | ask_first, auto | ask_first (default): the agent proposes changes and waits for Approve. auto: it makes them within its rules. |
Response
201 · The question, pending. · AiQuestion
Request
curl -X POST "https://cs.growthdept.ai/api/ai/agent/questions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": ""
}'Response 201
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}Get a custom action
GET/api/ai/custom-actions/{id}
One custom action with its steps, inputs, conditions, mode, the skills that use it, its last run and what still needs setting up.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The action. · AiCustomAction
Request
curl "https://cs.growthdept.ai/api/ai/custom-actions/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"custom": false,
"app": "",
"name": "Demo Store",
"description": "",
"mode": "on",
"kind": "read",
"apps": [
""
],
"customer_confirmation": false,
"based_on": null,
"inputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"type": "string",
"description": "",
"required": false
}
],
"conditions": {
"match": "none",
"items": [
{
"variable": "",
"operator": "is",
"value": ""
}
]
},
"steps": [
{
"kind": "helpdesk",
"op": "",
"step_id": 0,
"step_name": null,
"label": "Reason for contact",
"args": {},
"when": {
"id": 1
}
}
],
"status": "in_use",
"problems": [
""
],
"used_in": [
{
"id": 1,
"name": "Demo Store",
"status": "open"
}
],
"last_run": {
"status": "open",
"datetime": ""
},
"created_by": {
"id": 1,
"name": "Demo Store"
},
"created_by_ai_agent": false,
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Update a custom action
PUT/api/ai/custom-actions/{id}
Changes the fields you send. Skills that name the action use the new version at once. mode switches it on (on), to a person (ask) or off. The AI agent may change only actions that are off, and cannot switch them on.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| description | string | |
| mode | on, ask, off | |
| customer_ | boolean | |
| inputs | array of object | |
| conditions | object | |
| steps | array of object |
Response
202 · The action. · AiCustomAction
Request
curl -X PUT "https://cs.growthdept.ai/api/ai/custom-actions/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"description": "",
"mode": "on"
}'Response 202
{
"id": 1,
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"custom": false,
"app": "",
"name": "Demo Store",
"description": "",
"mode": "on",
"kind": "read",
"apps": [
""
],
"customer_confirmation": false,
"based_on": null,
"inputs": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"type": "string",
"description": "",
"required": false
}
],
"conditions": {
"match": "none",
"items": [
{
"variable": "",
"operator": "is",
"value": ""
}
]
},
"steps": [
{
"kind": "helpdesk",
"op": "",
"step_id": 0,
"step_name": null,
"label": "Reason for contact",
"args": {},
"when": {
"id": 1
}
}
],
"status": "in_use",
"problems": [
""
],
"used_in": [
{
"id": 1,
"name": "Demo Store",
"status": "open"
}
],
"last_run": {
"status": "open",
"datetime": ""
},
"created_by": {
"id": 1,
"name": "Demo Store"
},
"created_by_ai_agent": false,
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Delete a custom action
DELETE/api/ai/custom-actions/{id}
Deletes the action. Refused while a skill names it: take it out of the skill first. Its event log goes with it. Built-in actions cannot be deleted; switch them off instead.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/ai/custom-actions/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Get a skill
GET/api/ai/skills/{id}
One skill, any status.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The skill. · AiSkill
Request
curl "https://cs.growthdept.ai/api/ai/skills/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"name": "Demo Store",
"when_to_use": "",
"intents": [
""
],
"instructions": "",
"actions": [
""
],
"use_knowledge": false,
"status": "draft",
"source": "person",
"template_key": null,
"replaces_skill_id": null,
"pending_approval": false,
"generation": {},
"version": 0,
"created_by": {
"id": 1,
"name": "Demo Store"
},
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null,
"uri": "/api/"
}Update a skill
PUT/api/ai/skills/{id}
Changes the fields you send. A draft changes in place (202). An active skill changes in place only for a lead agent or admin; when anyone else, the AI agent included, edits an active skill, the change is saved as a proposal: a draft with replaces_skill_id set, answered with 201 (a new proposal) or 202 (their open proposal updated), and the active skill keeps working until a person switches the proposal on. Archived skills cannot be changed.
Role: agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| when_ | string | |
| intents | array of discount/request, exchange/request, exchange/status, feedback, feedback/negative, feedback/positive, order/cancel, order/change, order/damaged, order/wrong, other/no_reply, other/question, other/thanks, product/question, product/recommendation, refund/request, refund/status, return/request, return/status, shipping/change, shipping/delivery-issue, shipping/policy, shipping/status, stock/request, subscription/cancel, subscription/change | |
| instructions | string | |
| actions | array of string | |
| use_ | boolean |
Response
202 · The skill, or the proposal that holds the change. · AiSkill
Request
curl -X PUT "https://cs.growthdept.ai/api/ai/skills/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"when_to_use": "",
"intents": [
"discount/request"
]
}'Response 202
{
"id": 1,
"name": "Demo Store",
"when_to_use": "",
"intents": [
""
],
"instructions": "",
"actions": [
""
],
"use_knowledge": false,
"status": "draft",
"source": "person",
"template_key": null,
"replaces_skill_id": null,
"pending_approval": false,
"generation": {},
"version": 0,
"created_by": {
"id": 1,
"name": "Demo Store"
},
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null,
"uri": "/api/"
}Archive a skill
DELETE/api/ai/skills/{id}
Archives the skill (its history stays; POST .../deactivate restores it as a draft). Archiving an active skill needs a lead agent or an admin. The AI agent can archive the drafts and proposals it wrote. Open proposals for the skill are archived with it. Answers with the archived skill.
Role: agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The archived skill. · AiSkill
Request
curl -X DELETE "https://cs.growthdept.ai/api/ai/skills/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"name": "Demo Store",
"when_to_use": "",
"intents": [
""
],
"instructions": "",
"actions": [
""
],
"use_knowledge": false,
"status": "draft",
"source": "person",
"template_key": null,
"replaces_skill_id": null,
"pending_approval": false,
"generation": {},
"version": 0,
"created_by": {
"id": 1,
"name": "Demo Store"
},
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null,
"uri": "/api/"
}Test a reusable step
POST/api/ai/action-steps/{id}/test
Sends the step once, for real, with the input values you give (and ticket_id's ticket, customer and newest order for ticket.*, customer.* and order.*). Answers with the request (header names only, never the app's key), the answer and the outputs read from it. Nothing is logged. Admins only; demo helpdesks cannot call outside apps.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| values | object | Values for the step's inputs. |
| ticket_ | integer or null | A ticket whose customer and order fill ticket.*, customer.* and order.*. |
Response
200 · What was sent and what came back. · AiActionStepTest
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/action-steps/1/test" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"values": {},
"ticket_id": 4182
}'Response 200
{
"ok": false,
"http_status": null,
"error": null,
"request": {
"method": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [
""
],
"body_excerpt": null
},
"response": {},
"outputs": {},
"ms": 0,
"order_note": null
}Get an Ask Haylee question
GET/api/ai/agent/questions/{id}
One question with its status and answer. The person who asked and the AI agent can read it.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The question. · AiQuestion
Request
curl \
"https://cs.growthdept.ai/api/ai/agent/questions/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}Run a custom action on a ticket
POST/api/ai/custom-actions/{id}/run
Runs the action's steps in order on the ticket and stops at the first that fails. inputs are the values collected from the customer; order_id names the order (#1001) when a step acts on one. When the action asks for the customer's agreement, send customer_confirmed true only after the customer said yes in the conversation. The AI agent may run an action whose mode is on; people may run any action that is not off. Refused runs (mode, missing agreement, conditions not met) answer 403 or 409 and are still written to the event log. A real run answers 201 with the run, whose status is success or error, and leaves an internal note on the ticket saying what happened. dry_run true checks everything and shows what each step would send, running nothing (200); the AI agent may dry-run an action set to ask, to propose it precisely.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| ticket_ | integer | |
| order_ | string or integer | The order the action is about: its name (#1001), number or id. Needed when a step acts on an order. |
| inputs | object | |
| customer_ | boolean | The customer agreed in the conversation. Needed when the action asks for confirmation. |
| skill_ | integer or null | The skill that called for the action, for the usage report. |
| dry_ | boolean | Check the information and conditions and show what each step would send, without running anything. |
Response
201 · The run, from the event log. · AiActionRun
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/custom-actions/1/run" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ticket_id": 4182
}'Response 201
{
"id": 1,
"action_id": 0,
"action_name": null,
"ticket_id": 4182,
"skill": {
"id": 1,
"name": "Demo Store"
},
"run_by": {
"id": 1,
"name": "Demo Store"
},
"by_ai_agent": false,
"dry_run": false,
"status": "success",
"customer_confirmed": false,
"inputs": {},
"steps": [
{
"index": 0,
"kind": "",
"name": "Demo Store",
"status": "success",
"detail": null,
"error": null,
"http_status": null,
"outputs": {},
"request": {
"method": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [
""
],
"body_excerpt": null
},
"response_excerpt": null,
"ms": null
}
],
"error": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"finished_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}List an action's runs
GET/api/ai/custom-actions/{id}/runs
The action's event log, newest first: when it ran, on which ticket, who ran it, the result and each step's outcome (the request sent and the start of the answer). Lead agents and admins.
Role: lead-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| statusquery · string | success, error, refused |
| ticket_ | Only runs on this ticket. |
| sincequery · datetime | From this time (ISO 8601). |
| untilquery · datetime | Before this time. |
| dry_ | true: only dry runs; false: only real runs.0, 1, true, false |
| limitquery · string | At most this many (1 to 200, default 50). |
Response
200 · The runs. · object
Request
curl \
"https://cs.growthdept.ai/api/ai/custom-actions/1/runs" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"action_id": 0,
"action_name": null,
"ticket_id": 4182,
"skill": {
"id": 1,
"name": "Demo Store"
},
"run_by": {
"id": 1,
"name": "Demo Store"
},
"by_ai_agent": false,
"dry_run": false,
"status": "success",
"customer_confirmed": false,
"inputs": {},
"steps": [
{
"index": 0,
"kind": "",
"name": "Demo Store",
"status": "success",
"detail": null,
"error": null,
"http_status": null,
"outputs": {},
"request": {
"method": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"headers": [],
"body_excerpt": null
},
"response_excerpt": null,
"ms": null
}
],
"error": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"finished_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
]
}Where an action is used
GET/api/ai/custom-actions/{id}/usage
The skills that name the action, and how many real runs each skill led to in the period (runs without a skill are counted under skill null).
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| sincequery · datetime | |
| untilquery · datetime |
Response
200 · Skills and run counts. · object
Request
curl \
"https://cs.growthdept.ai/api/ai/custom-actions/1/usage" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"skills": [
{
"id": 1,
"name": "Demo Store",
"status": "open"
}
],
"runs": [
{
"skill": {},
"runs": 0,
"succeeded": 0,
"failed": 0,
"refused": 0,
"last_datetime": null
}
]
}Switch a skill on
POST/api/ai/skills/{id}/activate
Switches the skill on, so drafting follows it. For a proposal (replaces_skill_id), its text goes into the skill it replaces, which keeps its id and becomes active; the proposal is archived. Needs a lead agent or an admin, or the AI agent when the helpdesk lets it switch on its own skills.
Role: agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
Any JSON value.
Response
200 · The skill. · AiSkill
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/skills/1/activate" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 200
{
"id": 1,
"name": "Demo Store",
"when_to_use": "",
"intents": [
""
],
"instructions": "",
"actions": [
""
],
"use_knowledge": false,
"status": "draft",
"source": "person",
"template_key": null,
"replaces_skill_id": null,
"pending_approval": false,
"generation": {},
"version": 0,
"created_by": {
"id": 1,
"name": "Demo Store"
},
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null,
"uri": "/api/"
}Switch a skill off
POST/api/ai/skills/{id}/deactivate
Turns an active skill back into a draft, or restores an archived skill as a draft. Needs a lead agent or an admin, or the AI agent when the helpdesk lets it switch on its own skills.
Role: agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
Any JSON value.
Response
200 · The skill. · AiSkill
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/skills/1/deactivate" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 200
{
"id": 1,
"name": "Demo Store",
"when_to_use": "",
"intents": [
""
],
"instructions": "",
"actions": [
""
],
"use_knowledge": false,
"status": "draft",
"source": "person",
"template_key": null,
"replaces_skill_id": null,
"pending_approval": false,
"generation": {},
"version": 0,
"created_by": {
"id": 1,
"name": "Demo Store"
},
"updated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_by": {
"id": 1,
"name": "Demo Store"
},
"activated_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"archived_datetime": null,
"uri": "/api/"
}List a skill's history
GET/api/ai/skills/{id}/revisions
Every saved version of the skill and of the changes proposed to it, newest first (up to 50): what changed, who saved it and the full text at that point.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The skill's revisions. · object
Request
curl \
"https://cs.growthdept.ai/api/ai/skills/1/revisions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"version": 0,
"change": "",
"name": "Demo Store",
"when_to_use": "",
"intents": [
""
],
"instructions": "",
"actions": [
""
],
"use_knowledge": false,
"status": "open",
"agent": {
"id": 1,
"name": "Demo Store"
},
"created_datetime": "2026-11-04T09:41:12+00:00"
}
]
}Answer a question (AI agent)
POST/api/ai/agent/questions/{id}/answer
The AI agent's answer, plain text (Markdown links are fine), or a failure saying in plain words why it could not answer. proposal true marks an answer that proposes changes and waits for the person's Approve or Reject (ask_first turns only); their decision arrives as a new turn. Only the AI agent's key.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| answer | string | |
| failure | string | |
| proposal | boolean |
Response
200 · The answered question. · AiQuestion
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/agent/questions/1/answer" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"answer": "",
"failure": "",
"proposal": false
}'Response 200
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}Cancel a question
POST/api/ai/agent/questions/{id}/cancel
The person who asked withdraws a question that has not been answered.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
Any JSON value.
Response
200 · The question. · AiQuestion
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/agent/questions/1/cancel" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 200
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}Claim a question (AI agent)
POST/api/ai/agent/questions/{id}/claim
The AI agent marks a pending question as being answered, so the panel shows that it is working on it. Without an answer within 10 minutes it is pending again. Only the AI agent's key.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
Any JSON value.
Response
200 · The question. · AiQuestion
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/agent/questions/1/claim" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 200
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}AI Journey
The helpdesk's front to Growth Dept ACR, which texts, calls and emails shoppers: connect an ACR store key, see the engagements (cart abandoned, post-purchase, after delivery, win-back) and one-off campaigns, make and edit drafts, run ACR's simulated test, pause, and read ACR's figures. Publishing, triggers and enrolling stay in ACR with Growth Dept's approval. Segments are saved groups of customers by their store data, counted here and passed to ACR as a draft's start condition.
The JourneyCampaign object · 13 fields
An ACR campaign as AI Journey lists it.
| Field | Type | Description |
|---|---|---|
| id | integer | The ACR campaign id. |
| name | string | |
| objective | string | |
| objective_ | string | |
| journey | string or null | cart_abandoned, post_purchase, after_delivery, win_back or one_off. |
| status | draft, published, paused, archived | |
| display_ | setup_not_completed, running, paused, archived | |
| has_ | boolean | |
| agent_ | string or null | |
| published_ | datetime or null | |
| changed_ | datetime | |
| stats | object | |
| acr_ | string | The campaign's setup in ACR. |
The JourneyConnection object · 8 fields
The ACR store AI Journey uses. connected false when none.
| Field | Type | Description |
|---|---|---|
| connected | boolean | |
| store | object | |
| role | viewer, member, admin, owner | |
| can_ | boolean | The key may make and edit drafts (member and up). |
| key_ | string | |
| last_ | datetime or null | |
| last_ | string or null | |
| connected_ | datetime |
The CustomerSegment object · 10 fields
A saved group of customers by their store data.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| name | string | |
| description | string or null | |
| rules | array of object | |
| acr | object | |
| customers | integer or null | Customers the helpdesk knows who match, from its copy of the store data. |
| customers_ | integer or null | Customers with store data in the helpdesk. |
| capped | boolean | True when more than 50,000 customers have store data and only the first 50,000 were counted. |
| created_ | datetime | |
| updated_ | datetime |
The JourneyTest object · 4 fields
A simulated conversation run by ACR. Nothing is sent to anyone.
| Field | Type | Description |
|---|---|---|
| test_ | string | |
| status | queued, running, done, failed | |
| transcript | array of object | |
| note | string |
AI Journey performance
GET/api/ai-journey/analytics
ACR's figures for the period (range last_7_days, last_14_days, last_30_days or all_time; campaign_id for one campaign): shoppers reached, engaged and successful against the period before, revenue per currency (orders with a campaign code, orders credited by engagement, total), successes by goal, a day-by-day series, and reach per channel with each rate's numerator and denominator. ACR's own credit, not a figure blended across channels. Test runs are left out.
Parameters
| Name | Description |
|---|---|
| rangequery · string | last_7_days, last_14_days, last_30_days, all_timedefault last_30_days |
| campaign_ | Only this campaign. |
Response
200 · The figures, or connected false. · object
Request
curl \
"https://cs.growthdept.ai/api/ai-journey/analytics" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}List one-off campaigns
GET/api/ai-journey/campaigns
One-off campaigns: ACR campaigns with the share-information objective, whose shoppers come from a file you upload in ACR.
Response
200 · The campaigns. · object
Request
curl \
"https://cs.growthdept.ai/api/ai-journey/campaigns" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"name": "Demo Store",
"objective": "",
"objective_label": "",
"journey": null,
"status": "draft",
"display_status": "setup_not_completed",
"has_unpublished_changes": false,
"agent_name": null,
"published_at": "2026-11-04T09:41:12+00:00",
"changed_at": "2026-11-04T09:41:12+00:00",
"stats": {
"runs": 0,
"active_runs": 0,
"conversions": 0
},
"acr_url": ""
}
]
}Create a draft in ACR
POST/api/ai-journey/campaigns
Makes an ACR campaign as a draft from the objective's template, with its triggers off: journey cart_abandoned, post_purchase, after_delivery or win_back for an engagement, or one_off for a one-off campaign. A draft reaches no one. Publishing it, switching its triggers on and enrolling shoppers happen in ACR with Growth Dept's approval. Needs a member key. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| journeyrequired | cart_abandoned, post_purchase, after_delivery, win_back, browse_abandoned, welcome, one_off |
Response
201 · The draft. · JourneyCampaign
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai-journey/campaigns" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"journey": "cart_abandoned"
}'Response 201
{
"id": 1,
"name": "Demo Store",
"objective": "",
"objective_label": "",
"journey": null,
"status": "draft",
"display_status": "setup_not_completed",
"has_unpublished_changes": false,
"agent_name": null,
"published_at": "2026-11-04T09:41:12+00:00",
"changed_at": "2026-11-04T09:41:12+00:00",
"stats": {
"runs": 0,
"active_runs": 0,
"conversions": 0
},
"acr_url": ""
}The ACR store AI Journey uses
GET/api/ai-journey/connection
Whether AI Journey is connected to a Growth Dept ACR store, which store, the key's role in it (viewer keys only read; member keys also make drafts) and the key's first characters. The key itself is never shown.
Response
200 · The connection. · JourneyConnection
Request
curl \
"https://cs.growthdept.ai/api/ai-journey/connection" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"connected": false,
"store": {
"id": "",
"slug": "unassigned-shipping",
"name": "Demo Store",
"currency": "USD",
"timezone": "America/Los_Angeles"
},
"role": "viewer",
"can_draft": false,
"key_prefix": "",
"last_ok_datetime": "2026-11-04T09:41:12+00:00",
"last_error": null,
"connected_datetime": "2026-11-04T09:41:12+00:00"
}Connect an ACR store
PUT/api/ai-journey/connection
Saves an ACR store API key (it starts with acr_) after asking ACR which store and role it opens. It replaces any key saved before. The key is stored encrypted. Connecting sends nothing to anyone. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| keyrequired | string |
Response
202 · The connection. · JourneyConnection
Request
curl -X PUT \
"https://cs.growthdept.ai/api/ai-journey/connection" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6"
}'Response 202
{
"connected": false,
"store": {
"id": "",
"slug": "unassigned-shipping",
"name": "Demo Store",
"currency": "USD",
"timezone": "America/Los_Angeles"
},
"role": "viewer",
"can_draft": false,
"key_prefix": "",
"last_ok_datetime": "2026-11-04T09:41:12+00:00",
"last_error": null,
"connected_datetime": "2026-11-04T09:41:12+00:00"
}Disconnect ACR
DELETE/api/ai-journey/connection
Forgets the saved key. Campaigns in ACR keep running or stay paused as they are; manage them in ACR. Admins only.
Role: admin or higher
Response
204 · Disconnected.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/ai-journey/connection" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)List engagements
GET/api/ai-journey/engagements
The automated journeys and the ACR campaigns that run each one: cart abandoned (ACR's recover_checkout), post-purchase (upsell_post_purchase), after delivery (post_delivery) and customer win-back (client_reactivation). Browse abandoned and welcome are listed with available false and the reason: ACR has no objective for them yet. Without a connection, every journey lists no campaigns.
Response
200 · The journeys. · object
Request
curl \
"https://cs.growthdept.ai/api/ai-journey/engagements" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}List segments
GET/api/ai-journey/segments
Saved groups of customers by their store data, each with how many customers the helpdesk knows in it (customers is null when it was not counted) and its ACR start condition.
Response
200 · The segments. · object
Request
curl "https://cs.growthdept.ai/api/ai-journey/segments" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"name": "Demo Store",
"description": null,
"rules": [
{
"field": "",
"operator": "",
"value": ""
}
],
"acr": {
"formula": null,
"left_out": [
""
]
},
"customers": null,
"customers_known": null,
"capped": false,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
]
}Create a segment
POST/api/ai-journey/segments
One to ten rules, all of which a customer must meet: orders_count, total_spent, days_since_last_order (at_least or at_most a number), country (is or is_not a list such as US, CA), returning (is yes or no) and customer_tag (is or is_not). Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| description | string or null | |
| rulesrequired | array of object |
Response
201 · The segment. · CustomerSegment
Request
curl -X POST "https://cs.growthdept.ai/api/ai-journey/segments" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"rules": [
{
"field": "orders_count",
"operator": "at_least",
"value": ""
}
]
}'Response 201
{
"id": 1,
"name": "Demo Store",
"description": null,
"rules": [
{
"field": "",
"operator": "",
"value": ""
}
],
"acr": {
"formula": null,
"left_out": [
""
]
},
"customers": null,
"customers_known": null,
"capped": false,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Get a campaign
GET/api/ai-journey/campaigns/{id}
One ACR engagement or one-off campaign: its status, triggers (read-only here), the setup steps ACR still needs, whether the store can text yet, the draft's texting and email guidelines, and the draft's outreach steps with their timing and any fixed wording.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The campaign. · object
Request
curl \
"https://cs.growthdept.ai/api/ai-journey/campaigns/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Get a segment
GET/api/ai-journey/segments/{id}
One segment with its rules, its customer count and its ACR start condition.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The segment. · CustomerSegment
Request
curl \
"https://cs.growthdept.ai/api/ai-journey/segments/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"name": "Demo Store",
"description": null,
"rules": [
{
"field": "",
"operator": "",
"value": ""
}
],
"acr": {
"formula": null,
"left_out": [
""
]
},
"customers": null,
"customers_known": null,
"capped": false,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Update a segment
PUT/api/ai-journey/segments/{id}
Changes the fields you send. Campaigns that already use its start condition in ACR keep the condition they were given. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| description | string or null | |
| rules | array of object |
Response
202 · The segment. · CustomerSegment
Request
curl -X PUT \
"https://cs.growthdept.ai/api/ai-journey/segments/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"description": null,
"rules": [
{
"field": "orders_count",
"operator": "at_least",
"value": ""
}
]
}'Response 202
{
"id": 1,
"name": "Demo Store",
"description": null,
"rules": [
{
"field": "",
"operator": "",
"value": ""
}
],
"acr": {
"formula": null,
"left_out": [
""
]
},
"customers": null,
"customers_known": null,
"capped": false,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Delete a segment
DELETE/api/ai-journey/segments/{id}
Deletes the segment here. Start conditions already saved in ACR stay as they are. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Deleted.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/ai-journey/segments/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Use a segment as a draft's start condition
PUT/api/ai-journey/campaigns/{id}/conditions
Turns the segment's rules into ACR's start condition for a draft campaign (rules ACR does not receive, such as store customer tags, are left out and listed). On a published or paused campaign the condition would apply at once, so this answers 409 there. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| segment_ | integer |
Response
202 · The formula ACR saved and the rules left out. · object
Request
curl -X PUT \
"https://cs.growthdept.ai/api/ai-journey/campaigns/1/conditions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"segment_id": 0
}'Response 202
{
"formula": null,
"left_out": [
""
]
}Change texting and email guidelines
PUT/api/ai-journey/campaigns/{id}/guidelines
The store's own rules for the campaign's texts (sms) and emails (email), up to 2,000 characters each: length, tone, words to avoid. ACR's agent reads them whenever it writes a message. They go into the campaign's draft; a published campaign keeps its current guidelines until Growth Dept publishes again. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| sms | string | |
| string |
Response
202 · The draft's guidelines. · object
Request
curl -X PUT \
"https://cs.growthdept.ai/api/ai-journey/campaigns/1/guidelines" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sms": "",
"email": "maya.okafor@example.com"
}'Response 202
{
"sms": "",
"email": "maya.okafor@example.com"
}Pause a campaign
POST/api/ai-journey/campaigns/{id}/pause
Stops the campaign taking new shoppers; conversations already under way finish. Resuming happens in ACR with Growth Dept's approval. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| reason | string or null |
Response
202 · The campaign. · JourneyCampaign
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai-journey/campaigns/1/pause" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": null
}'Response 202
{
"id": 1,
"name": "Demo Store",
"objective": "",
"objective_label": "",
"journey": null,
"status": "draft",
"display_status": "setup_not_completed",
"has_unpublished_changes": false,
"agent_name": null,
"published_at": "2026-11-04T09:41:12+00:00",
"changed_at": "2026-11-04T09:41:12+00:00",
"stats": {
"runs": 0,
"active_runs": 0,
"conversions": 0
},
"acr_url": ""
}Run a simulated conversation
POST/api/ai-journey/campaigns/{id}/tests
ACR's agent plays the campaign's draft through with a made-up shopper called first_name, on the channel you choose (sms, email or call). Nothing is sent to anyone. Answers with the test id; read the transcript with GET .../tests/{test_id} until status is done. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| first_ | string | |
| channel | sms, email, call | |
| language | string or null |
Response
202 · The test. · JourneyTest
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai-journey/campaigns/1/tests" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"first_name": ""
}'Response 202
{
"test_id": "",
"status": "queued",
"transcript": [
{
"role": "agent",
"text": ""
}
],
"note": ""
}Ask the AI agent to write the texts
POST/api/ai-journey/campaigns/{id}/texts
Queues a request in a new Assistant chat for the helpdesk's AI agent to propose the campaign's texting guidelines, a first text and an email in the brand's voice. It answers from the brand's machine with a proposal to approve; once approved it writes them into the ACR draft, never the published campaign. Answers with the chat's id. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| goal | string or null |
Response
201 · The chat. · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai-journey/campaigns/1/texts" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"goal": null
}'Response 201
{
"chat_id": 0
}Get a simulated conversation
GET/api/ai-journey/campaigns/{id}/tests/{test_id}
The test's status (queued, running, done or failed) and its transcript so far.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| test_ |
Response
200 · The test. · JourneyTest
Request
curl \
"https://cs.growthdept.ai/api/ai-journey/campaigns/1/tests/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"test_id": "",
"status": "queued",
"transcript": [
{
"role": "agent",
"text": ""
}
],
"note": ""
}Assistant
Chats and routines with the helpdesk's AI agent. A chat is a list of turns; each turn is queued for the AI agent, which runs on the brand's own machine and answers through the API within about a minute. In ask-first mode the agent answers with a proposal and waits: approving or rejecting it adds a turn telling it what to do. Chats are private until their owner shares them with the team. Routines ask the agent a question on a schedule; each run is a chat of its own.
The AiChatWithMessages object · 15 fields
A chat and its turns, oldest first.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| title | string | |
| kind | chat, routine | |
| routine | object or null | |
| owner | object | |
| yours | boolean | |
| shared | boolean | Teammates can open the chat and add to it. |
| turns | integer | |
| waiting | integer | Turns waiting for the AI agent. |
| proposals | integer | Proposals waiting for a decision. |
| last_ | string or null | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| uri | string | |
| messages | array of AiQuestion |
The AiRoutine object · 19 fields
A question the AI agent answers on a schedule.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| owner | object | |
| name | string | |
| instructions | string | |
| frequency | daily, weekdays, weekly, monthly | |
| hour | integer | |
| minute | integer | |
| weekday | integer or null | 1 Monday .. 7 Sunday, for weekly routines. |
| monthday | integer or null | 1..28, for monthly routines. |
| timezone | string | |
| schedule | string | The schedule in words. |
| mode | ask_first, auto | |
| template_ | string or null | |
| paused | boolean | |
| next_ | datetime or null | |
| last_ | datetime or null | |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| uri | string |
List chats
GET/api/ai/assistant/chats
Your chats with the helpdesk's AI agent and the ones teammates shared, most recent first. kind=routine lists routine runs; routine_id one routine's runs; search matches titles, questions and answers.
Parameters
| Name | Description |
|---|---|
| searchquery · string | Words in the title, a question or an answer. |
| kindquery · string | chat, routine |
| routine_ | Runs of this routine. |
| limitquery · string | At most this many (1 to 200, default 50). |
Response
200 · The chats. · object
Request
curl "https://cs.growthdept.ai/api/ai/assistant/chats" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"title": "",
"kind": "chat",
"routine": {
"id": 1,
"name": "Demo Store"
},
"owner": {
"id": 1,
"name": "Demo Store"
},
"yours": false,
"shared": false,
"turns": 0,
"waiting": 0,
"proposals": 0,
"last_text": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}
]
}Start a chat
POST/api/ai/assistant/chats
Starts a chat with the AI agent with a first question or request. mode ask_first (default) asks the agent to propose any change and wait for Approve; auto lets it make changes within its own rules and your role's limits. The agent runs on the brand's own machine and answers within about a minute; poll GET .../chats/{id}. page and ticket_id say where you were. Answers 409 when no AI agent is linked or you already have 5 questions waiting.
Body
| Field | Type | Description |
|---|---|---|
| textrequired | string | |
| mode | ask_first, auto | |
| title | string or null | |
| shared | boolean | |
| page | string or null | |
| ticket_ | integer or null |
Response
201 · The chat with its first turn. · AiChatWithMessages
Request
curl -X POST "https://cs.growthdept.ai/api/ai/assistant/chats" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": ""
}'Response 201
{
"id": 1,
"title": "",
"kind": "chat",
"routine": {
"id": 1,
"name": "Demo Store"
},
"owner": {
"id": 1,
"name": "Demo Store"
},
"yours": false,
"shared": false,
"turns": 0,
"waiting": 0,
"proposals": 0,
"last_text": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/",
"messages": [
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
]
}The assistant's home
GET/api/ai/assistant/home
What the assistant's home page shows: the AI agent (name, linked), three figures about the queue and the agent's drafts over the last 7 days, your recent chats and the routines with their next run.
Response
200 · The home page's data. · object
Request
curl "https://cs.growthdept.ai/api/ai/assistant/home" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"agent": {
"name": "Demo Store",
"linked": false
},
"you": {
"name": "Demo Store"
},
"figures": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"label": "Reason for contact",
"value": null,
"unit": ""
}
],
"recent": [
{
"id": 1,
"title": "",
"kind": "chat",
"routine": {
"id": 1,
"name": "Demo Store"
},
"owner": {
"id": 1,
"name": "Demo Store"
},
"yours": false,
"shared": false,
"turns": 0,
"waiting": 0,
"proposals": 0,
"last_text": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}
],
"routines": [
{
"id": 1,
"owner": {
"id": 1,
"name": "Demo Store"
},
"name": "Demo Store",
"instructions": "",
"frequency": "daily",
"hour": 0,
"minute": 0,
"weekday": null,
"monthday": null,
"timezone": "America/Los_Angeles",
"schedule": "",
"mode": "ask_first",
"template_key": null,
"paused": false,
"next_run_datetime": "2026-11-04T09:41:12+00:00",
"last_run_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}
]
}Routine templates
GET/api/ai/assistant/routine-templates
Starting points for routines teams often want: a weekly summary, a morning check for upset customers, topics without a skill, a macro and rule tidy-up, and a report on the AI agent's drafts.
Response
200 · The templates. · object
Request
curl \
"https://cs.growthdept.ai/api/ai/assistant/routine-templates" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"name": "Demo Store",
"instructions": "",
"frequency": "",
"hour": 0,
"weekday": 0
}
]
}List routines
GET/api/ai/assistant/routines
The helpdesk's routines (at most 10): questions the AI agent answers on a schedule, with when each runs next.
Response
200 · The routines. · object
Request
curl \
"https://cs.growthdept.ai/api/ai/assistant/routines" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"owner": {
"id": 1,
"name": "Demo Store"
},
"name": "Demo Store",
"instructions": "",
"frequency": "daily",
"hour": 0,
"minute": 0,
"weekday": null,
"monthday": null,
"timezone": "America/Los_Angeles",
"schedule": "",
"mode": "ask_first",
"template_key": null,
"paused": false,
"next_run_datetime": "2026-11-04T09:41:12+00:00",
"last_run_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}
]
}Create a routine
POST/api/ai/assistant/routines
A question the AI agent answers on a schedule: daily, on weekdays, weekly (weekday 1 Monday .. 7 Sunday) or monthly (monthday 1 to 28), at hour:minute in timezone (the helpdesk's by default). Each run starts a routine chat you can continue. Lead agents and admins; at most 10 per helpdesk.
Role: lead-agent or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| instructionsrequired | string | |
| frequency | daily, weekdays, weekly, monthly | |
| hour | integer | |
| minute | integer | |
| weekday | integer or null | |
| monthday | integer or null | |
| timezone | string | |
| mode | ask_first, auto | |
| template_ | string or null | |
| paused | boolean |
Response
201 · The routine. · AiRoutine
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/assistant/routines" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"instructions": ""
}'Response 201
{
"id": 1,
"owner": {
"id": 1,
"name": "Demo Store"
},
"name": "Demo Store",
"instructions": "",
"frequency": "daily",
"hour": 0,
"minute": 0,
"weekday": null,
"monthday": null,
"timezone": "America/Los_Angeles",
"schedule": "",
"mode": "ask_first",
"template_key": null,
"paused": false,
"next_run_datetime": "2026-11-04T09:41:12+00:00",
"last_run_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Get a chat
GET/api/ai/assistant/chats/{id}
A chat and all its turns, oldest first. Yours, or one a teammate shared.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The chat. · AiChatWithMessages
Request
curl \
"https://cs.growthdept.ai/api/ai/assistant/chats/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"title": "",
"kind": "chat",
"routine": {
"id": 1,
"name": "Demo Store"
},
"owner": {
"id": 1,
"name": "Demo Store"
},
"yours": false,
"shared": false,
"turns": 0,
"waiting": 0,
"proposals": 0,
"last_text": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/",
"messages": [
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
]
}Rename or share a chat
PUT/api/ai/assistant/chats/{id}
title renames it; shared true lets teammates in the helpdesk open it and add to it, false stops sharing. Only the person who started it.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| title | string | |
| shared | boolean |
Response
202 · The chat. · AiChatWithMessages
Request
curl -X PUT \
"https://cs.growthdept.ai/api/ai/assistant/chats/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "",
"shared": false
}'Response 202
{
"id": 1,
"title": "",
"kind": "chat",
"routine": {
"id": 1,
"name": "Demo Store"
},
"owner": {
"id": 1,
"name": "Demo Store"
},
"yours": false,
"shared": false,
"turns": 0,
"waiting": 0,
"proposals": 0,
"last_text": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/",
"messages": [
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
]
}Delete a chat
DELETE/api/ai/assistant/chats/{id}
Removes the chat from your history and withdraws any turn still waiting. Only the person who started it. Anything the AI agent already changed stays changed.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Deleted.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/ai/assistant/chats/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Get a routine
GET/api/ai/assistant/routines/{id}
One routine. Its runs are chats: GET /api/ai/assistant/chats?routine_id=.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The routine. · AiRoutine
Request
curl \
"https://cs.growthdept.ai/api/ai/assistant/routines/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"owner": {
"id": 1,
"name": "Demo Store"
},
"name": "Demo Store",
"instructions": "",
"frequency": "daily",
"hour": 0,
"minute": 0,
"weekday": null,
"monthday": null,
"timezone": "America/Los_Angeles",
"schedule": "",
"mode": "ask_first",
"template_key": null,
"paused": false,
"next_run_datetime": "2026-11-04T09:41:12+00:00",
"last_run_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Update, pause or resume a routine
PUT/api/ai/assistant/routines/{id}
Changes the fields you send; paused true stops its runs until paused false. The next run is worked out again.
Role: lead-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| instructions | string | |
| frequency | daily, weekdays, weekly, monthly | |
| hour | integer | |
| minute | integer | |
| weekday | integer or null | |
| monthday | integer or null | |
| timezone | string | |
| mode | ask_first, auto | |
| paused | boolean |
Response
202 · The routine. · AiRoutine
Request
curl -X PUT \
"https://cs.growthdept.ai/api/ai/assistant/routines/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"instructions": "",
"frequency": "daily"
}'Response 202
{
"id": 1,
"owner": {
"id": 1,
"name": "Demo Store"
},
"name": "Demo Store",
"instructions": "",
"frequency": "daily",
"hour": 0,
"minute": 0,
"weekday": null,
"monthday": null,
"timezone": "America/Los_Angeles",
"schedule": "",
"mode": "ask_first",
"template_key": null,
"paused": false,
"next_run_datetime": "2026-11-04T09:41:12+00:00",
"last_run_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Delete a routine
DELETE/api/ai/assistant/routines/{id}
Stops it for good. Its past runs stay in the chat history.
Role: lead-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Deleted.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/ai/assistant/routines/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Approve or reject a proposal
POST/api/ai/agent/questions/{id}/decision
For a turn the AI agent answered with a proposal: approved adds a turn telling it to make exactly that change (in auto mode); rejected adds one telling it not to, with your reason, so it can suggest something else. Anyone who can see the chat. The agent still works within its own rules and the helpdesk's settings.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| decisionrequired | approved, rejected | |
| reason | string or null |
Response
201 · The chat with the decision and the new turn. · AiChatWithMessages
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/agent/questions/1/decision" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"decision": "approved"
}'Response 201
{
"id": 1,
"title": "",
"kind": "chat",
"routine": {
"id": 1,
"name": "Demo Store"
},
"owner": {
"id": 1,
"name": "Demo Store"
},
"yours": false,
"shared": false,
"turns": 0,
"waiting": 0,
"proposals": 0,
"last_text": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/",
"messages": [
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
]
}Add to a chat
POST/api/ai/assistant/chats/{id}/messages
A follow-up question or request in the chat; the AI agent sees the turns before it. mode as for starting a chat.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| textrequired | string | |
| mode | ask_first, auto | |
| page | string or null | |
| ticket_ | integer or null |
Response
201 · The chat with the new turn. · AiChatWithMessages
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/assistant/chats/1/messages" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": ""
}'Response 201
{
"id": 1,
"title": "",
"kind": "chat",
"routine": {
"id": 1,
"name": "Demo Store"
},
"owner": {
"id": 1,
"name": "Demo Store"
},
"yours": false,
"shared": false,
"turns": 0,
"waiting": 0,
"proposals": 0,
"last_text": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/",
"messages": [
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
]
}Run a routine now
POST/api/ai/assistant/routines/{id}/run
Starts a run at once, without changing the schedule. Refused while an earlier run is still waiting for an answer.
Role: lead-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
201 · The new run's chat. · AiChatWithMessages
Request
curl -X POST \
"https://cs.growthdept.ai/api/ai/assistant/routines/1/run" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 201
{
"id": 1,
"title": "",
"kind": "chat",
"routine": {
"id": 1,
"name": "Demo Store"
},
"owner": {
"id": 1,
"name": "Demo Store"
},
"yours": false,
"shared": false,
"turns": 0,
"waiting": 0,
"proposals": 0,
"last_text": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/",
"messages": [
{
"id": 1,
"chat_id": null,
"mode": "ask_first",
"kind": "question",
"proposal": false,
"decision": "approved",
"decided_datetime": "2026-11-04T09:41:12+00:00",
"asked_by": {
"id": 1,
"name": "Demo Store"
},
"text": "",
"page": null,
"ticket_id": 4182,
"status": "pending",
"answer": null,
"failure": null,
"answered_by_agent_id": null,
"claimed_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
]
}Automation
What runs without a person, in one place: whether the AI agent, flows, order management, article suggestions, rules, auto-assignment, auto-merge, SLAs and the satisfaction survey are on, and the automation on each mailbox, chat, contact form and help center. Admins switch the AI agent on or off per channel and order management and article suggestions per chat.
Automation by channel
GET/api/automation/channels
Each mailbox, chat, contact form and help center with the automation that runs on it: whether the AI agent works on that channel, and for chats the flows offered, order management and article suggestions.
Response
200 · The channels. · object
Request
curl "https://cs.growthdept.ai/api/automation/channels" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"agent": {
"name": "Demo Store",
"channels": {}
},
"channels": [
{
"kind": "email",
"id": 1,
"name": "Demo Store",
"agent_channel": "",
"agent_on": false,
"flows": null,
"orders": false,
"suggestions": false,
"path": ""
}
]
}Switch automation by channel
PUT/api/automation/channels
agent switches the AI agent on or off per channel group (email, chat, contact_form, sms, phone, other): with a group off, its drafts and custom action runs on those tickets are refused. chats switches order management (orders) and article suggestions (suggestions) for each chat by id; the chat's other settings stay as they are. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| agent | object | |
| chats | array of object |
Response
202 · The channels. · object
Request
curl -X PUT "https://cs.growthdept.ai/api/automation/channels" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent": {},
"chats": [
{
"id": 1,
"orders": false,
"suggestions": false
}
]
}'Response 202
{
"agent": {
"name": "Demo Store",
"channels": {}
},
"channels": [
{
"kind": "email",
"id": 1,
"name": "Demo Store",
"agent_channel": "",
"agent_on": false,
"flows": null,
"orders": false,
"suggestions": false,
"path": ""
}
]
}What is automated
GET/api/automation/overview
Every automation in the helpdesk with whether it is on and a line on its state: the AI agent, flows, order management, article suggestions, rules, auto-assignment, auto-merge, SLAs and the satisfaction survey. path is the page that sets each up.
Response
200 · The automations. · object
Request
curl "https://cs.growthdept.ai/api/automation/overview" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"agent": {
"name": "Demo Store",
"linked": false
},
"features": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"name": "Demo Store",
"on": false,
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"path": ""
}
],
"counts": {
"on": 0,
"total": 0
}
}Business hours
Custom business hours give a mailbox, chat widget or contact form its own schedule instead of the default hours, and holiday hours close or shorten given dates, once or every year, for every channel or the ones assigned. Chat visibility, SLA deadlines and the reports' business-hours option use the hours that apply to each channel.
List custom business hours
GET/api/business-hours
Every custom schedule, oldest first, with integration_count and first_integration.
Parameters
| Name | Description |
|---|---|
| namequery · string | Only schedules whose name contains this text. |
| limitquery · integer |
Response
200 · The schedules. · list of object
Request
curl \
"https://cs.growthdept.ai/api/business-hours?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/business-hours",
"data": [
{}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Create custom business hours
POST/api/business-hours
A title, a time zone, one or more ranges, and the integrations it covers (assigned_integrations.assign_integrations: integration ids, or {integration_id, integration_type} for a chat widget or contact form). An integration moved here leaves its previous schedule. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| business_ | object | |
| assigned_ | object |
Response
201 · The new schedule. · object
Request
curl -X POST "https://cs.growthdept.ai/api/business-hours" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"business_hours_config": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "",
"from_time": "",
"to_time": ""
}
]
}
}'Response 201
{}List holiday hours
GET/api/holiday-hours
Every holiday, by first date.
Response
200 · The holidays. · list of object
Request
curl \
"https://cs.growthdept.ai/api/holiday-hours?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/holiday-hours",
"data": [
{}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Create holiday hours
POST/api/holiday-hours
A title, a first and last date, closed (holiday_hours_config null) or open with other ranges, repeats_yearly, and the integrations it covers (none: every channel). An integration can't be in two holidays on overlapping dates. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| start_ | string | |
| end_ | string | |
| holiday_ | object or null | |
| repeats_ | boolean | |
| assigned_ | array of integer or object |
Response
201 · The new holiday. · object
Request
curl -X POST "https://cs.growthdept.ai/api/holiday-hours" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"start_date": "",
"end_date": ""
}'Response 201
{}Get custom business hours
GET/api/business-hours/{id}
One schedule with the integrations it covers.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The schedule's id. |
Response
200 · The schedule. · object
Request
curl "https://cs.growthdept.ai/api/business-hours/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Update custom business hours
PUT/api/business-hours/{id}
Changes the title, time zone or ranges, and assigns or unassigns integrations (assigned_integrations.assign_integrations and unassign_integrations). Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The schedule's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| business_ | object | |
| assigned_ | object |
Response
202 · The schedule after the change. · object
Request
curl -X PUT "https://cs.growthdept.ai/api/business-hours/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"business_hours_config": {
"timezone": "America/Los_Angeles",
"business_hours": [
{
"days": "",
"from_time": "",
"to_time": ""
}
]
},
"assigned_integrations": {
"assign_integrations": [
0
],
"unassign_integrations": [
0
]
}
}'Response 202
{}Delete custom business hours
DELETE/api/business-hours/{id}
Its integrations go back to the default hours. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The schedule's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/business-hours/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)List integrations and their hours
GET/api/business-hours/integrations
Mailboxes, chat widgets and contact forms, newest first, each with integration_id, integration_type, integration_name, integration_address, store and business_hours ({id, name} or null).
Parameters
| Name | Description |
|---|---|
| limitquery · integer |
Response
200 · The integrations. · list of object
Request
curl \
"https://cs.growthdept.ai/api/business-hours/integrations?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/business-hours/integrations",
"data": [
{}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Get holiday hours
GET/api/holiday-hours/{id}
One holiday with the integrations it covers.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The holiday's id. |
Response
200 · The holiday. · object
Request
curl "https://cs.growthdept.ai/api/holiday-hours/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Update holiday hours
PUT/api/holiday-hours/{id}
Changes any field; assigned_integrations replaces the list. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The holiday's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| start_ | string | |
| end_ | string | |
| holiday_ | object or null | |
| repeats_ | boolean | |
| assigned_ | array of integer or object |
Response
202 · The holiday after the change. · object
Request
curl -X PUT "https://cs.growthdept.ai/api/holiday-hours/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"start_date": "",
"end_date": ""
}'Response 202
{}Delete holiday hours
DELETE/api/holiday-hours/{id}
Its dates follow the usual hours again. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The holiday's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/holiday-hours/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)List integrations for holidays
GET/api/holiday-hours/integrations
The same list as /api/business-hours/integrations.
Response
200 · The integrations. · list of object
Request
curl \
"https://cs.growthdept.ai/api/holiday-hours/integrations?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/holiday-hours/integrations",
"data": [
{}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}List a schedule's integrations
GET/api/business-hours/{id}/integrations
The integrations, chat widgets and contact forms this schedule covers.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The schedule's id. |
Response
200 · The integrations. · list of object
Request
curl \
"https://cs.growthdept.ai/api/business-hours/1/integrations?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/business-hours/1/integrations",
"data": [
{}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Find overlapping holidays
POST/api/holiday-hours/overlaps/search
For a first and last date, a yearly flag and integrations: the holidays that already cover one of them on an overlapping date.
Body
| Field | Type | Description |
|---|---|---|
| start_ | string | |
| end_ | string | |
| repeats_ | boolean | |
| holiday_ | any | |
| integration_ | array of integer or object | |
| holiday_ | integer or null |
Response
200 · {overlaps: [{holiday_hours_id, name, integration_id, integration_type}]} · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/holiday-hours/overlaps/search" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"start_date": "",
"end_date": ""
}'Response 200
{}Calls and texts billing
How the helpdesk pays for calls and texts: Telnyx's cost of each text and call leg, passed through and invoiced monthly in USD. Phone numbers and carrier registration are Growth Dept's cost and never billed. Read the mode, the card and this month's usage, choose a card Growth Dept already holds or add one through Stripe Checkout, or pay by emailed invoice.
The TelephonyBilling object · 16 fields
| Field | Type | Description |
|---|---|---|
| mode | off, growth_dept, standalone | off: not billed. growth_dept: Telnyx's cost passed through to the Growth Dept billing account. standalone: cost plus a markup. |
| telephony_ | boolean | Whether Growth Dept switched voice and SMS on for this helpdesk. |
| open | boolean | Whether invoices can be made now. |
| closed_ | mode_off, no_key, bad_key, live_gate, no_customer, other_mode, null or null | |
| closed_ | string or null | |
| stripe_ | test, live, null or null | |
| markup_ | number | |
| customer_ | boolean | |
| card | object or null | The card that pays calls and texts: its brand, last four digits and expiry, never the number. |
| pay_ | card, invoice | card: the monthly invoice charges the card. invoice: Stripe emails the invoice to pay within 14 days. |
| wording | object | |
| gd_ | object | The tick that lets the same card pay the brand's Growth Dept bill. |
| usage | object | This month so far, in the helpdesk's time zone. |
| invoices | array of TelephonyBillingInvoice | |
| covered_ | array of string | |
| can_ | boolean |
The TelephonyBillingCardOption object · 10 fields
| Field | Type | Description |
|---|---|---|
| payment_ | string | |
| brand | string | |
| last4 | string | |
| exp_ | integer | |
| exp_ | integer | |
| funding | string or null | |
| label | string | |
| gd_ | boolean | The card Growth Dept's invoices are charged to now. |
| in_ | boolean | The card that pays calls and texts. |
| wording | string | The authorization for choosing this card; send it back as wording_seen. |
How calls and texts are billed
GET/api/telephony/billing
The billing mode, whether invoices can be made and why not, the card that pays (brand, last four and expiry only), paying by card or emailed invoice, the Growth Dept bill tick and its wording, this month's usage by kind at Telnyx's cost, and the last 12 invoices. Phone numbers and carrier registration are covered by Growth Dept and never billed.
Response
200 · The billing view. · TelephonyBilling
Request
curl "https://cs.growthdept.ai/api/telephony/billing" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"mode": "off",
"telephony_enabled": false,
"open": false,
"closed_reason": "mode_off",
"closed_text": null,
"stripe_mode": "test",
"markup_pct": 0,
"customer_linked": false,
"card": {
"brand": "",
"last4": "",
"exp_month": 0,
"exp_year": 0,
"funding": null,
"label": "Reason for contact",
"source": "growth_dept_file",
"chosen_at": null
},
"pay_by": "card",
"wording": {
"add_card": "",
"card": null
},
"gd_bill": {
"available": false,
"label": "Reason for contact",
"checked": false,
"wording": null,
"consent": {
"at": "",
"by": null
},
"sets_default": false,
"can_change": false,
"why_not": null
},
"usage": {
"period_start": "",
"timezone": "America/Los_Angeles",
"lines": [
{
"kind": "",
"label": "Reason for contact",
"count": 0,
"quantity": 0,
"amount": 0,
"unit": "",
"cost_usd": "",
"unpriced": 0
}
],
"cost_usd": "",
"billed_usd": "",
"unpriced": 0,
"earlier_uninvoiced_usd": ""
},
"invoices": [
{
"id": 1,
"period_start": "",
"period_end": "",
"status": "open",
"amount_usd": "",
"livemode": false,
"collection_method": "charge_automatically",
"due_date": null,
"hosted_url": null,
"lines": [
{
"kind": "",
"description": "",
"amount_usd": ""
}
],
"created_datetime": ""
}
],
"covered_by_growth_dept": [
""
],
"can_manage": false
}Change how calls and texts are paid
PUT/api/telephony/billing
pay_by card or invoice. card_for_gd_bill true, with wording_seen equal to gd_bill.wording, lets the same card pay the organization's Growth Dept bill (organization owners only); false withdraws it. A person signed in to the helpdesk makes these changes, not an API key.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| pay_ | card, invoice | |
| card_ | boolean | |
| wording_ | string | The exact wording shown for the tick, from gd_bill.wording. |
Response
200 · The billing view, with a message about what changed. · TelephonyBilling
Request
curl -X PUT "https://cs.growthdept.ai/api/telephony/billing" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"pay_by": "card",
"card_for_gd_bill": false,
"wording_seen": ""
}'Response 200
{
"mode": "off",
"telephony_enabled": false,
"open": false,
"closed_reason": "mode_off",
"closed_text": null,
"stripe_mode": "test",
"markup_pct": 0,
"customer_linked": false,
"card": {
"brand": "",
"last4": "",
"exp_month": 0,
"exp_year": 0,
"funding": null,
"label": "Reason for contact",
"source": "growth_dept_file",
"chosen_at": null
},
"pay_by": "card",
"wording": {
"add_card": "",
"card": null
},
"gd_bill": {
"available": false,
"label": "Reason for contact",
"checked": false,
"wording": null,
"consent": {
"at": "",
"by": null
},
"sets_default": false,
"can_change": false,
"why_not": null
},
"usage": {
"period_start": "",
"timezone": "America/Los_Angeles",
"lines": [
{
"kind": "",
"label": "Reason for contact",
"count": 0,
"quantity": 0,
"amount": 0,
"unit": "",
"cost_usd": "",
"unpriced": 0
}
],
"cost_usd": "",
"billed_usd": "",
"unpriced": 0,
"earlier_uninvoiced_usd": ""
},
"invoices": [
{
"id": 1,
"period_start": "",
"period_end": "",
"status": "open",
"amount_usd": "",
"livemode": false,
"collection_method": "charge_automatically",
"due_date": null,
"hosted_url": null,
"lines": [
{
"kind": "",
"description": "",
"amount_usd": ""
}
],
"created_datetime": ""
}
],
"covered_by_growth_dept": [
""
],
"can_manage": false
}Pay with a card on file
POST/api/telephony/billing/card
Chooses one of the cards from GET /api/telephony/billing/cards to pay each month's calls and texts. wording_seen must be that card's wording; the person, time, address and browser are recorded with it.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| payment_ | string | |
| wording_ | string | The exact wording shown for the card, from GET /api/telephony/billing/cards. |
Response
200 · The billing view. · TelephonyBilling
Request
curl -X POST \
"https://cs.growthdept.ai/api/telephony/billing/card" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"payment_method_id": "",
"wording_seen": ""
}'Response 200
{
"mode": "off",
"telephony_enabled": false,
"open": false,
"closed_reason": "mode_off",
"closed_text": null,
"stripe_mode": "test",
"markup_pct": 0,
"customer_linked": false,
"card": {
"brand": "",
"last4": "",
"exp_month": 0,
"exp_year": 0,
"funding": null,
"label": "Reason for contact",
"source": "growth_dept_file",
"chosen_at": null
},
"pay_by": "card",
"wording": {
"add_card": "",
"card": null
},
"gd_bill": {
"available": false,
"label": "Reason for contact",
"checked": false,
"wording": null,
"consent": {
"at": "",
"by": null
},
"sets_default": false,
"can_change": false,
"why_not": null
},
"usage": {
"period_start": "",
"timezone": "America/Los_Angeles",
"lines": [
{
"kind": "",
"label": "Reason for contact",
"count": 0,
"quantity": 0,
"amount": 0,
"unit": "",
"cost_usd": "",
"unpriced": 0
}
],
"cost_usd": "",
"billed_usd": "",
"unpriced": 0,
"earlier_uninvoiced_usd": ""
},
"invoices": [
{
"id": 1,
"period_start": "",
"period_end": "",
"status": "open",
"amount_usd": "",
"livemode": false,
"collection_method": "charge_automatically",
"due_date": null,
"hosted_url": null,
"lines": [
{
"kind": "",
"description": "",
"amount_usd": ""
}
],
"created_datetime": ""
}
],
"covered_by_growth_dept": [
""
],
"can_manage": false
}Cards Growth Dept has on file
GET/api/telephony/billing/cards
The cards on the helpdesk's Growth Dept billing account, the one Growth Dept's invoices use first, each with the authorization text to confirm when choosing it. Brand, last four and expiry only.
Role: admin or higher
Response
200 · The cards. · list of TelephonyBillingCardOption
Request
curl \
"https://cs.growthdept.ai/api/telephony/billing/cards?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/telephony/billing/cards",
"data": [
{
"payment_method_id": "",
"brand": "",
"last4": "",
"exp_month": 0,
"exp_year": 0,
"funding": null,
"label": "Reason for contact",
"gd_bill_default": false,
"in_use": false,
"wording": ""
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Add a card with Stripe
POST/api/telephony/billing/checkout
Starts a Stripe Checkout page that saves a card to the helpdesk's billing account. Open the returned url in the browser; Stripe sends the person back to the Billing page when the card is saved.
Role: admin or higher
Response
200 · The Checkout page. · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/telephony/billing/checkout" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"id": ""
}Return from Stripe's card page
GET/api/telephony/billing/checkout/return
Where Stripe Checkout sends the browser after saving a card (query: helpdesk, session_id). It needs the helpdesk admin's session, reads the Checkout session from Stripe, saves the card and redirects to the Billing page.
Response
303 · A redirect to the Billing page with the result.
Request
curl \
"https://cs.growthdept.ai/api/telephony/billing/checkout/return"Response 303
(no body)Chat
Chat windows the helpdesk puts on its own sites. Each conversation is a ticket on the chat channel; the ticket's messages are the conversation. Admins create and change widgets; the app follows a chat ticket and shows typing with the ticket routes here. The visitor routes under /api/chat/{helpdesk}/{public_id} are what the chat window itself calls, with a page token to start and a visitor token after that. They also run the window's automation: flows, order lookup behind an emailed code, and suggested articles for the first message.
The ChatPresence object · 8 fields
| Field | Type | Description |
|---|---|---|
| widgets | integer | Chat widgets in the helpdesk. |
| online_ | integer | Agents online for chat now. |
| me_ | boolean | Whether you count as online: status available and a role that answers chats. |
| availability | available, busy, offline | Your status. |
| availability_ | string or null | Your away reason or status name, while away. |
| status_ | integer or null | The status you picked, if any. |
| availability_ | datetime or null | When your status ends, for a status with a duration. |
| auto_ | boolean | Auto-assignment is on: keep calling every minute, even from a hidden tab, to stay eligible. |
The ChatWidget object · 19 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| public_ | string | The random id in the widget's public addresses. |
| name | string | The widget's name, shown to agents. |
| default_ | en, fr, de, es | The language visitors get when the widget does not offer theirs. |
| languages | array of en, fr, de, es | The languages the window offers, the default first. |
| integration_ | integer or null | The mailbox for offline messages and replies to customers who left. |
| mailbox | object or null | |
| help_ | integer or null | The help center the window links to. |
| help_ | object or null | |
| allowed_ | array of string | Sites the widget may run on. Empty: any site. |
| settings | object | |
| script_ | string | The script a site adds to show the launcher. |
| chat_ | string | The chat page the script frames; it also works on its own. |
| snippet | string | The script tag to paste before </body>. |
| status | object | Whether the chat is live now and why not. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| deleted_ | datetime or null |
The ArticleSuggestionTest object · 4 fields
| Field | Type | Description |
|---|---|---|
| help_ | integer or null | The help center searched; null when the chat has none. |
| language | string or null | The language searched. |
| threshold | number | The lowest score the chat's strength suggests. |
| articles | array of object |
The ChatTicketLive object · 2 fields
| Field | Type | Description |
|---|---|---|
| chat | object or null | The ticket's chat conversation; null for a ticket that did not come from chat. |
| messages | array of Message | Messages after the one given, notes included. |
The ChatVisitorState object · 5 fields
| Field | Type | Description |
|---|---|---|
| status | live, offline | |
| conversation | object | |
| messages | array of object | |
| agent_ | string or null | The name of the agent typing, or null. |
| suggestion | object or null | Help center articles suggested for the first message and waiting for an answer: on the start, and on a poll from the beginning (after=0). |
The ChatVisitorStarted object · 6 fields
| Field | Type | Description |
|---|---|---|
| status | live, offline | |
| conversation | object | |
| messages | array of object | |
| agent_ | string or null | The name of the agent typing, or null. |
| suggestion | object or null | Help center articles suggested for the first message and waiting for an answer: on the start, and on a poll from the beginning (after=0). |
| token | string | The visitor token: send it as Authorization: Bearer on later calls. |
The ChatOrders object · 2 fields
| Field | Type | Description |
|---|---|---|
| string | The verified address. | |
| orders | array of object |
The ChatStatus object · 1 fields
| Field | Type | Description |
|---|---|---|
| status | live, offline |
The ChatVisitorMessage object · 1 fields
| Field | Type | Description |
|---|---|---|
| message | object |
The ChatFlowView object · 5 fields
What the chat window shows after starting a flow or answering a step.
| Field | Type | Description |
|---|---|---|
| flow | object | |
| run | object | |
| answer | string or null | What the visitor answered, to show as their message. |
| messages | array of object | |
| next | object | What waits for the visitor: choices (options), question (answer text or email), end (did this help?), handover (show the chat form, with prefill), or resolved. |
The ChatOrderCode object · 2 fields
| Field | Type | Description |
|---|---|---|
| verification | string | Send it back with the code. |
| expires_ | integer | Seconds the code works. |
The ChatOrderSession object · 2 fields
| Field | Type | Description |
|---|---|---|
| token | string | The order session: send it as Authorization: Bearer. |
| expires_ | integer | Seconds it lasts. |
The ChatSuggestionAnswer object · 2 fields
| Field | Type | Description |
|---|---|---|
| outcome | resolved, escalated | |
| closed | boolean | The conversation was closed. |
Report that you have the helpdesk open
POST/api/chat-presence
Marks you as present for chat and for auto-assignment for the next few minutes. The app calls it every minute while a tab is visible, and while it is hidden when auto-assignment is on. A Growth Dept admin viewing the helpdesk is not recorded. Answers how many agents are online and whether you are one of them. Coming back online starts an auto-assignment run for your teams.
Role: lite-agent or higher
Response
200 · Presence after the call. · ChatPresence
Request
curl -X POST "https://cs.growthdept.ai/api/chat-presence" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"widgets": 0,
"online_agents": 0,
"me_online": false,
"availability": "available",
"availability_reason": null,
"status_id": null,
"availability_until": "2026-11-04T09:41:12+00:00",
"auto_assign": false
}List chat widgets
GET/api/chat-widgets
The helpdesk's chat widgets, newest first, each with whether it is live now, its mailbox and the script to install it. Deleted widgets are left out.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc, name:asc, name:desc |
Response
200 · A page of chat widgets. · list of ChatWidget
Request
curl \
"https://cs.growthdept.ai/api/chat-widgets?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/chat-widgets?limit=2",
"data": [
{
"id": 1,
"uri": "/api/",
"public_id": "",
"name": "Demo Store",
"default_language": "en",
"languages": [
"en"
],
"integration_id": 2,
"mailbox": {
"id": 1,
"type": "gmail",
"address": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"help_center_id": null,
"help_center": {
"id": 1,
"name": "Demo Store",
"live": false
},
"allowed_origins": [
""
],
"settings": {
"enabled": false,
"accent": "",
"logo_url": null,
"position": "right",
"offset_x": 0,
"offset_y": 0,
"launcher": "icon",
"agent_names": "first",
"availability": "agents",
"show_outside_hours": false,
"show_on_mobile": false,
"email": "optional",
"name": "off",
"texts": {},
"flows": {
"ids": [
0
],
"mode": "before"
},
"orders": false,
"suggest": {
"enabled": false,
"help_center_id": null,
"strength": "broad",
"exclude": [
0
]
}
},
"script_url": "",
"chat_url": "",
"snippet": "",
"status": {
"live": false,
"visible": false,
"reason": "disabled",
"open": false,
"online_agents": 0
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a chat widget
POST/api/chat-widgets
Creates a chat widget with a new random public address, switched on and live while an agent is available during business hours. name is required. integration_id names the Gmail or forwarding mailbox for offline messages and replies to customers who left.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| name | string | The widget's name, shown to agents. |
| default_ | en, fr, de, es | The language visitors get when the widget does not offer theirs. |
| languages | array of en, fr, de, es | The languages the window offers; it follows the visitor's browser among them. |
| integration_ | integer or string | The mailbox for offline messages and replies to customers who left: a Gmail or forwarding mailbox in this helpdesk. null for none. |
| help_ | integer or string | A help center whose newest articles the window links to while it is live. null for none. |
| allowed_ | array of string | Sites the widget may run on, such as https://shop.example.com. Empty: any site. |
| settings | object | Look, availability and texts. Fields sent replace the stored ones; others stay. |
Response
201 · The new widget. · ChatWidget
Request
curl -X POST "https://cs.growthdept.ai/api/chat-widgets" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"default_language": "en",
"languages": [
"en"
]
}'Response 201
{
"id": 1,
"uri": "/api/",
"public_id": "",
"name": "Demo Store",
"default_language": "en",
"languages": [
"en"
],
"integration_id": 2,
"mailbox": {
"id": 1,
"type": "gmail",
"address": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"help_center_id": null,
"help_center": {
"id": 1,
"name": "Demo Store",
"live": false
},
"allowed_origins": [
""
],
"settings": {
"enabled": false,
"accent": "",
"logo_url": null,
"position": "right",
"offset_x": 0,
"offset_y": 0,
"launcher": "icon",
"agent_names": "first",
"availability": "agents",
"show_outside_hours": false,
"show_on_mobile": false,
"email": "optional",
"name": "off",
"texts": {},
"flows": {
"ids": [
0
],
"mode": "before"
},
"orders": false,
"suggest": {
"enabled": false,
"help_center_id": null,
"strength": "broad",
"exclude": [
0
]
}
},
"script_url": "",
"chat_url": "",
"snippet": "",
"status": {
"live": false,
"visible": false,
"reason": "disabled",
"open": false,
"online_agents": 0
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null
}Get a chat widget
GET/api/chat-widgets/{id}
One chat widget with its settings, whether it is live now, and its install script.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The chat widget's id. |
Response
200 · The widget. · ChatWidget
Request
curl "https://cs.growthdept.ai/api/chat-widgets/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"uri": "/api/",
"public_id": "",
"name": "Demo Store",
"default_language": "en",
"languages": [
"en"
],
"integration_id": 2,
"mailbox": {
"id": 1,
"type": "gmail",
"address": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"help_center_id": null,
"help_center": {
"id": 1,
"name": "Demo Store",
"live": false
},
"allowed_origins": [
""
],
"settings": {
"enabled": false,
"accent": "",
"logo_url": null,
"position": "right",
"offset_x": 0,
"offset_y": 0,
"launcher": "icon",
"agent_names": "first",
"availability": "agents",
"show_outside_hours": false,
"show_on_mobile": false,
"email": "optional",
"name": "off",
"texts": {},
"flows": {
"ids": [
0
],
"mode": "before"
},
"orders": false,
"suggest": {
"enabled": false,
"help_center_id": null,
"strength": "broad",
"exclude": [
0
]
}
},
"script_url": "",
"chat_url": "",
"snippet": "",
"status": {
"live": false,
"visible": false,
"reason": "disabled",
"open": false,
"online_agents": 0
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null
}Change a chat widget
PUT/api/chat-widgets/{id}
Changes the fields sent. Fields inside settings replace the stored ones and the rest stay; texts merge per language and field. allowed_origins replaces the whole list.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The chat widget's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | The widget's name, shown to agents. |
| default_ | en, fr, de, es | The language visitors get when the widget does not offer theirs. |
| languages | array of en, fr, de, es | The languages the window offers; it follows the visitor's browser among them. |
| integration_ | integer or string | The mailbox for offline messages and replies to customers who left: a Gmail or forwarding mailbox in this helpdesk. null for none. |
| help_ | integer or string | A help center whose newest articles the window links to while it is live. null for none. |
| allowed_ | array of string | Sites the widget may run on, such as https://shop.example.com. Empty: any site. |
| settings | object | Look, availability and texts. Fields sent replace the stored ones; others stay. |
Response
202 · The widget after the change. · ChatWidget
Request
curl -X PUT "https://cs.growthdept.ai/api/chat-widgets/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"default_language": "en",
"languages": [
"en"
]
}'Response 202
{
"id": 1,
"uri": "/api/",
"public_id": "",
"name": "Demo Store",
"default_language": "en",
"languages": [
"en"
],
"integration_id": 2,
"mailbox": {
"id": 1,
"type": "gmail",
"address": "maya.okafor@example.com",
"name": "Demo Store",
"active": true
},
"help_center_id": null,
"help_center": {
"id": 1,
"name": "Demo Store",
"live": false
},
"allowed_origins": [
""
],
"settings": {
"enabled": false,
"accent": "",
"logo_url": null,
"position": "right",
"offset_x": 0,
"offset_y": 0,
"launcher": "icon",
"agent_names": "first",
"availability": "agents",
"show_outside_hours": false,
"show_on_mobile": false,
"email": "optional",
"name": "off",
"texts": {},
"flows": {
"ids": [
0
],
"mode": "before"
},
"orders": false,
"suggest": {
"enabled": false,
"help_center_id": null,
"strength": "broad",
"exclude": [
0
]
}
},
"script_url": "",
"chat_url": "",
"snippet": "",
"status": {
"live": false,
"visible": false,
"reason": "disabled",
"open": false,
"online_agents": 0
},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"deleted_datetime": null
}Delete a chat widget
DELETE/api/chat-widgets/{id}
Takes the chat off every site: its script draws nothing and its page says the chat is no longer in use. Tickets it opened stay.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The chat widget's id. |
Response
204 · The widget was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/chat-widgets/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Try article suggestions
POST/api/chat-widgets/{id}/article-suggestions
The published help center articles a first message would match in this chat, best first, with their scores and which would be suggested. Saved settings are used unless the body gives others, so unsaved changes can be tried. Nothing is stored.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The chat widget's id. |
Body
| Field | Type | Description |
|---|---|---|
| messagerequired | string | A first message as a visitor might write it. |
| language | en, fr, de, es | The visitor's language; the chat's default when left out. |
| help_ | integer or string | Try another help center than the saved one; null tries the chat's own help center. |
| strength | broad, balanced, strict | Try another strength than the saved one. |
| exclude | array of integer or string | Try another list of excluded articles. |
Response
200 · The matches. · ArticleSuggestionTest
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat-widgets/1/article-suggestions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": ""
}'Response 200
{
"help_center_id": null,
"language": "en",
"threshold": 0,
"articles": [
{
"id": 1,
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week.",
"score": 5,
"suggested": false
}
]
}Follow a chat ticket
GET/api/tickets/{id}/chat
The ticket's messages after the message id in after (notes included), and its chat conversation: whether the visitor is still on the site and typing, and whether a reply sent now would also go out by email. chat is null for tickets that did not come from chat.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The ticket's id. |
| afterquery · string | Only messages with a larger id. 0 for all. |
Response
200 · News on the ticket. · ChatTicketLive
Request
curl "https://cs.growthdept.ai/api/tickets/4182/chat" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"chat": {
"conversation_id": 0,
"kind": "live",
"widget": {
"id": 1,
"name": "Demo Store",
"deleted": false
},
"page_url": null,
"visitor": {
"present": false,
"seen_datetime": "2026-11-04T09:41:12+00:00",
"typing": false
},
"has_email": false,
"reply_by_email": false,
"away_after_seconds": 0
},
"messages": [
{
"id": 90311,
"uri": "/api/",
"ticket_id": 4182,
"message_id": "<CAB7xk2Q9m@mail.gmail.com>",
"external_id": null,
"public": true,
"channel": "email",
"via": "email",
"source": {
"type": "email",
"from": {},
"to": [],
"cc": [],
"bcc": []
},
"sender": {
"id": 7311,
"email": "maya.okafor@example.com",
"name": "Maya Okafor",
"firstname": "Maya",
"lastname": "Okafor",
"meta": {}
},
"receiver": {
"id": 12
},
"integration_id": 2,
"rule_id": null,
"from_agent": false,
"subject": "Where is order #1042?",
"body_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"body_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_text": "Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?",
"stripped_html": "<p>Hi, order #1042 said 3 to 5 days and it has been a week. Tracking has not moved since Monday. Can you check where it is?</p>",
"stripped_signature": null,
"attachments": [
{
"id": 1
}
],
"actions": [],
"macros": [],
"intents": [],
"headers": {},
"meta": {},
"imported": false,
"is_retriable": false,
"last_sending_error": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"processed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"failed_datetime": null,
"opened_datetime": null,
"deleted_datetime": null
}
]
}Follow a chat conversation
GET/api/chat/{helpdesk}/{public_id}/conversation
Messages after the id in after, whether the chat is live, and whether an agent is typing. Needs the visitor token as Authorization: Bearer. typing=1 tells agents the visitor is typing. Each call also tells the helpdesk the visitor is still on the site.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
200 · News on the conversation. · ChatVisitorState
Request
curl \
"https://cs.growthdept.ai/api/chat/1/1/conversation"Response 200
{
"status": "live",
"conversation": {
"id": 1,
"kind": "live",
"has_email": false,
"closed": false
},
"messages": [
{
"id": 1,
"from": "customer",
"author": null,
"text": "",
"created_datetime": "",
"emailed": false,
"attachments": [
{
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
],
"agent_typing": null,
"suggestion": {
"id": 1,
"articles": [
{
"id": 1,
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week."
}
]
}
}Start a chat conversation
POST/api/chat/{helpdesk}/{public_id}/conversations
What the chat page posts when a visitor starts a conversation: JSON with message, and name, email, language and page_url as the widget asks. Needs the page token in the X-Chat-Page header. Opens a ticket on the chat channel and answers the visitor token for the later calls. 409 with code offline when nobody can answer live any more.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
201 · The conversation and its visitor token. · ChatVisitorStarted
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/conversations"Response 201
{
"status": "live",
"conversation": {
"id": 1,
"kind": "live",
"has_email": false,
"closed": false
},
"messages": [
{
"id": 1,
"from": "customer",
"author": null,
"text": "",
"created_datetime": "",
"emailed": false,
"attachments": [
{
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
],
"agent_typing": null,
"suggestion": {
"id": 1,
"articles": [
{
"id": 1,
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week."
}
]
},
"token": ""
}Leave an offline chat message
POST/api/chat/{helpdesk}/{public_id}/offline
What the chat page's offline form posts: JSON with email and message (both required), name as the widget asks, language and page_url. Needs the page token in the X-Chat-Page header. Opens a ticket on the chat channel whose replies go out by email from the widget's mailbox.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
201 · The conversation and its visitor token. · ChatVisitorStarted
Request
curl -X POST "https://cs.growthdept.ai/api/chat/1/1/offline"Response 201
{
"status": "live",
"conversation": {
"id": 1,
"kind": "live",
"has_email": false,
"closed": false
},
"messages": [
{
"id": 1,
"from": "customer",
"author": null,
"text": "",
"created_datetime": "",
"emailed": false,
"attachments": [
{
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
],
"agent_typing": null,
"suggestion": {
"id": 1,
"articles": [
{
"id": 1,
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week."
}
]
},
"token": ""
}List a visitor's orders
GET/api/chat/{helpdesk}/{public_id}/orders
The recent orders of the verified address, read from the connected Shopify store: status, items, tracking when it is offered, and per order which requests can be made and why others cannot. Needs the order session as Authorization: Bearer; 401 with code orders_session without one.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
200 · The orders. · ChatOrders
Request
curl "https://cs.growthdept.ai/api/chat/1/1/orders"Response 200
{
"email": "maya.okafor@example.com",
"orders": [
{
"id": 1,
"name": "Demo Store",
"created_at": null,
"status": "cancelled",
"total": null,
"currency": "USD",
"items": [
{
"title": "",
"variant": null,
"quantity": 0,
"image_url": null
}
],
"more_items": 0,
"tracking": [
{
"company": null,
"number": null,
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"delivered_at": null
}
],
"status_url": null,
"actions": [
{
"action": "issue",
"available": false,
"why": "not_delivered"
}
]
}
]
}Ask whether a chat is live
GET/api/chat/{helpdesk}/{public_id}/status
What the chat page asks while no conversation is open: live when a visitor can start a conversation now, offline when they can only leave a message.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
200 · The chat's state. · ChatStatus
Request
curl "https://cs.growthdept.ai/api/chat/1/1/status"Response 200
{
"status": "live"
}Show the visitor that you are typing
POST/api/tickets/{id}/chat/typing
Shows the chat visitor that you are typing for the next six seconds; the composer calls it every few seconds while you type. typing false clears it. Does nothing on tickets that did not come from chat.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The ticket's id. |
Body
| Field | Type | Description |
|---|---|---|
| typing | boolean | false stops the indicator at once. |
Response
200 · Whether the ticket has a chat conversation. · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/tickets/4182/chat/typing" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"typing": false
}'Response 200
{
"chat": false
}Leave an email in a campaign
POST/api/chat/{helpdesk}/{public_id}/campaigns/email
Sent by the chat launcher as text/plain JSON: {"campaign", "variant", "visitor", "email"}. For a running campaign with an email form, the helpdesk finds or creates the customer and records an email event. Nothing is sent to the address. Always answers 204.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
204 · Received.
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/campaigns/email"Response 204
(no body)Record a campaign event
POST/api/chat/{helpdesk}/{public_id}/campaigns/events
Sent by the chat launcher as text/plain JSON (so the store page needs no cross-site permission): {"campaign", "variant", "type": shown | opened | clicked | code_copied | dismissed, "visitor": the random id the browser keeps}. The visitor id is stored only as a keyed hash. Shown, opened and closed count once per visitor and campaign a day. Always answers 204.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
204 · Received.
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/campaigns/events"Response 204
(no body)Which campaigns fit this visitor (script)
GET/api/chat/{helpdesk}/{public_id}/campaigns/visitor.js
A script the chat's launcher loads on the store page when a running campaign uses the visitor's country or store customer conditions (tags, orders, total spent, products bought). cid is the signed-in store customer's id, when the store page knows it. It calls window.__gdHelpdeskChatVisitor(public_id, {ok: [campaign ids]}) with the campaigns whose server conditions hold. Never cached; limited per address.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
200 · JavaScript. · object
Request
curl \
"https://cs.growthdept.ai/api/chat/1/1/campaigns/visitor.js"Response 200
{}Write in a chat conversation
POST/api/chat/{helpdesk}/{public_id}/conversation/messages
JSON with message (up to 4,000 characters). Needs the visitor token as Authorization: Bearer. Adds the message to the conversation's ticket.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
201 · The message as the widget shows it. · ChatVisitorMessage
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/conversation/messages"Response 201
{
"message": {
"id": 1,
"from": "customer",
"author": null,
"text": "",
"created_datetime": "",
"emailed": false,
"attachments": [
{
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
}Answer a flow step
POST/api/chat/{helpdesk}/{public_id}/flow-runs/{run_id}
The visitor's answer to the step the run waits on, with the run's token as Authorization: Bearer: step (from next.step) and choice (a button's id), text (a question's answer) or helpful (true or false for did this help?). Answers the messages to show next and what waits then. 409 when the run waits on another step.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
| run_ | The run's id. |
Response
200 · The next steps. · ChatFlowView
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/flow-runs/1"Response 200
{
"flow": {
"id": 1,
"name": "Demo Store"
},
"run": {
"id": 1,
"token": null
},
"answer": null,
"messages": [
{
"step": "",
"text": "",
"articles": [
{
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
],
"next": {
"type": "choices",
"step": "",
"text": null,
"options": [
{
"id": "",
"label": "Reason for contact"
}
],
"answer": "text",
"prefill": {
"email": "maya.okafor@example.com",
"message": null
}
}
}Email a code to see orders
POST/api/chat/{helpdesk}/{public_id}/orders/code
Emails a 6-digit code to the address in email, valid for 10 minutes, and answers the verification to send back with it. Needs the page token in X-Chat-Page. The answer is the same whether or not the address has orders. 409 with code orders_off when the chat does not offer order lookup. Limits: 5 codes per address of the caller per ten minutes, 3 per email address per hour.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
201 · The verification to send back with the code. · ChatOrderCode
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/orders/code"Response 201
{
"verification": "",
"expires_in": 0
}Check an order code
POST/api/chat/{helpdesk}/{public_id}/orders/verify
Checks code against verification. A right code answers an order session for 30 minutes; a wrong one is 400 with code code, and after 5 tries, or once the code is 10 minutes old, 400 with code code_expired.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
Response
200 · The order session. · ChatOrderSession
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/orders/verify"Response 200
{
"token": "",
"expires_in": 0
}Answer suggested articles
POST/api/chat/{helpdesk}/{public_id}/conversation/suggestions/{suggestion_id}
outcome resolved (an article answered the question; article_id says which) closes the conversation's ticket, tagged resolved-by-article, with a note for agents. outcome escalated leaves it to the team. Needs the visitor token as Authorization: Bearer.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
| suggestion_ | The suggestion's id, from the conversation's suggestion. |
Response
200 · What was recorded. · ChatSuggestionAnswer
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/conversation/suggestions/1"Response 200
{
"outcome": "resolved",
"closed": false
}Start a flow in the chat
POST/api/chat/{helpdesk}/{public_id}/flows/{flow_id}/runs
What the chat page posts when a visitor picks a flow: JSON with language. The flow must be switched on and offered by the chat. Answers the first messages, what waits for the visitor, and the run's token for the later calls. Each address may start 30 runs per ten minutes in a helpdesk.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
| flow_ | The flow's id. |
Response
201 · The flow's first steps and the run's token. · ChatFlowView
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/flows/1/runs"Response 201
{
"flow": {
"id": 1,
"name": "Demo Store"
},
"run": {
"id": 1,
"token": null
},
"answer": null,
"messages": [
{
"step": "",
"text": "",
"articles": [
{
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
],
"next": {
"type": "choices",
"step": "",
"text": null,
"options": [
{
"id": "",
"label": "Reason for contact"
}
],
"answer": "text",
"prefill": {
"email": "maya.okafor@example.com",
"message": null
}
}
}Request a return, cancellation or help with an order
POST/api/chat/{helpdesk}/{public_id}/orders/{order_id}/requests
Opens a chat conversation for the team about one of the verified address's orders: action (issue, return or cancel), reason, and message, name, language and page_url. Needs the order session as Authorization: Bearer and the page token in X-Chat-Page. The ticket gets the action's tag and a note with the order. Nothing is refunded, returned or cancelled by this call. 409 with code order when the order does not allow the action now.
Parameters
| Name | Description |
|---|---|
| helpdeskrequiredpath · string | The helpdesk's slug. |
| public_ | The widget's public id. |
| order_ | The Shopify order id. |
Response
201 · The conversation and its visitor token. · ChatVisitorStarted
Request
curl -X POST \
"https://cs.growthdept.ai/api/chat/1/1/orders/1/requests"Response 201
{
"status": "live",
"conversation": {
"id": 1,
"kind": "live",
"has_email": false,
"closed": false
},
"messages": [
{
"id": 1,
"from": "customer",
"author": null,
"text": "",
"created_datetime": "",
"emailed": false,
"attachments": [
{
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
],
"agent_typing": null,
"suggestion": {
"id": 1,
"articles": [
{
"id": 1,
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week."
}
]
},
"token": ""
}Flows
Flows are guided conversations in the chat window: the visitor presses buttons, reads answers, may type an answer, and either says the flow helped or is handed to the team. Steps are a tree, checked when you save. A chat offers the flows its settings name. Admins build flows; every agent can read them.
The Flow object · 10 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| name | string | Agents see it in the list; visitors see it on the flow's button. |
| language | en, fr, de, es | |
| enabled | boolean | Off hides the flow from every chat. |
| steps | array of FlowStep | |
| step_ | integer | Steps in the whole tree. |
| widgets | array of object | The chats that offer this flow. |
| created_ | datetime or null | |
| updated_ | datetime or null |
List flows
GET/api/flows
The helpdesk's flows, by name, each with its steps and the chats that offer it.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default name:asc.updated_datetime:asc, updated_datetime:desc, created_datetime:asc, created_datetime:desc, name:asc, name:desc |
Response
200 · A page of flows. · list of Flow
Request
curl "https://cs.growthdept.ai/api/flows?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/flows?limit=2",
"data": [
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"language": "en",
"enabled": false,
"steps": [
{
"id": "",
"type": "message",
"text": null,
"articles": [
0
],
"answer": "text",
"options": [
{
"id": "",
"label": "Reason for contact",
"steps": []
}
],
"tags": [
""
]
}
],
"step_count": 0,
"widgets": [
{
"id": 1,
"name": "Demo Store"
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a flow
POST/api/flows
Creates a flow, switched off unless enabled is true. name and at least one step are required; steps are checked as a tree (see FlowStep) and problems come back per field, such as steps.0.options.1.label. A chat offers the flow once its settings.flows.ids name it.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| name | string | The flow's name: agents see it in the list, visitors on the flow's button in the chat window. |
| language | en, fr, de, es | The language the flow is written in. A chat shows it to visitors whose window is in this language. |
| enabled | boolean | Off hides the flow from every chat. |
| steps | array of any | The steps, as a tree: see the FlowStep schema. |
Response
201 · The new flow. · Flow
Request
curl -X POST "https://cs.growthdept.ai/api/flows" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"language": "en",
"enabled": false
}'Response 201
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"language": "en",
"enabled": false,
"steps": [
{
"id": "",
"type": "message",
"text": null,
"articles": [
0
],
"answer": "text",
"options": [
{
"id": "",
"label": "Reason for contact",
"steps": []
}
],
"tags": [
""
]
}
],
"step_count": 0,
"widgets": [
{
"id": 1,
"name": "Demo Store"
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Get a flow
GET/api/flows/{id}
One flow with its steps and the chats that offer it.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The flow's id. |
Response
200 · The flow. · Flow
Request
curl "https://cs.growthdept.ai/api/flows/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"language": "en",
"enabled": false,
"steps": [
{
"id": "",
"type": "message",
"text": null,
"articles": [
0
],
"answer": "text",
"options": [
{
"id": "",
"label": "Reason for contact",
"steps": []
}
],
"tags": [
""
]
}
],
"step_count": 0,
"widgets": [
{
"id": 1,
"name": "Demo Store"
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Change a flow
PUT/api/flows/{id}
Changes the fields sent. steps replaces the whole tree. Visitors already in the flow carry on from the step they are at when it still exists.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The flow's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | The flow's name: agents see it in the list, visitors on the flow's button in the chat window. |
| language | en, fr, de, es | The language the flow is written in. A chat shows it to visitors whose window is in this language. |
| enabled | boolean | Off hides the flow from every chat. |
| steps | array of any | The steps, as a tree: see the FlowStep schema. |
Response
200 · The flow after the change. · Flow
Request
curl -X PUT "https://cs.growthdept.ai/api/flows/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"language": "en",
"enabled": false
}'Response 200
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"language": "en",
"enabled": false,
"steps": [
{
"id": "",
"type": "message",
"text": null,
"articles": [
0
],
"answer": "text",
"options": [
{
"id": "",
"label": "Reason for contact",
"steps": []
}
],
"tags": [
""
]
}
],
"step_count": 0,
"widgets": [
{
"id": 1,
"name": "Demo Store"
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Delete a flow
DELETE/api/flows/{id}
Deletes the flow and takes it out of every chat. Tickets it handed over keep their notes, and reports keep counting its runs under its name.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The flow's id. |
Response
204 · The flow was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/flows/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Help center
Help centers are public sites of articles at /hc/<helpdesk>/<slug>, with categories, one or more languages and a contact card. Each article keeps a working copy and a published copy: saving changes the working copy, publishing puts it on the site. Bodies are sanitized when saved and again when shown. Admins write; every agent can read and search published articles to link them in replies.
The HelpCenter object · 15 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| name | string | Shown to agents. |
| slug | string | The last part of the public address, /hc/<helpdesk>/<slug>. |
| default_ | en, fr, de, es | The language the help center's own address shows. |
| languages | array of en, fr, de, es | Every language the help center publishes in, the default first. |
| live | boolean | Customers can open the public site only while this is true. |
| url | string | The public home page in the default language. |
| urls | object | The public home page in each language. |
| contact | object | The contact card at the bottom of the home and article pages. |
| settings | object | |
| articles_ | integer | |
| published_ | integer | Articles published in at least one of the help center's languages. |
| created_ | datetime or null | |
| updated_ | datetime or null | When the help center, or anything in it, last changed. |
The HelpCenterSearchHit object · 11 fields
| Field | Type | Description |
|---|---|---|
| article_ | integer | |
| help_ | integer | |
| help_ | string | |
| language | en, fr, de, es | |
| title | string | The published title. |
| excerpt | string | The excerpt, or the body's first words. |
| snippet | string | A passage around the words found; U+0001 and U+0002 surround each match. |
| category_ | integer or null | |
| category_ | string or null | |
| url | string | The article's public page. |
| published_ | datetime or null |
The HelpCenterArticle object · 9 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| help_ | integer | |
| category_ | integer or null | null when uncategorized. |
| position | integer | Order within its category, lowest first. |
| translations | object | The article in each language it has. |
| created_ | integer or null | |
| created_ | datetime or null | |
| updated_ | datetime or null |
The HelpCenterCategory object · 8 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| help_ | integer | |
| position | integer | Order on the home page, lowest first. |
| translations | object | The category's words in each language it has. |
| articles_ | integer | |
| created_ | datetime or null | |
| updated_ | datetime or null |
List help centers
GET/api/help-centers
The helpdesk's help centers, oldest first, with their public addresses, languages, contact card and article counts.
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:asc.created_datetime:asc, created_datetime:desc, updated_datetime:asc, updated_datetime:desc, name:asc, name:desc |
Response
200 · A page of help centers. · list of HelpCenter
Request
curl \
"https://cs.growthdept.ai/api/help-centers?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/help-centers?limit=2",
"data": [
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"slug": "unassigned-shipping",
"default_language": "en",
"languages": [
"en"
],
"live": false,
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"urls": {},
"contact": {
"enabled": false,
"contact_form_id": null,
"contact_integration_id": null,
"contact_form": {
"id": 1,
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"active": true
},
"mailbox": {
"id": 1,
"type": "email",
"address": "maya.okafor@example.com",
"active": true
},
"target": {
"kind": "contact_form",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
},
"settings": {
"brand_name": "",
"logo_url": null,
"favicon_url": null,
"theme": "light",
"accent": "",
"logo_link": null,
"header_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"footer_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"noindex": false,
"contact_enabled": false,
"texts": {}
},
"articles_count": 0,
"published_articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a help center
POST/api/help-centers
Creates a help center that is not live yet. name is required; slug is made from it when left out. default_language and languages are among en, fr, de and es.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| name | string | The help center's name, shown to agents. Also the brand name until one is set. |
| slug | string | The last part of the public address, /hc/<helpdesk>/<slug>. Made from the name when left out. |
| default_ | en, fr, de, es | The language the help center's own address shows. |
| languages | array of en, fr, de, es | Every language the help center publishes in, the default included. |
| live | boolean | Customers can open the public site only while this is true. |
| contact_ | integer or string | The contact form the contact card opens. null for none. |
| contact_ | integer or string | A mailbox whose address the contact card links to when no contact form is set. null for none. |
| settings | object | Look, words and links. Fields sent replace the stored ones; others stay. |
Response
201 · The new help center. · HelpCenter
Request
curl -X POST "https://cs.growthdept.ai/api/help-centers" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"slug": "unassigned-shipping",
"default_language": "en"
}'Response 201
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"slug": "unassigned-shipping",
"default_language": "en",
"languages": [
"en"
],
"live": false,
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"urls": {},
"contact": {
"enabled": false,
"contact_form_id": null,
"contact_integration_id": null,
"contact_form": {
"id": 1,
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"active": true
},
"mailbox": {
"id": 1,
"type": "email",
"address": "maya.okafor@example.com",
"active": true
},
"target": {
"kind": "contact_form",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
},
"settings": {
"brand_name": "",
"logo_url": null,
"favicon_url": null,
"theme": "light",
"accent": "",
"logo_link": null,
"header_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"footer_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"noindex": false,
"contact_enabled": false,
"texts": {}
},
"articles_count": 0,
"published_articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Get a help center
GET/api/help-centers/{id}
One help center with its settings, contact card and public addresses.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
Response
200 · The help center. · HelpCenter
Request
curl "https://cs.growthdept.ai/api/help-centers/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"slug": "unassigned-shipping",
"default_language": "en",
"languages": [
"en"
],
"live": false,
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"urls": {},
"contact": {
"enabled": false,
"contact_form_id": null,
"contact_integration_id": null,
"contact_form": {
"id": 1,
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"active": true
},
"mailbox": {
"id": 1,
"type": "email",
"address": "maya.okafor@example.com",
"active": true
},
"target": {
"kind": "contact_form",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
},
"settings": {
"brand_name": "",
"logo_url": null,
"favicon_url": null,
"theme": "light",
"accent": "",
"logo_link": null,
"header_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"footer_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"noindex": false,
"contact_enabled": false,
"texts": {}
},
"articles_count": 0,
"published_articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Change a help center
PUT/api/help-centers/{id}
Changes the fields sent. Fields inside settings replace the stored ones and the rest stay; texts merge per language and field. live true puts the public site up, false takes it down. Removing a language hides its articles without deleting them.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | The help center's name, shown to agents. Also the brand name until one is set. |
| slug | string | The last part of the public address, /hc/<helpdesk>/<slug>. Made from the name when left out. |
| default_ | en, fr, de, es | The language the help center's own address shows. |
| languages | array of en, fr, de, es | Every language the help center publishes in, the default included. |
| live | boolean | Customers can open the public site only while this is true. |
| contact_ | integer or string | The contact form the contact card opens. null for none. |
| contact_ | integer or string | A mailbox whose address the contact card links to when no contact form is set. null for none. |
| settings | object | Look, words and links. Fields sent replace the stored ones; others stay. |
Response
202 · The help center after the change. · HelpCenter
Request
curl -X PUT "https://cs.growthdept.ai/api/help-centers/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"slug": "unassigned-shipping",
"default_language": "en"
}'Response 202
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"slug": "unassigned-shipping",
"default_language": "en",
"languages": [
"en"
],
"live": false,
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"urls": {},
"contact": {
"enabled": false,
"contact_form_id": null,
"contact_integration_id": null,
"contact_form": {
"id": 1,
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"active": true
},
"mailbox": {
"id": 1,
"type": "email",
"address": "maya.okafor@example.com",
"active": true
},
"target": {
"kind": "contact_form",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
},
"settings": {
"brand_name": "",
"logo_url": null,
"favicon_url": null,
"theme": "light",
"accent": "",
"logo_link": null,
"header_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"footer_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"noindex": false,
"contact_enabled": false,
"texts": {}
},
"articles_count": 0,
"published_articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Delete a help center
DELETE/api/help-centers/{id}
Deletes the help center with its categories and articles. Its public address stops answering at once. This cannot be undone.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
Response
204 · The help center was deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/help-centers/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Search published articles
GET/api/help-centers/search
Articles customers can read: published translations in live help centers, best matches first, each with its public address. Agents use it to link an article in a reply. Without q, the most recently published come first.
Parameters
| Name | Description |
|---|---|
| qquery · string | Words to find in titles, excerpts and bodies. Partial words match their beginning. |
| languagequery · string | Only articles in this language.en, fr, de, es |
| help_ | Only this help center. |
| limitquery · string | At most this many results, up to 50. Defaults to 20. |
Response
200 · Matching articles. · list of HelpCenterSearchHit
Request
curl \
"https://cs.growthdept.ai/api/help-centers/search?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/help-centers/search",
"data": [
{
"article_id": 0,
"help_center_id": 0,
"help_center_name": "",
"language": "en",
"title": "",
"excerpt": "Hi, order #1042 said 3 to 5 days and it has been a week.",
"snippet": "",
"category_id": null,
"category_name": null,
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"published_datetime": "2026-11-04T09:41:12+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}List a help center's articles
GET/api/help-centers/{id}/articles
Articles in their order within categories, each with every translation's working copy and publication state. Filter by category, by language, by state (draft or published in that language, or in any) or by words in the title.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default position:asc.position:asc, position:desc, created_datetime:asc, created_datetime:desc, updated_datetime:asc, updated_datetime:desc |
| category_ | A category id, or none for uncategorized articles. |
| languagequery · string | Only articles with a translation in this language.en, fr, de, es |
| statequery · string | published: published in language (or in any language). draft: not.draft, published |
| searchquery · string | Words in the title, in any language. |
Response
200 · A page of articles. · list of HelpCenterArticle
Request
curl \
"https://cs.growthdept.ai/api/help-centers/1/articles?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/help-centers/1/articles?limit=2",
"data": [
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"category_id": null,
"position": 0,
"translations": {},
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create an article
POST/api/help-centers/{id}/articles
Creates an article as a draft, at the end of its category. title is required, in language (the help center's default when left out); the slug is made from it unless given. publish true publishes it at once.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
Body
| Field | Type | Description |
|---|---|---|
| language | string | Which language the title, slug, excerpt and body are in. Defaults to the help center's default language. |
| title | string | Required when the article has no translation in this language yet. |
| slug | string | The last part of the article's address in this language, unique in the help center. Made from the title when the translation is created without one; later title changes keep it. |
| excerpt | string or null | A short summary shown in lists and search results. Without one, the body's first words are used. |
| body_ | string | The article in HTML. Scripts, styles, event handlers and links other than http(s), mailto and tel are removed when it is saved. |
| category_ | integer or string | The category the article is in; null for none. |
| position | integer | Order within its category, lowest first. |
| publish | boolean | true publishes this language's working copy after saving it. |
Response
201 · The new article. · HelpCenterArticle
Request
curl -X POST \
"https://cs.growthdept.ai/api/help-centers/1/articles" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"language": "en",
"title": "",
"slug": "unassigned-shipping"
}'Response 201
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"category_id": null,
"position": 0,
"translations": {},
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}List a help center's categories
GET/api/help-centers/{id}/categories
The help center's categories in their order, each with its words in every language it has and how many articles it holds.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default position:asc.position:asc, position:desc, created_datetime:asc, created_datetime:desc |
Response
200 · A page of categories. · list of HelpCenterCategory
Request
curl \
"https://cs.growthdept.ai/api/help-centers/1/categories?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/help-centers/1/categories?limit=2",
"data": [
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"position": 0,
"translations": {},
"articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Create a category
POST/api/help-centers/{id}/categories
Adds a category at the end of the list. name is required, in language (the help center's default language when left out).
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
Body
| Field | Type | Description |
|---|---|---|
| language | string | Which language the name, slug and description are in. Defaults to the help center's default language. |
| name | string | The category's name in that language. Required when the category has no name in it yet. |
| slug | string | The last part of the category's address in that language. Made from the name when left out. |
| description | string or null | A line under the name on the help center's home page. |
| position | integer | Order among the help center's categories, lowest first. |
Response
201 · The new category. · HelpCenterCategory
Request
curl -X POST \
"https://cs.growthdept.ai/api/help-centers/1/categories" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"language": "en",
"name": "Demo Store",
"slug": "unassigned-shipping"
}'Response 201
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"position": 0,
"translations": {},
"articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Duplicate a help center
POST/api/help-centers/{id}/duplicate
Copies the help center with its settings, categories and articles under a new address. The copy is not live and its articles are drafts, so nothing changes for customers until someone publishes it.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center to copy. |
Response
201 · The copy. · HelpCenter
Request
curl -X POST \
"https://cs.growthdept.ai/api/help-centers/1/duplicate" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 201
{
"id": 1,
"uri": "/api/",
"name": "Demo Store",
"slug": "unassigned-shipping",
"default_language": "en",
"languages": [
"en"
],
"live": false,
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"urls": {},
"contact": {
"enabled": false,
"contact_form_id": null,
"contact_integration_id": null,
"contact_form": {
"id": 1,
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"active": true
},
"mailbox": {
"id": 1,
"type": "email",
"address": "maya.okafor@example.com",
"active": true
},
"target": {
"kind": "contact_form",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
},
"settings": {
"brand_name": "",
"logo_url": null,
"favicon_url": null,
"theme": "light",
"accent": "",
"logo_link": null,
"header_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"footer_links": [
{
"label": "Reason for contact",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
],
"noindex": false,
"contact_enabled": false,
"texts": {}
},
"articles_count": 0,
"published_articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Get an article
GET/api/help-centers/{id}/articles/{articleId}
One article with every translation's working copy and publication state.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| articleIdrequiredpath · integer | The article's id. |
Response
200 · The article. · HelpCenterArticle
Request
curl \
"https://cs.growthdept.ai/api/help-centers/1/articles/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"category_id": null,
"position": 0,
"translations": {},
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Change an article
PUT/api/help-centers/{id}/articles/{articleId}
Saves the fields sent to the working copy in language, adding that translation when the article has none (which needs title). Customers keep seeing the published copy until the article is published again; publish true does that after saving. category_id moves the article to the end of another category.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| articleIdrequiredpath · integer | The article's id. |
Body
| Field | Type | Description |
|---|---|---|
| language | string | Which language the title, slug, excerpt and body are in. Defaults to the help center's default language. |
| title | string | Required when the article has no translation in this language yet. |
| slug | string | The last part of the article's address in this language, unique in the help center. Made from the title when the translation is created without one; later title changes keep it. |
| excerpt | string or null | A short summary shown in lists and search results. Without one, the body's first words are used. |
| body_ | string | The article in HTML. Scripts, styles, event handlers and links other than http(s), mailto and tel are removed when it is saved. |
| category_ | integer or string | The category the article is in; null for none. |
| position | integer | Order within its category, lowest first. |
| publish | boolean | true publishes this language's working copy after saving it. |
Response
202 · The article after the change. · HelpCenterArticle
Request
curl -X PUT \
"https://cs.growthdept.ai/api/help-centers/1/articles/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"language": "en",
"title": "",
"slug": "unassigned-shipping"
}'Response 202
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"category_id": null,
"position": 0,
"translations": {},
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Delete an article
DELETE/api/help-centers/{id}/articles/{articleId}
Deletes the article in every language; its addresses stop answering. With language, deletes only that translation, unless it is the last one.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| articleIdrequiredpath · integer | The article's id. |
| languagequery · string | Delete only this translation.en, fr, de, es |
Response
204 · Deleted.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/help-centers/1/articles/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Move and reorder articles
PUT/api/help-centers/{id}/articles/positions
Puts the listed articles in category_id (null for uncategorized), in the order given. Articles already in that category and not listed follow them. Use it to reorder a category or to move an article into another one.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
Body
| Field | Type | Description |
|---|---|---|
| category_ | integer or string | The category the listed articles are in after the move; null for uncategorized. |
| article_ | array of integer or string | Article ids in their new order in that category. |
Response
202 · The articles of that category in their new order. · list of HelpCenterArticle
Request
curl -X PUT \
"https://cs.growthdept.ai/api/help-centers/1/articles/positions?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"category_id": 0,
"article_ids": [
0
]
}'Response 202
{
"object": "list",
"uri": "/api/help-centers/1/articles/positions",
"data": [
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"category_id": null,
"position": 0,
"translations": {},
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Get a category
GET/api/help-centers/{id}/categories/{categoryId}
One category with its words in every language it has.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| categoryIdrequiredpath · integer | The category's id. |
Response
200 · The category. · HelpCenterCategory
Request
curl \
"https://cs.growthdept.ai/api/help-centers/1/categories/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"position": 0,
"translations": {},
"articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Change a category
PUT/api/help-centers/{id}/categories/{categoryId}
Changes the category's name, slug and description in language (adding that language when the category has no words in it yet, which needs name), and its position.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| categoryIdrequiredpath · integer | The category's id. |
Body
| Field | Type | Description |
|---|---|---|
| language | string | Which language the name, slug and description are in. Defaults to the help center's default language. |
| name | string | The category's name in that language. Required when the category has no name in it yet. |
| slug | string | The last part of the category's address in that language. Made from the name when left out. |
| description | string or null | A line under the name on the help center's home page. |
| position | integer | Order among the help center's categories, lowest first. |
Response
202 · The category after the change. · HelpCenterCategory
Request
curl -X PUT \
"https://cs.growthdept.ai/api/help-centers/1/categories/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"language": "en",
"name": "Demo Store",
"slug": "unassigned-shipping"
}'Response 202
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"position": 0,
"translations": {},
"articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Delete a category
DELETE/api/help-centers/{id}/categories/{categoryId}
Deletes the category; its articles stay, uncategorized. With language, deletes only the category's words in that language.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| categoryIdrequiredpath · integer | The category's id. |
| languagequery · string | Delete only this language's words.en, fr, de, es |
Response
204 · Deleted.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/help-centers/1/categories/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Reorder categories
PUT/api/help-centers/{id}/categories/positions
Sets the order of the help center's categories on its home page. Categories left out follow the listed ones, in their current order.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
Body
| Field | Type | Description |
|---|---|---|
| category_ | array of integer or string | Category ids in their new order. Categories left out follow, in their current order. |
Response
202 · Every category in its new order. · list of HelpCenterCategory
Request
curl -X PUT \
"https://cs.growthdept.ai/api/help-centers/1/categories/positions?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"category_ids": [
0
]
}'Response 202
{
"object": "list",
"uri": "/api/help-centers/1/categories/positions",
"data": [
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"position": 0,
"translations": {},
"articles_count": 0,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Publish an article
POST/api/help-centers/{id}/articles/{articleId}/publish
Copies the working copy in language to the public site. Customers can read it while the help center is live. An article with an empty body cannot be published.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| articleIdrequiredpath · integer | The article's id. |
Body
| Field | Type | Description |
|---|---|---|
| language | string | The language to publish or unpublish. Defaults to the help center's default language. |
Response
200 · The article, published. · HelpCenterArticle
Request
curl -X POST \
"https://cs.growthdept.ai/api/help-centers/1/articles/1/publish" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"language": "en"
}'Response 200
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"category_id": null,
"position": 0,
"translations": {},
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Unpublish an article
POST/api/help-centers/{id}/articles/{articleId}/unpublish
Takes the article in language off the public site. The working copy stays, so it can be published again.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The help center's id. |
| articleIdrequiredpath · integer | The article's id. |
Body
| Field | Type | Description |
|---|---|---|
| language | string | The language to publish or unpublish. Defaults to the help center's default language. |
Response
200 · The article, unpublished. · HelpCenterArticle
Request
curl -X POST \
"https://cs.growthdept.ai/api/help-centers/1/articles/1/unpublish" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"language": "en"
}'Response 200
{
"id": 1,
"uri": "/api/",
"help_center_id": 0,
"category_id": null,
"position": 0,
"translations": {},
"created_by_agent_id": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Imports
Import from Gorgias with an API key from that account: agents (switched off, and nobody is invited), teams, tags, customers, tickets with their messages and satisfaction scores, macros, views and rules (switched off until someone turns them on). An import runs in the background; follow its progress here or cancel it. Running it again later updates what it copied instead of making copies.
The Import object · 11 fields
A copy of another helpdesk's data into this one, running in the background.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| type | gorgias, zendesk | Where the import copies from. |
| status | pending, running, done, failed, cancelled | |
| params | object | |
| meta | object | |
| user | object or null | The agent who started it. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| started_ | datetime or null | |
| ended_ | datetime or null |
The MailImport object · 15 fields
An import of a connected Gmail mailbox's older mail for a date range, running in the background.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| uri | string | |
| integration_ | integer | The Gmail mailbox (an integration of type gmail). |
| address | string or null | The mailbox's address. |
| since | datetime | Mail received from this moment... |
| until | datetime | ...up to, not including, this one. |
| status | pending, running, done, failed, cancelled | |
| close_ | boolean | Whether the tickets it opens start closed. |
| progress | object | |
| error | string or null | Why it stopped, when it failed. |
| user | object or null | The agent who started it. |
| created_ | datetime or null | |
| updated_ | datetime or null | |
| started_ | datetime or null | |
| ended_ | datetime or null |
List imports
GET/api/imports
Every import into this helpdesk, from Gorgias or Zendesk, newest first, with its status, progress per object, the items that could not be copied and the copies someone should check. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| limitquery · integer | How many objects to return, from 1 to 100. Default 30. |
| cursorquery · string | Where to continue: meta.next_cursor or meta.prev_cursor from the previous page. |
| order_ | Sort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc |
Response
200 · A page of imports. · list of Import
Request
curl "https://cs.growthdept.ai/api/imports?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/imports?limit=2",
"data": [
{
"id": 1,
"uri": "/api/",
"type": "gorgias",
"status": "pending",
"params": {
"source": "",
"domain": "demo-store",
"objects": [
"customers"
]
},
"meta": {
"phase": null,
"progress": {},
"error": null,
"errors": [
{
"object": "",
"gorgias_id": null,
"source_id": null,
"message": ""
}
],
"errors_total": 0,
"flags": [
{
"object": "",
"id": 1,
"gorgias_id": null,
"source_id": null,
"name": "Demo Store",
"problem": ""
}
]
},
"user": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
}
}Start an import
POST/api/imports
Starts copying another helpdesk's account into this one. From Gorgias (source gorgias, the default): agents (switched off, nobody is invited), teams, tags, customers, tickets with their messages and satisfaction scores, macros, views and rules (switched off). From Zendesk (source zendesk): agents (switched off), end users as customers with their organization's name, tags, tickets with their public replies and internal notes, and macros, read through Zendesk's incremental exports. The key or token is checked first, stored encrypted and dropped when the import ends; it is never returned. Nothing copied sends email or runs rules. Running it again later updates what it copied instead of making copies. One import runs at a time. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| source | gorgias, zendesk | Where to import from: gorgias (the default) or zendesk. |
| domainrequired | string | The account's subdomain: acme for acme.gorgias.com or acme.zendesk.com. |
| emailrequired | string | Gorgias: the email of the person the API key belongs to. Zendesk: the email of the admin the API token belongs to. |
| api_ | string | A Gorgias REST API key, or a Zendesk API token, used only for this import. |
| objects | array of customers, tickets, tags, macros, views, rules | What to copy; everything when left out. Agents (and from Gorgias, teams) always come across. Zendesk takes customers, tickets, tags and macros. |
Response
201 · The import, waiting to start. · Import
Request
curl -X POST "https://cs.growthdept.ai/api/imports" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "demo-store",
"email": "maya.okafor@example.com",
"api_key": ""
}'Response 201
{
"id": 1,
"uri": "/api/",
"type": "gorgias",
"status": "pending",
"params": {
"source": "",
"domain": "demo-store",
"objects": [
"customers"
]
},
"meta": {
"phase": null,
"progress": {},
"error": null,
"errors": [
{
"object": "",
"gorgias_id": null,
"source_id": null,
"message": ""
}
],
"errors_total": 0,
"flags": [
{
"object": "",
"id": 1,
"gorgias_id": null,
"source_id": null,
"name": "Demo Store",
"problem": ""
}
]
},
"user": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null
}List email history imports
GET/api/mail-imports
The latest 50 imports of older mail from this helpdesk's Gmail mailboxes, newest first, with their progress. Admins only.
Role: admin or higher
Response
200 · The imports. · list of MailImport
Request
curl \
"https://cs.growthdept.ai/api/mail-imports?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/mail-imports",
"data": [
{
"id": 1,
"uri": "/api/",
"integration_id": 2,
"address": "maya.okafor@example.com",
"since": "2026-11-04T09:41:12+00:00",
"until": "2026-11-04T09:41:12+00:00",
"status": "pending",
"close_tickets": false,
"progress": {
"threads_seen": 0,
"threads_imported": 0,
"messages_imported": 0,
"tickets_created": 0,
"messages_skipped": 0
},
"error": null,
"user": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Start an email history import
POST/api/mail-imports
Brings in the mail a connected Gmail mailbox received in a date range, up to 2 years back, in the background. Only inbox conversations are read, the mailbox's address filter applies, and messages already in the helpdesk are skipped, so nothing comes in twice. Nothing is sent and no rule runs. Tickets it opens start closed unless close_tickets is false. One import runs at a time per mailbox. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| integration_ | integer | The Gmail mailbox's integration id. |
| sincerequired | string | The first day, such as 2025-01-01 (UTC), or an ISO time. |
| untilrequired | string | The last day, included, such as 2025-06-30 (UTC), or an ISO time, not included. |
| close_ | boolean | Open the imported conversations as closed tickets. True when left out. |
Response
201 · The import, waiting to start. · MailImport
Request
curl -X POST "https://cs.growthdept.ai/api/mail-imports" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"integration_id": 2,
"since": "",
"until": ""
}'Response 201
{
"id": 1,
"uri": "/api/",
"integration_id": 2,
"address": "maya.okafor@example.com",
"since": "2026-11-04T09:41:12+00:00",
"until": "2026-11-04T09:41:12+00:00",
"status": "pending",
"close_tickets": false,
"progress": {
"threads_seen": 0,
"threads_imported": 0,
"messages_imported": 0,
"tickets_created": 0,
"messages_skipped": 0
},
"error": null,
"user": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null
}Get an import
GET/api/imports/{id}
One import with its status and progress per object. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The import's id. |
Response
200 · The import. · Import
Request
curl "https://cs.growthdept.ai/api/imports/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"uri": "/api/",
"type": "gorgias",
"status": "pending",
"params": {
"source": "",
"domain": "demo-store",
"objects": [
"customers"
]
},
"meta": {
"phase": null,
"progress": {},
"error": null,
"errors": [
{
"object": "",
"gorgias_id": null,
"source_id": null,
"message": ""
}
],
"errors_total": 0,
"flags": [
{
"object": "",
"id": 1,
"gorgias_id": null,
"source_id": null,
"name": "Demo Store",
"problem": ""
}
]
},
"user": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null
}Cancel an import
DELETE/api/imports/{id}
Stops an import that is waiting or running. What it copied so far stays, and its API key is dropped. An import that has ended answers 409. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The import's id. |
Response
202 · The cancelled import. · Import
Request
curl -X DELETE "https://cs.growthdept.ai/api/imports/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 202
{
"id": 1,
"uri": "/api/",
"type": "gorgias",
"status": "pending",
"params": {
"source": "",
"domain": "demo-store",
"objects": [
"customers"
]
},
"meta": {
"phase": null,
"progress": {},
"error": null,
"errors": [
{
"object": "",
"gorgias_id": null,
"source_id": null,
"message": ""
}
],
"errors_total": 0,
"flags": [
{
"object": "",
"id": 1,
"gorgias_id": null,
"source_id": null,
"name": "Demo Store",
"problem": ""
}
]
},
"user": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null
}Get an email history import
GET/api/mail-imports/{id}
One import of older mail with its status and progress. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The import's id. |
Response
200 · The import. · MailImport
Request
curl "https://cs.growthdept.ai/api/mail-imports/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"uri": "/api/",
"integration_id": 2,
"address": "maya.okafor@example.com",
"since": "2026-11-04T09:41:12+00:00",
"until": "2026-11-04T09:41:12+00:00",
"status": "pending",
"close_tickets": false,
"progress": {
"threads_seen": 0,
"threads_imported": 0,
"messages_imported": 0,
"tickets_created": 0,
"messages_skipped": 0
},
"error": null,
"user": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null
}Cancel an email history import
DELETE/api/mail-imports/{id}
Stops an import that is waiting or running. The mail it brought in stays. An import that has ended answers 409. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The import's id. |
Response
202 · The cancelled import. · MailImport
Request
curl -X DELETE "https://cs.growthdept.ai/api/mail-imports/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 202
{
"id": 1,
"uri": "/api/",
"integration_id": 2,
"address": "maya.okafor@example.com",
"since": "2026-11-04T09:41:12+00:00",
"until": "2026-11-04T09:41:12+00:00",
"status": "pending",
"close_tickets": false,
"progress": {
"threads_seen": 0,
"threads_imported": 0,
"messages_imported": 0,
"tickets_created": 0,
"messages_skipped": 0
},
"error": null,
"user": {},
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"started_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null
}Onsite campaigns
Messages a chat shows by itself to store visitors who meet conditions: the page, time, visits, an exit, the cart, the signed-in store customer, business hours or country, with an optional code, products, an email form and an A/B split. The helpdesk's switch is off until an admin turns it on for chosen chats. Performance counts what visitors did, and orders that used a campaign's code come from the connected store.
The Campaign object · 22 fields
An onsite campaign: a message a chat shows by itself to store visitors who meet its conditions.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| chat | object | |
| name | string | |
| language | string | |
| status | draft, active, paused | |
| running | boolean | Active and inside its dates. |
| conditions | array of object | |
| delay_ | integer | |
| device | all, desktop, mobile | |
| allow_ | boolean | |
| include_ | boolean | With customer conditions, also show to visitors the store does not know. |
| from | object or null | |
| variants | array of object | |
| discount_ | string or null | |
| products | array of object | |
| email_ | boolean | |
| starts_ | datetime or null | |
| ends_ | datetime or null | |
| template_ | string or null | |
| created_ | datetime | |
| updated_ | datetime | |
| uri | string |
List onsite campaigns
GET/api/convert/campaigns
The helpdesk's onsite campaigns, active first. running says whether it is active and inside its dates; it shows only while the onsite campaigns switch is on for its chat.
Parameters
| Name | Description |
|---|---|
| chat_ | Only campaigns in this chat. |
Response
200 · The campaigns. · object
Request
curl "https://cs.growthdept.ai/api/convert/campaigns" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"chat": {
"id": 1,
"name": "Demo Store"
},
"name": "Demo Store",
"language": "en",
"status": "draft",
"running": false,
"conditions": [
{
"type": "email",
"operator": "",
"value": ""
}
],
"delay_seconds": 0,
"device": "all",
"allow_replies": false,
"include_unknown": false,
"from": {
"id": 1,
"name": "Demo Store"
},
"variants": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"message": "",
"weight": 0
}
],
"discount_code": null,
"products": [
{
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"image_url": null,
"price": null
}
],
"email_capture": false,
"starts_datetime": "2026-11-04T09:41:12+00:00",
"ends_datetime": "2026-11-04T09:41:12+00:00",
"template_key": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}
]
}Create an onsite campaign
POST/api/convert/campaigns
A message a chat shows by itself to store visitors who meet every condition: the page (url, product_page, time_on_page, visits, time_on_site, exit_intent, out_of_stock), the cart (cart_value, cart_product), the signed-in store customer (customer_tag, orders_count, total_spent, purchased_product), business_hours or country. delay_seconds waits after the conditions hold; device limits it to desktop or mobile. One to three variants make an A/B test, split by weight. discount_code, up to three products and an email form are optional. status active runs it between starts_datetime and ends_datetime. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| widget_ | integer | |
| namerequired | string | |
| language | string | |
| conditions | array of object | |
| delay_ | integer | |
| device | all, desktop, mobile | |
| allow_ | boolean | |
| include_ | boolean | |
| from_ | integer or null | |
| variantsrequired | array of object | |
| discount_ | string or null | |
| products | array of object | |
| email_ | boolean | |
| starts_ | datetime or null | |
| ends_ | datetime or null | |
| status | draft, active, paused | |
| template_ | string or null |
Response
201 · The campaign. · Campaign
Request
curl -X POST "https://cs.growthdept.ai/api/convert/campaigns" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"widget_id": 0,
"name": "Demo Store",
"variants": [
{
"key": "A",
"message": "",
"weight": 0
}
]
}'Response 201
{
"id": 1,
"chat": {
"id": 1,
"name": "Demo Store"
},
"name": "Demo Store",
"language": "en",
"status": "draft",
"running": false,
"conditions": [
{
"type": "email",
"operator": "",
"value": ""
}
],
"delay_seconds": 0,
"device": "all",
"allow_replies": false,
"include_unknown": false,
"from": {
"id": 1,
"name": "Demo Store"
},
"variants": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"message": "",
"weight": 0
}
],
"discount_code": null,
"products": [
{
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"image_url": null,
"price": null
}
],
"email_capture": false,
"starts_datetime": "2026-11-04T09:41:12+00:00",
"ends_datetime": "2026-11-04T09:41:12+00:00",
"template_key": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Onsite campaigns at a glance
GET/api/convert/overview
The helpdesk's switch and limits; every chat with its campaigns, whether campaigns are on for it, and when it last had a conversation or showed a campaign (seen_datetime, null until the chat is on a store); whether a store is connected (cart and customer conditions need one); and the last 30 days' figures with the five most-shown campaigns.
Response
200 · The summary. · object
Request
curl "https://cs.growthdept.ai/api/convert/overview" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Get the onsite campaigns switch
GET/api/convert/settings
Whether onsite campaigns are on, in which chats, and how often one visitor may see them.
Response
200 · The settings. · object
Request
curl "https://cs.growthdept.ai/api/convert/settings" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"enabled": false,
"chats": [
0
],
"max_per_visit": 0,
"minutes_between": 0,
"hide_days_after_close": 0
}Change the onsite campaigns switch
PUT/api/convert/settings
enabled turns campaigns on or off for the whole helpdesk; chats lists the chats that show them; max_per_visit (1 to 5), minutes_between (0 to 1,440) and hide_days_after_close (0 to 90) limit how often one visitor sees them. Fields you leave out keep their value. Admins only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| enabled | boolean | |
| chats | array of integer | |
| max_ | integer | |
| minutes_ | integer | |
| hide_ | integer |
Response
202 · The settings. · object
Request
curl -X PUT "https://cs.growthdept.ai/api/convert/settings" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": false,
"chats": [
0
],
"max_per_visit": 0
}'Response 202
{
"enabled": false,
"chats": [
0
],
"max_per_visit": 0,
"minutes_between": 0,
"hide_days_after_close": 0
}Onsite campaign performance
GET/api/convert/stats
For the period (default the last 30 days): per campaign and variant, how many visitors saw it, opened it, clicked a product, copied the code, left an email, replied or closed it, with the engagement and reply rates from those counts. orders=true also asks the connected store for orders that used each campaign's code in the period (slower).
Parameters
| Name | Description |
|---|---|
| sincequery · datetime | |
| untilquery · datetime | |
| ordersquery · string | Include orders that used each code.0, 1, true, false |
Response
200 · The figures. · object
Request
curl "https://cs.growthdept.ai/api/convert/stats" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Campaign templates
GET/api/convert/templates
Starting points: welcome a first-time visitor, catch a visitor about to leave, free-shipping nudge, help on a product page, out-of-stock email form, returning visitor. Offers are left in [BRACKETS].
Response
200 · The templates. · object
Request
curl "https://cs.growthdept.ai/api/convert/templates" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{}
]
}Get an onsite campaign
GET/api/convert/campaigns/{id}
One campaign with its conditions, versions, offer, dates and status.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The campaign. · Campaign
Request
curl "https://cs.growthdept.ai/api/convert/campaigns/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"chat": {
"id": 1,
"name": "Demo Store"
},
"name": "Demo Store",
"language": "en",
"status": "draft",
"running": false,
"conditions": [
{
"type": "email",
"operator": "",
"value": ""
}
],
"delay_seconds": 0,
"device": "all",
"allow_replies": false,
"include_unknown": false,
"from": {
"id": 1,
"name": "Demo Store"
},
"variants": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"message": "",
"weight": 0
}
],
"discount_code": null,
"products": [
{
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"image_url": null,
"price": null
}
],
"email_capture": false,
"starts_datetime": "2026-11-04T09:41:12+00:00",
"ends_datetime": "2026-11-04T09:41:12+00:00",
"template_key": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Update an onsite campaign
PUT/api/convert/campaigns/{id}
Changes the fields you send; status active starts it and paused stops it. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| widget_ | integer | |
| name | string | |
| language | string | |
| conditions | array of object | |
| delay_ | integer | |
| device | all, desktop, mobile | |
| allow_ | boolean | |
| include_ | boolean | |
| from_ | integer or null | |
| variants | array of object | |
| discount_ | string or null | |
| products | array of object | |
| email_ | boolean | |
| starts_ | datetime or null | |
| ends_ | datetime or null | |
| status | draft, active, paused | |
| template_ | string or null |
Response
202 · The campaign. · Campaign
Request
curl -X PUT "https://cs.growthdept.ai/api/convert/campaigns/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"widget_id": 0,
"name": "Demo Store",
"language": "en"
}'Response 202
{
"id": 1,
"chat": {
"id": 1,
"name": "Demo Store"
},
"name": "Demo Store",
"language": "en",
"status": "draft",
"running": false,
"conditions": [
{
"type": "email",
"operator": "",
"value": ""
}
],
"delay_seconds": 0,
"device": "all",
"allow_replies": false,
"include_unknown": false,
"from": {
"id": 1,
"name": "Demo Store"
},
"variants": [
{
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"message": "",
"weight": 0
}
],
"discount_code": null,
"products": [
{
"title": "",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"image_url": null,
"price": null
}
],
"email_capture": false,
"starts_datetime": "2026-11-04T09:41:12+00:00",
"ends_datetime": "2026-11-04T09:41:12+00:00",
"template_key": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00",
"uri": "/api/"
}Delete an onsite campaign
DELETE/api/convert/campaigns/{id}
Stops it and removes it from the lists and from performance figures. To keep its figures, pause it instead. Admins only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/convert/campaigns/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Ask the AI agent for wording
POST/api/convert/campaigns/{id}/copy
Queues a request in a new Assistant chat for the helpdesk's AI agent to write versions of the campaign's message from its audience and offer. The agent answers from the brand's machine, usually within a minute or two; nothing in the campaign changes. Answers with the chat's id.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| goal | string or null |
Response
201 · The chat. · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/convert/campaigns/1/copy" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"goal": null
}'Response 201
{
"chat_id": 0
}Order management
What chat visitors can do with their orders once they confirm their email address with a code: see status and tracking, and ask to report a problem, return or cancel. Each request opens a ticket with the order attached; nothing is refunded, returned or cancelled on its own. Needs a connected Shopify store.
The OrderManagement object · 4 fields
| Field | Type | Description |
|---|---|---|
| settings | object | |
| store | object or null | The store orders come from; null when none is connected. |
| object | ||
| widgets | array of object |
Read order management
GET/api/order-management
What chat visitors may do with their orders once they confirm their email with a code: tracking, and asking to report a problem, return or cancel, with the conditions for each. Also the store the orders come from, whether codes can be emailed, and which chats offer it.
Response
200 · The settings and what they depend on. · OrderManagement
Request
curl "https://cs.growthdept.ai/api/order-management" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"settings": {
"track": {
"enabled": false
},
"issue": {
"enabled": false,
"tag": ""
},
"return": {
"enabled": false,
"tag": "",
"days_after_delivery": 0
},
"cancel": {
"enabled": false,
"tag": "",
"hours_after_order": null
},
"orders_shown": 0
},
"store": {
"id": 1,
"name": "Demo Store",
"shop": "",
"status": "open"
},
"mail": {
"configured": false
},
"widgets": [
{
"id": 1,
"name": "Demo Store",
"orders": false
}
]
}Change order management
PUT/api/order-management
Replaces the settings with the ones sent; fields left out take their defaults. Requests never refund, return or cancel anything themselves: each opens a ticket with the order attached. Switch it on per chat with settings.orders on /api/chat-widgets/{id}.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| settingsrequired | any |
Response
200 · The settings and what they depend on. · OrderManagement
Request
curl -X PUT "https://cs.growthdept.ai/api/order-management" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"settings": {}
}'Response 200
{
"settings": {
"track": {
"enabled": false
},
"issue": {
"enabled": false,
"tag": ""
},
"return": {
"enabled": false,
"tag": "",
"days_after_delivery": 0
},
"cancel": {
"enabled": false,
"tag": "",
"hours_after_order": null
},
"orders_shown": 0
},
"store": {
"id": 1,
"name": "Demo Store",
"shop": "",
"status": "open"
},
"mail": {
"configured": false
},
"widgets": [
{
"id": 1,
"name": "Demo Store",
"orders": false
}
]
}Phone numbers
The helpdesk's phone numbers: search for one to buy, buy it, rename it and release it. Numbers are bought on Growth Dept's carrier account and Growth Dept pays for them; the cost shown on each is never billed to the helpdesk. Voice and SMS must be switched on for the helpdesk first.
The PhoneNumber object · 13 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| phone_ | string | E.164, such as +14155550123. |
| name | string | |
| country | string | |
| type | local, toll_free, mobile, national | |
| status | pending, active, failed, released | pending until Telnyx finishes the order, usually seconds. |
| status_ | string or null | |
| capabilities | array of string | |
| cost | object | What the number costs Growth Dept. It is never billed to the helpdesk. |
| registration | object | |
| integrations | array of object | |
| created_ | datetime or null | |
| updated_ | datetime or null |
The AvailablePhoneNumber object · 6 fields
| Field | Type | Description |
|---|---|---|
| e164 | string | |
| region | string or null | |
| locality | string or null | |
| upfront_ | string or null | |
| monthly_ | string or null | |
| features | array of string |
List phone numbers
GET/api/phone-numbers
The helpdesk's phone numbers, oldest first, each with the voice and SMS lines on it. Released numbers are left out.
Response
200 · The numbers. · list of PhoneNumber
Request
curl \
"https://cs.growthdept.ai/api/phone-numbers?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/phone-numbers",
"data": [
{
"id": 1,
"phone_number": "",
"name": "Demo Store",
"country": "",
"type": "local",
"status": "pending",
"status_detail": null,
"capabilities": [
""
],
"cost": {
"upfront_usd": null,
"monthly_usd": null,
"paid_by": "growth_dept"
},
"registration": {
"id": 1,
"assignment_status": null
},
"integrations": [
{
"id": 1,
"type": "phone",
"name": "Demo Store"
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Buy a phone number
POST/api/phone-numbers
Buys a number found with GET /api/phone-numbers/available. Growth Dept pays for the number; nothing is billed to the helpdesk. The number is pending until Telnyx finishes the order, usually within seconds. Voice and SMS must be switched on for the helpdesk, and it can hold a limited number of numbers (2 unless Growth Dept raised it).
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| phone_ | string | |
| name | string | |
| country | US, CA |
Response
201 · The new number, pending. · PhoneNumber
Request
curl -X POST "https://cs.growthdept.ai/api/phone-numbers" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": ""
}'Response 201
{
"id": 1,
"phone_number": "",
"name": "Demo Store",
"country": "",
"type": "local",
"status": "pending",
"status_detail": null,
"capabilities": [
""
],
"cost": {
"upfront_usd": null,
"monthly_usd": null,
"paid_by": "growth_dept"
},
"registration": {
"id": 1,
"assignment_status": null
},
"integrations": [
{
"id": 1,
"type": "phone",
"name": "Demo Store"
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Get a phone number
GET/api/phone-numbers/{id}
One number with the lines on it.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The phone number's id. |
Response
200 · The number. · PhoneNumber
Request
curl "https://cs.growthdept.ai/api/phone-numbers/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"phone_number": "",
"name": "Demo Store",
"country": "",
"type": "local",
"status": "pending",
"status_detail": null,
"capabilities": [
""
],
"cost": {
"upfront_usd": null,
"monthly_usd": null,
"paid_by": "growth_dept"
},
"registration": {
"id": 1,
"assignment_status": null
},
"integrations": [
{
"id": 1,
"type": "phone",
"name": "Demo Store"
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Rename a phone number
PUT/api/phone-numbers/{id}
Changes the name agents see.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The phone number's id. |
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string |
Response
200 · The number. · PhoneNumber
Request
curl -X PUT "https://cs.growthdept.ai/api/phone-numbers/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store"
}'Response 200
{
"id": 1,
"phone_number": "",
"name": "Demo Store",
"country": "",
"type": "local",
"status": "pending",
"status_detail": null,
"capabilities": [
""
],
"cost": {
"upfront_usd": null,
"monthly_usd": null,
"paid_by": "growth_dept"
},
"registration": {
"id": 1,
"assignment_status": null
},
"integrations": [
{
"id": 1,
"type": "phone",
"name": "Demo Store"
}
],
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Release a phone number
DELETE/api/phone-numbers/{id}
Gives the number back, which ends its monthly cost to Growth Dept. Remove the voice and SMS lines on it first. A released number cannot be got back.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The phone number's id. |
Response
204 · Released.
Request
curl -X DELETE "https://cs.growthdept.ai/api/phone-numbers/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Search numbers to buy
GET/api/phone-numbers/available
Numbers Telnyx has available now, with voice and SMS. type is local (give an area_code) or toll_free. The prices shown are Growth Dept's cost, not billed to the helpdesk.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| countryquery · string | US, CAdefault US |
| typequery · string | local, toll_freedefault local |
| area_ | |
| containsquery · string |
Response
200 · Up to 12 numbers. · list of AvailablePhoneNumber
Request
curl \
"https://cs.growthdept.ai/api/phone-numbers/available?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/phone-numbers/available",
"data": [
{
"e164": "",
"region": null,
"locality": null,
"upfront_cost_usd": null,
"monthly_cost_usd": null,
"features": [
""
]
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Whether voice and SMS are available
GET/api/telephony/status
Whether Growth Dept switched voice and SMS on for this helpdesk, how many numbers it may hold and holds, and whether calls can ring in the browser on this service.
Response
200 · The status. · object
Request
curl "https://cs.growthdept.ai/api/telephony/status" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Shopify
A connected Shopify store: the customer's orders, totals and fulfilment status for the sidebar, and order actions (refund, cancel, duplicate, replacement order, address change, resending the order email). Every action is planned first, checked again against the live order when it runs, and written to an append-only log.
The ShopifyStore object · 28 fields
A connected Shopify store. Its token is never returned.
| Field | Type | Description |
|---|---|---|
| id | integer | The integration id. |
| type | string | Always shopify. |
| name | string | |
| shop | string | The store's myshopify.com domain. |
| shop_ | string or null | |
| status | active, uninstalled, disconnected, redacted, token_invalid | |
| active | boolean | True when the helpdesk can read the store now. |
| install_ | oauth, custom_app, gd_connect | How the store is connected: the Shopify app, a custom app's token, or, for a Growth Dept fleet brand, Growth Dept's connection (gd_connect), which holds no Shopify token here. |
| currency | string or null | The store's currency. |
| timezone | string or null | |
| scopes | array of string | Scopes the token holds. |
| missing_ | array of string | Read scopes the sidebar needs and the token lacks. |
| missing_ | array of string | Scopes order actions need and the token lacks. |
| missing_ | array of string | Scopes for editing orders, discount codes and syncing customers to Shopify that the token lacks; only those actions are refused. |
| actions_ | boolean | Order actions are on. They start on when the store links with the scopes they need, as Gorgias's Shopify actions do. |
| agents_ | boolean | Agents (Basic and above), not only admins, can run money actions: refunds, cancellations, free replacements, orders marked as paid and discount codes. Starts on, as in Gorgias. |
| webhooks | array of string | Shopify topics that notify the helpdesk of changes. |
| webhook_ | string or null | Why notifications are missing, when they are. |
| fleet_ | string or null | The Growth Dept brand a gd_connect store belongs to. |
| refresh | webhooks, polling | How changes in the store reach the helpdesk: Shopify's notifications, or, for a gd_connect store, a check every few minutes. |
| polled_ | datetime or null | When the helpdesk last looked for changes (polling stores). |
| poll_ | string or null | Why the last check for changes did not finish. |
| last_ | string or null | |
| connected_ | datetime or null | |
| checked_ | datetime or null | |
| created_ | datetime or null | |
| deactivated_ | datetime or null | |
| admin_ | string | The store's Shopify admin. |
The ShopifyActionLogEntry object · 15 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| integration_ | integer or null | |
| plan_ | string or null | |
| action | string | |
| outcome | planned, requested, done, failed, refused, replayed | |
| order_ | string or null | |
| order_ | string or null | |
| ticket_ | integer or null | |
| customer_ | integer or null | |
| user_ | integer or null | |
| money | boolean | |
| amount | string or null | |
| currency | string or null | |
| detail | any | Ids, codes and short reasons. |
| created_ | datetime or null |
The ShopifyProduct object · 5 fields
An active product and its variants.
| Field | Type | Description |
|---|---|---|
| id | integer or string | |
| title | string | |
| image_ | string or null | |
| tracks_ | boolean | |
| variants | array of object |
The ShopifyLinkTicket object · 2 fields
A one-time link for connecting the store to a helpdesk.
| Field | Type | Description |
|---|---|---|
| url | string | The link page, with the ticket. Open it in a new tab. |
| expires_ | integer | Seconds until the ticket expires. |
The ShopifyEmbeddedSession object · 9 fields
What the Shopify app's page shows.
| Field | Type | Description |
|---|---|---|
| shop | string | The store's myshopify.com domain, from the ID token. |
| shop_ | string or null | |
| scopes | array of string | Scopes Shopify granted the app on this store. |
| missing_ | array of string | Read scopes the sidebar needs that Shopify has not granted. |
| missing_ | array of string | Scopes order actions need that Shopify has not granted. |
| token_ | boolean | True when this call exchanged the ID token for a new access token. |
| helpdesk | object or null | The helpdesk the store is linked to, or null. |
| plan | ShopifyPlan | |
| plan_ | boolean | True when the store must choose a plan in Shopify before it can be linked: plans are checked and it has no active one. |
The ShopifyPlan object · 11 fields
A store's Growth Dept Helpdesk plan, priced and charged through Shopify.
| Field | Type | Description |
|---|---|---|
| billing | shopify, not_checked, outside_shopify | shopify: billed through Shopify App Pricing and checked. not_checked: this deployment does not read plans. outside_shopify: a custom app's connection, billed by Growth Dept directly. |
| state | active, none, unknown, null or null | active: the store has a plan. none: it has not chosen one. unknown: Shopify did not answer; try again. |
| name | string or null | The plan's name in Shopify. |
| handle | string or null | The plan's handle in Shopify. |
| billing_ | string or null | EVERY_30_DAYS or ANNUAL. |
| trial_ | datetime or null | When the free trial ends, during a trial. |
| current_ | datetime or null | When the current billing period ends. |
| cancel_ | boolean | True when the plan stops at the end of the current period. |
| plans_ | string or null | Shopify's page for choosing or changing the plan. Open it at the top level of the Shopify admin. |
| checked_ | datetime or null | When Shopify was asked. |
| message | string or null | Why the state is none or unknown, in plain words. |
The ShopifyPlanPreview object · 7 fields
What an action would do, worked out without storing a plan.
| Field | Type | Description |
|---|---|---|
| preview | boolean | Always true: nothing was stored. |
| action | refund, cancel, duplicate, replacement, edit_address, resend_confirmation, edit_note, edit_tags, edit_order, remove_item, replace_item, create_order, sync_customer, create_discount | |
| label | string | |
| money | boolean | Moves money or gives goods away. |
| integration_ | integer | |
| order | object or null | The order, for an order action: id and name. |
| effect | any | What the action would do, as in a plan, with its figures. |
The ShopifyMetafields object · 3 fields
| Field | Type | Description |
|---|---|---|
| order | object | The order, for an order's metafields. |
| shopify_ | integer or string or null | The Shopify customer, for a customer's metafields. |
| data | array of object |
The ShopifyCustomerSummary object · 3 fields
A customer's data from every connected store.
| Field | Type | Description |
|---|---|---|
| customer_ | integer | |
| stores | array of ShopifyStoreSummary | |
| problem | object or null | Set when no store could be read and one the helpdesk holds needs attention (its key or token was refused): integration_id, shop, status, message and fleet (true for a store linked through Growth Dept). |
The ShopifyOrderDelivery object · 4 fields
| Field | Type | Description |
|---|---|---|
| order | object | |
| estimated_ | datetime or null | The latest expected date of the shipments still on their way. |
| delivered_ | datetime or null | When the last shipment arrived, once all have. |
| shipments | array of object |
The ShopifyOrderReturns object · 2 fields
| Field | Type | Description |
|---|---|---|
| order | object | |
| data | array of object |
The ShopifyOrderTimeline object · 2 fields
| Field | Type | Description |
|---|---|---|
| order | object | |
| data | array of object |
List connected Shopify stores
GET/api/integrations/shopify
Every Shopify store this helpdesk has connected, with its status, granted scopes and action settings, and in setup the scopes and addresses a store's app needs. For a Growth Dept fleet brand, setup.fleet names the brand and the store is linked by Growth Dept rather than here. Tokens are never returned.
Response
200 · The stores, and what connecting one needs. · list of ShopifyStore
Request
curl \
"https://cs.growthdept.ai/api/integrations/shopify?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/integrations/shopify",
"data": [
{
"id": 1,
"type": "email",
"name": "Demo Store",
"shop": "",
"shop_name": null,
"status": "active",
"active": true,
"install_type": "oauth",
"currency": "USD",
"timezone": "America/Los_Angeles",
"scopes": [
""
],
"missing_read_scopes": [
""
],
"missing_action_scopes": [
""
],
"missing_extra_scopes": [
""
],
"actions_enabled": false,
"agents_can_execute_money": false,
"webhooks": [
""
],
"webhook_note": null,
"fleet_slug": null,
"refresh": "webhooks",
"polled_datetime": "2026-11-04T09:41:12+00:00",
"poll_error": null,
"last_error": null,
"connected_datetime": "2026-11-04T09:41:12+00:00",
"checked_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"deactivated_datetime": null,
"admin_url": ""
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Connect a Shopify store with an access token
POST/api/integrations/shopify
Connects a store with the Admin API access token of a custom app installed on it. The token is checked against the store and must hold the read scopes listed in setup. Give the app's API secret key as well so the helpdesk can verify Shopify's change notifications. Connecting a store already in this helpdesk replaces its token.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| shoprequired | string | The store's myshopify.com domain or its admin URL. |
| access_ | string | The custom app's Admin API access token (shpat_...). |
| api_ | string or null | The custom app's API secret key, which signs its webhooks. |
Response
201 · The connected store. · ShopifyStore
Request
curl -X POST \
"https://cs.growthdept.ai/api/integrations/shopify" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"shop": "",
"access_token": ""
}'Response 201
{
"id": 1,
"type": "email",
"name": "Demo Store",
"shop": "",
"shop_name": null,
"status": "active",
"active": true,
"install_type": "oauth",
"currency": "USD",
"timezone": "America/Los_Angeles",
"scopes": [
""
],
"missing_read_scopes": [
""
],
"missing_action_scopes": [
""
],
"missing_extra_scopes": [
""
],
"actions_enabled": false,
"agents_can_execute_money": false,
"webhooks": [
""
],
"webhook_note": null,
"fleet_slug": null,
"refresh": "webhooks",
"polled_datetime": "2026-11-04T09:41:12+00:00",
"poll_error": null,
"last_error": null,
"connected_datetime": "2026-11-04T09:41:12+00:00",
"checked_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"deactivated_datetime": null,
"admin_url": ""
}List order action history
GET/api/shopify/actions
The order action log, newest first: every plan, attempt and outcome, with the order, amount, agent and reason. Filter by ticket, customer or Shopify order id.
Parameters
| Name | Description |
|---|---|
| ticket_ | |
| customer_ | |
| order_ | |
| limitquery · string | At most 100; 30 by default. |
Response
200 · Log entries. · list of ShopifyActionLogEntry
Request
curl \
"https://cs.growthdept.ai/api/shopify/actions?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/shopify/actions",
"data": [
{
"id": 1,
"integration_id": 2,
"plan_id": null,
"action": "",
"outcome": "planned",
"order_id": null,
"order_name": null,
"ticket_id": 4182,
"customer_id": 7311,
"user_id": 12,
"money": false,
"amount": null,
"currency": "USD",
"detail": {},
"created_datetime": "2026-11-04T09:41:12+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Finish installing the app
GET/api/shopify/callback
Shopify sends the browser here after the store owner approves the app. The signature, the install cookie and the signed-in person are checked, the token is stored, and the browser returns to the store settings page with a notice or an error.
Response
303 · A redirect back to the helpdesk's store settings.
Request
curl "https://cs.growthdept.ai/api/shopify/callback"Response 303
(no body)Install the app from Shopify
GET/api/shopify/install
Where an install started in Shopify (the app listing or the store admin) lands. Shopify signs the link; a signed-in helpdesk admin is sent on to Shopify's consent screen. Add helpdesk=<address> to choose the helpdesk when the person administers several.
Response
303 · A redirect to Shopify's consent screen, the sign-in page or the account page.
Request
curl "https://cs.growthdept.ai/api/shopify/install"Response 303
(no body)List the store's metafield definitions
GET/api/shopify/metafield-definitions
The metafields the store defines for customers, orders and draft orders (namespace, key, name, type), for the macro editor's Shopify metafields variables. A macro reads a value as {{ticket.customer.integrations.shopify.customer.metafields.<namespace>.<key>.value}}, or orders[0] or draft_orders[0] in place of customer.
Parameters
| Name | Description |
|---|---|
| integration_ | The store, when the helpdesk has more than one. |
Response
200 · Definitions by owner. · object
Request
curl \
"https://cs.growthdept.ai/api/shopify/metafield-definitions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Search the store's products
GET/api/shopify/products
Active products whose title or SKU matches search (all active products without it), up to 20, with the first variant's SKU and price, the stock Shopify tracks (null when it does not), an image and the product's storefront address. The reply box links a product with it.
Parameters
| Name | Description |
|---|---|
| searchquery · string | |
| integration_ | The store, when the helpdesk has more than one. |
Response
200 · Matching products. · object
Request
curl "https://cs.growthdept.ai/api/shopify/products" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Search the store's products and their variants
GET/api/shopify/variants
Active products whose title, SKU or barcode match query, with every variant's price, stock (null when Shopify does not count it) and whether it is for sale; up to 10 products. Draft and archived products are left out, as Gorgias's product search leaves them out. The Create order and Edit order dialogs use it; the reply box's product insert uses GET /api/shopify/products.
Parameters
| Name | Description |
|---|---|
| queryquery · string | Words from the title, a SKU or a barcode. |
| integration_ | The store, when the helpdesk has more than one. |
Response
200 · Matching products. · list of ShopifyProduct
Request
curl \
"https://cs.growthdept.ai/api/shopify/variants?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/shopify/variants",
"data": [
{
"id": 1,
"title": "",
"image_url": null,
"tracks_inventory": false,
"variants": [
{
"id": 1,
"title": "",
"sku": null,
"price": null,
"currency": "USD",
"available": false,
"stock": null
}
]
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Receive Shopify notifications
POST/api/shopify/webhooks
Shopify posts order, customer, uninstall and privacy notifications here, signed with the app's secret. Order and customer changes refresh the cached data of customers who have it; privacy requests remove or report what the helpdesk holds from the store. An unsigned or wrongly signed request gets 401.
Response
200 · Received. · object
Request
curl -X POST "https://cs.growthdept.ai/api/shopify/webhooks"Response 200
{}Get a connected Shopify store
GET/api/integrations/shopify/{id}
One store's status, granted scopes, notification setup and action settings, as last checked. Use the check endpoint to read them from Shopify again.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The store. · ShopifyStore
Request
curl \
"https://cs.growthdept.ai/api/integrations/shopify/2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"type": "email",
"name": "Demo Store",
"shop": "",
"shop_name": null,
"status": "active",
"active": true,
"install_type": "oauth",
"currency": "USD",
"timezone": "America/Los_Angeles",
"scopes": [
""
],
"missing_read_scopes": [
""
],
"missing_action_scopes": [
""
],
"missing_extra_scopes": [
""
],
"actions_enabled": false,
"agents_can_execute_money": false,
"webhooks": [
""
],
"webhook_note": null,
"fleet_slug": null,
"refresh": "webhooks",
"polled_datetime": "2026-11-04T09:41:12+00:00",
"poll_error": null,
"last_error": null,
"connected_datetime": "2026-11-04T09:41:12+00:00",
"checked_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"deactivated_datetime": null,
"admin_url": ""
}Change a store's settings
PUT/api/integrations/shopify/{id}
Renames the store or turns order actions on or off. Turning actions on needs the write scopes listed in setup. agents_can_execute_money lets agents, not only admins, run refunds, cancellations and free replacements.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| actions_ | boolean | |
| agents_ | boolean |
Response
200 · The store after the change. · ShopifyStore
Request
curl -X PUT \
"https://cs.growthdept.ai/api/integrations/shopify/2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"actions_enabled": false,
"agents_can_execute_money": false
}'Response 200
{
"id": 1,
"type": "email",
"name": "Demo Store",
"shop": "",
"shop_name": null,
"status": "active",
"active": true,
"install_type": "oauth",
"currency": "USD",
"timezone": "America/Los_Angeles",
"scopes": [
""
],
"missing_read_scopes": [
""
],
"missing_action_scopes": [
""
],
"missing_extra_scopes": [
""
],
"actions_enabled": false,
"agents_can_execute_money": false,
"webhooks": [
""
],
"webhook_note": null,
"fleet_slug": null,
"refresh": "webhooks",
"polled_datetime": "2026-11-04T09:41:12+00:00",
"poll_error": null,
"last_error": null,
"connected_datetime": "2026-11-04T09:41:12+00:00",
"checked_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"deactivated_datetime": null,
"admin_url": ""
}Disconnect a Shopify store
DELETE/api/integrations/shopify/{id}
Removes the helpdesk's notifications from the store, forgets the token and deletes the store data cached on customers. Plans and the action log are kept. Uninstall the app in Shopify as well if it should lose access there.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
204 · Disconnected.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/integrations/shopify/2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Start installing the Shopify app on a store
POST/api/integrations/shopify/install
Returns the address of Shopify's consent screen for the store and sets a short-lived cookie that the callback checks. Open the address in the same browser. Available when this deployment has a Shopify app; otherwise connect with an access token. With actions true the app also asks for the scopes order actions need.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| shoprequired | string | The store's myshopify.com domain or its admin URL. |
| actions | boolean | Ask for the scopes refunds, cancellations and drafts need. |
Response
200 · Where to send the browser. · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/integrations/shopify/install" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"shop": ""
}'Response 200
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"scopes": [
""
]
}Get a link to connect the store to a helpdesk
POST/api/shopify/embedded/link-ticket
Called by the app's page inside the Shopify admin, with the ID token as a bearer token like the session call. Returns the address of a page on Growth Dept Helpdesk, opened in a new tab, where an admin of a helpdesk links the store to it. The address carries a signed ticket naming the store; it works once and expires after ten minutes. When plans are checked, a store without an active plan gets 402 and a store whose plan Shopify did not confirm gets 503; choose a plan in Shopify, then ask again.
Response
200 · The link page's address. · ShopifyLinkTicket
Request
curl -X POST \
"https://cs.growthdept.ai/api/shopify/embedded/link-ticket"Response 200
{
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg",
"expires_in": 0
}Open the Shopify app
POST/api/shopify/embedded/session
Called by the app's page inside the Shopify admin with Authorization: Bearer and the ID token App Bridge issued (shopify.idToken()), not with an API key. The token's signature, audience, lifetime and store are checked. When the helpdesk holds no working access token for the store, the ID token is exchanged for an expiring offline token. Answers with the store's granted scopes, the helpdesk it is linked to and its plan, which Shopify charges through Shopify App Pricing. A confirmed plan is cached for a minute; fresh_plan=1 asks Shopify again. A token that fails a check gets 401 with X-Shopify-Retry-Invalid-Session-Request, so App Bridge retries once with a fresh one.
Parameters
| Name | Description |
|---|---|
| fresh_ | 1 to read the store's plan from Shopify instead of the cached copy.1 |
Response
200 · The store, the helpdesk it is linked to, and its plan. · ShopifyEmbeddedSession
Request
curl -X POST \
"https://cs.growthdept.ai/api/shopify/embedded/session"Response 200
{
"shop": "",
"shop_name": null,
"scopes": [
""
],
"missing_scopes": [
""
],
"missing_action_scopes": [
""
],
"token_exchanged": false,
"helpdesk": {
"name": "Demo Store",
"slug": "unassigned-shipping",
"inbox_url": "",
"settings_url": ""
},
"plan": {
"billing": "shopify",
"state": "active",
"name": "Demo Store",
"handle": null,
"billing_period": null,
"trial_ends_datetime": null,
"current_period_end_datetime": "2026-11-04T09:41:12+00:00",
"cancel_at_period_end": false,
"plans_url": null,
"checked_datetime": "2026-11-04T09:41:12+00:00",
"message": null
},
"plan_required": false
}Execute a planned store action for a customer
POST/api/shopify/execute/{action}
Runs a plan made by POST /api/shopify/plan/{action}. What the plan relied on is read again first (the customer's Shopify match, product prices and Shopify's total, whether a code is free); if it changed, nothing is sent and the answer is 409. Store actions need a Basic agent or above; an order marked as paid and a discount code also need an admin when the store's "Agents can run money actions" is off. Executing the same plan again returns its first result.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| actionrequiredpath · string | create_order | sync_customer | create_discount |
Body
| Field | Type | Description |
|---|---|---|
| plan_ | string | |
| confirm_ | boolean | Make another draft even though one was made for this order in the last 30 minutes. |
Response
200 · The plan with what Shopify made. · ShopifyPlan
Request
curl -X POST "https://cs.growthdept.ai/api/shopify/execute/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"plan_id": ""
}'Response 200
{
"billing": "shopify",
"state": "active",
"name": "Demo Store",
"handle": null,
"billing_period": null,
"trial_ends_datetime": null,
"current_period_end_datetime": "2026-11-04T09:41:12+00:00",
"cancel_at_period_end": false,
"plans_url": null,
"checked_datetime": "2026-11-04T09:41:12+00:00",
"message": null
}Plan a store action for a customer
POST/api/shopify/plan/{action}
Works out what a store action with no order to start from would do, without changing anything, and returns a plan to confirm with the execute endpoint. action is one of create_order, sync_customer, create_discount. Send ticket_id (or customer_id). Bodies: create_order {items: [{variant_id, quantity} or {title, price, quantity, taxable, requires_shipping}], note, tags, discount {type: fixed_amount|percentage, value, reason}, shipping {free} or {title, price}, taxes, outcome: draft|draft_invoice|paid|pending} for a customer already in Shopify (the total is Shopify's draftOrderCalculate); sync_customer {first_name, last_name, phone, address} creates the Shopify customer from the helpdesk profile's email when Shopify has none; create_discount {code, type: percentage|fixed_amount, value, ends_at, usage_limit, once_per_customer, customer_only, minimum_subtotal} (the code is made up when left out, and works for this customer only by default). Answers 409 with the reason when the action cannot be done.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| actionrequiredpath · string | create_order | sync_customer | create_discount |
Body
Any JSON value.
Response
201 · The plan. · ShopifyPlan
Request
curl -X POST "https://cs.growthdept.ai/api/shopify/plan/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 201
{
"billing": "shopify",
"state": "active",
"name": "Demo Store",
"handle": null,
"billing_period": null,
"trial_ends_datetime": null,
"current_period_end_datetime": "2026-11-04T09:41:12+00:00",
"cancel_at_period_end": false,
"plans_url": null,
"checked_datetime": "2026-11-04T09:41:12+00:00",
"message": null
}Preview a store action for a customer
POST/api/shopify/preview/{action}
Takes the same body as planning the action and answers with what it would do and Shopify's figures (for create_order: subtotal, discount, shipping, tax and total), without storing a plan or writing to the action log. action is one of create_order, sync_customer, create_discount.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| actionrequiredpath · string | create_order | sync_customer | create_discount |
Body
Any JSON value.
Response
200 · What the action would do. · ShopifyPlanPreview
Request
curl -X POST "https://cs.growthdept.ai/api/shopify/preview/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 200
{
"preview": false,
"action": "refund",
"label": "Reason for contact",
"money": false,
"integration_id": 2,
"order": {},
"effect": {}
}Check a store's access again
POST/api/integrations/shopify/{id}/check
Reads the store's name and the token's scopes from Shopify again and sets up any missing change notifications. Use it after adding scopes to the store's app. Answers 409 when Shopify no longer accepts the token.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The store as Shopify describes it now. · ShopifyStore
Request
curl -X POST \
"https://cs.growthdept.ai/api/integrations/shopify/2/check" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"type": "email",
"name": "Demo Store",
"shop": "",
"shop_name": null,
"status": "active",
"active": true,
"install_type": "oauth",
"currency": "USD",
"timezone": "America/Los_Angeles",
"scopes": [
""
],
"missing_read_scopes": [
""
],
"missing_action_scopes": [
""
],
"missing_extra_scopes": [
""
],
"actions_enabled": false,
"agents_can_execute_money": false,
"webhooks": [
""
],
"webhook_note": null,
"fleet_slug": null,
"refresh": "webhooks",
"polled_datetime": "2026-11-04T09:41:12+00:00",
"poll_error": null,
"last_error": null,
"connected_datetime": "2026-11-04T09:41:12+00:00",
"checked_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"deactivated_datetime": null,
"admin_url": ""
}Get a store's plan
GET/api/integrations/shopify/{id}/plan
The Growth Dept Helpdesk plan of a store connected through the Shopify app, as Shopify App Pricing reports it: the plan's name, any free trial, and Shopify's page for choosing or changing the plan. A store connected with a custom app's token is billed outside Shopify and answers billing outside_shopify. A confirmed plan is cached for a minute; refresh=true asks Shopify again.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| refreshquery · string | Ask Shopify now instead of using the cached copy.0, 1, true, false |
Response
200 · The store's plan. · ShopifyPlan
Request
curl \
"https://cs.growthdept.ai/api/integrations/shopify/2/plan" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"billing": "shopify",
"state": "active",
"name": "Demo Store",
"handle": null,
"billing_period": null,
"trial_ends_datetime": null,
"current_period_end_datetime": "2026-11-04T09:41:12+00:00",
"cancel_at_period_end": false,
"plans_url": null,
"checked_datetime": "2026-11-04T09:41:12+00:00",
"message": null
}Get a customer's Shopify metafields
GET/api/shopify/customers/{id}/metafields
The metafields of the Shopify customer matched to this helpdesk customer (namespace, key, the definition's name, type and value); empty when Shopify has no such customer. Gorgias calls this Load Customer Metafields and shows them in its sidebar.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| integration_ | The store, when the helpdesk has more than one. |
Response
200 · The customer's metafields. · ShopifyMetafields
Request
curl \
"https://cs.growthdept.ai/api/shopify/customers/1/metafields" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"order": {},
"shopify_customer_id": 0,
"data": [
{
"namespace": "",
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"name": "Demo Store",
"type": "email",
"value": ""
}
]
}Get a customer's Shopify data
GET/api/shopify/customers/{id}/summary
The Shopify customer matched to this helpdesk customer (by email, then phone), their lifetime spend, order count and tags, and their recent orders with items, fulfilment and tracking, payment status and refunds. Served from a copy kept for two minutes and read from Shopify again after that, or at once with refresh=true. The same data is stored on the customer under integrations.<store id>.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
| refreshquery · string | Read from Shopify now instead of using the copy.0, 1, true, false |
| integration_ | Only this store. |
Response
200 · The customer's data from each connected store. · ShopifyCustomerSummary
Request
curl \
"https://cs.growthdept.ai/api/shopify/customers/1/summary" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"customer_id": 7311,
"stores": [
{
"integration": {
"id": 1,
"name": "Demo Store",
"shop": "",
"status": "open",
"actions_enabled": false,
"agents_can_execute_money": false,
"currency": "USD",
"admin_url": ""
},
"matched_by": "email",
"shopify_customer_id": null,
"customer": {},
"orders": [
{}
],
"fetched_datetime": "2026-11-04T09:41:12+00:00",
"stale": false,
"error": null
}
],
"problem": {}
}Change a customer's Shopify tags
POST/api/shopify/customers/{id}/tags
Adds and removes tags on the Shopify customer matched to this helpdesk customer, at once and without a plan, as the ticket sidebar does. Tags already there (in any case) are not added again; a tag both added and removed is added. Needs order actions on for the store and the write_customers scope. Answers with the Shopify customer's tags afterwards.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| integration_ | integer | The store, when the helpdesk has more than one. |
| add | array of string | Tags to add to the Shopify customer. |
| remove | array of string | Tags to take off the Shopify customer. |
Response
200 · The customer's tags in Shopify now. · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/shopify/customers/1/tags" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"integration_id": 2,
"add": [
""
],
"remove": [
""
]
}'Response 200
{}Get an order's delivery dates
GET/api/shopify/orders/{id}/delivery
When the order's shipments were sent, are expected and arrived, with tracking, from Shopify's fulfilments and the carriers' updates. estimated_delivery_datetime is the latest expected date of the shipments still on their way. Gorgias calls this Get Delivery Date. The order must belong to the ticket's customer.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · string | Shopify's numeric order id. |
| ticket_ | The ticket; its customer must own the order. |
| customer_ | The helpdesk customer, when there is no ticket. |
| integration_ | The store, when the helpdesk has more than one. |
Response
200 · Get an order's delivery dates. · ShopifyOrderDelivery
Request
curl \
"https://cs.growthdept.ai/api/shopify/orders/1/delivery" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"order": {
"id": 1,
"name": "Demo Store",
"fulfillment_status": null
},
"estimated_delivery_datetime": "2026-11-04T09:41:12+00:00",
"delivered_datetime": "2026-11-04T09:41:12+00:00",
"shipments": [
{
"name": "Demo Store",
"status": "open",
"shipped_datetime": "2026-11-04T09:41:12+00:00",
"in_transit_datetime": "2026-11-04T09:41:12+00:00",
"estimated_delivery_datetime": "2026-11-04T09:41:12+00:00",
"delivered_datetime": "2026-11-04T09:41:12+00:00",
"tracking": [
{
"company": null,
"number": null,
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
]
}Get an order's metafields
GET/api/shopify/orders/{id}/metafields
The order's metafields in Shopify (namespace, key, the definition's name, type and value). Gorgias calls this Retrieve Order Metafields and shows them on the order in its sidebar. The order must belong to the ticket's customer.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · string | Shopify's numeric order id. |
| ticket_ | The ticket; its customer must own the order. |
| customer_ | The helpdesk customer, when there is no ticket. |
| integration_ | The store, when the helpdesk has more than one. |
Response
200 · Get an order's metafields. · ShopifyMetafields
Request
curl \
"https://cs.growthdept.ai/api/shopify/orders/1/metafields" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"order": {},
"shopify_customer_id": 0,
"data": [
{
"namespace": "",
"key": "7c1e0b4f2a9d6e3b8a51f0c2d7e4b9a6",
"name": "Demo Store",
"type": "email",
"value": ""
}
]
}Get an order's returns
GET/api/shopify/orders/{id}/returns
The order's returns in Shopify, newest first: each return's status, the items with the reason and notes, how many were refunded, and the return parcel's tracking. Gorgias calls this Retrieve Order Returns. The order must belong to the ticket's customer. Needs read_returns on the store's app; without it the answer is 502 with the reason.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · string | Shopify's numeric order id. |
| ticket_ | The ticket; its customer must own the order. |
| customer_ | The helpdesk customer, when there is no ticket. |
| integration_ | The store, when the helpdesk has more than one. |
Response
200 · The order's returns. · ShopifyOrderReturns
Request
curl \
"https://cs.growthdept.ai/api/shopify/orders/1/returns" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"order": {
"id": 1,
"name": "Demo Store",
"return_status": null
},
"data": [
{
"id": null,
"name": "Demo Store",
"status": "open",
"created_datetime": "2026-11-04T09:41:12+00:00",
"closed_datetime": null,
"quantity": 0,
"items": [
{
"title": "",
"quantity": 0,
"refunded_quantity": 0,
"reason": null,
"reason_note": null,
"customer_note": null
}
],
"tracking": [
{
"company": null,
"number": null,
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
]
}Get an order's timeline
GET/api/shopify/orders/{id}/timeline
The order's timeline in Shopify, newest first: staff comments in full (with attachments) and the events Shopify records (payments, fulfilments, edits, emails). Gorgias calls this Fetch Order Comment Timeline. The order must belong to the ticket's customer.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · string | Shopify's numeric order id. |
| ticket_ | The ticket; its customer must own the order. |
| customer_ | The helpdesk customer, when there is no ticket. |
| integration_ | The store, when the helpdesk has more than one. |
Response
200 · Get an order's timeline. · ShopifyOrderTimeline
Request
curl \
"https://cs.growthdept.ai/api/shopify/orders/1/timeline" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"order": {
"id": 1,
"name": "Demo Store"
},
"data": [
{
"id": null,
"kind": "comment",
"created_datetime": "2026-11-04T09:41:12+00:00",
"message": "",
"author": null,
"app": null,
"action": null,
"attachments": [
{
"name": "Demo Store",
"url": "https://cs.growthdept.ai/files/7Qm2xk9Lr4/parcel-photo.jpg"
}
]
}
]
}Execute a planned order action
POST/api/shopify/orders/{id}/execute/{action}
Runs a plan made by the plan endpoint. The order is read again first: if anything the plan relied on changed (amounts, quantities, status, address), nothing is sent and the answer is 409. Store actions need a Basic agent or above, as in Gorgias. Refunds, cancellations, free replacements and orders marked as paid also need an admin when the store's "Agents can run money actions" is off. Executing the same plan again returns its first result with replayed true. On success the ticket gets an internal note and an event.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · string | Shopify's numeric order id. |
| actionrequiredpath · string | refund | cancel | duplicate | replacement | edit_address | resend_confirmation | edit_note | edit_tags | edit_order | remove_item | replace_item |
Body
| Field | Type | Description |
|---|---|---|
| plan_ | string | |
| confirm_ | boolean | Make another draft even though one was made for this order in the last 30 minutes. |
Response
200 · The plan with what Shopify made. · ShopifyPlan
Request
curl -X POST \
"https://cs.growthdept.ai/api/shopify/orders/1/execute/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"plan_id": ""
}'Response 200
{
"billing": "shopify",
"state": "active",
"name": "Demo Store",
"handle": null,
"billing_period": null,
"trial_ends_datetime": null,
"current_period_end_datetime": "2026-11-04T09:41:12+00:00",
"cancel_at_period_end": false,
"plans_url": null,
"checked_datetime": "2026-11-04T09:41:12+00:00",
"message": null
}Plan an order action
POST/api/shopify/orders/{id}/plan/{action}
Works out exactly what an action on a Shopify order would do, without changing anything, and returns a plan to show before confirming. action is one of refund, cancel, duplicate, replacement, edit_address, resend_confirmation, edit_note, edit_tags, edit_order, remove_item, replace_item. id is Shopify's order id. Send ticket_id (or customer_id): the order must belong to that customer. Refund amounts are Shopify's own suggested refund in the currency the customer paid in. Bodies: refund {full, line_items: [{id, quantity}], shipping, restock, notify, note} (full refunds every item still refundable and the shipping charge; line_items refunds those items, plus the shipping charge when shipping is true; shipping: true without line_items refunds only the shipping charge; an empty body is Shopify's own suggestion, which covers the items but not the shipping charge); cancel {reason: customer|declined|fraud|inventory|staff|other, refund, restock, notify, staff_note}; duplicate {line_items, note}; replacement {line_items: [{id, quantity, variant_id}], reason}; edit_address {address: {first_name, last_name, company, address1, address2, city, province_code, country_code, zip, phone}}; resend_confirmation {}; edit_order {add: [{variant_id, quantity} or {title, price, quantity, taxable, requires_shipping}], set: [{line_id, quantity, restock}], reason, notify} (Shopify order editing: the plan stages the edit to read Shopify's new total, executing stages it again and commits it); remove_item {line_items: [{id, quantity}], restock, reason, notify}; replace_item {line_item_id, variant_id, quantity, restock, reason, notify}. Refund and cancel also take amount, an amount of the agent's choosing in the currency the customer paid in (refund: alone, it refunds that amount without marking items refunded). duplicate takes the Create order form too (items, note, tags, discount {type: fixed_amount|percentage, value, reason}, shipping {free} or {title, price}, taxes, outcome: draft|draft_invoice|paid|pending), which is how the sidebar's Duplicate works; replacement takes outcome: order to make the free order at once. A plan can be executed for 15 minutes. Answers 409 with the reason when the action cannot be done on this order.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · string | Shopify's numeric order id. |
| actionrequiredpath · string | refund | cancel | duplicate | replacement | edit_address | resend_confirmation | edit_note | edit_tags | edit_order | remove_item | replace_item |
Body
Any JSON value.
Response
201 · The plan. · ShopifyPlan
Request
curl -X POST \
"https://cs.growthdept.ai/api/shopify/orders/1/plan/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 201
{
"billing": "shopify",
"state": "active",
"name": "Demo Store",
"handle": null,
"billing_period": null,
"trial_ends_datetime": null,
"current_period_end_datetime": "2026-11-04T09:41:12+00:00",
"cancel_at_period_end": false,
"plans_url": null,
"checked_datetime": "2026-11-04T09:41:12+00:00",
"message": null
}Preview an order action
POST/api/shopify/orders/{id}/preview/{action}
Takes the same body as planning the action and answers with what it would do and Shopify's figures for it (effect, and effect.figures: for a refund or cancellation Shopify's figure for what is picked and the most that can still be refunded), without storing a plan or writing to the action log. Dialogs call it while an agent changes quantities. action is one of refund, cancel, duplicate, replacement, edit_address, resend_confirmation, edit_note, edit_tags, edit_order, remove_item, replace_item.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · string | Shopify's numeric order id. |
| actionrequiredpath · string | refund | cancel | duplicate | replacement | edit_address | resend_confirmation | edit_note | edit_tags | edit_order | remove_item | replace_item |
Body
Any JSON value.
Response
200 · What the action would do. · ShopifyPlanPreview
Request
curl -X POST \
"https://cs.growthdept.ai/api/shopify/orders/1/preview/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Response 200
{
"preview": false,
"action": "refund",
"label": "Reason for contact",
"money": false,
"integration_id": 2,
"order": {},
"effect": {}
}SLA policies
SLA policies set first response and resolution targets for the tickets on their channels that match their conditions. The app reads and changes them with the signed-in session; an API key gets 403 here, which keeps these paths compatible with Gorgias.
List SLA policies
GET/api/sla-policies
The policies that are not deleted, in the order they are checked (lowest priority first). For the app's own pages: an API key gets 403, as on Gorgias.
Parameters
| Name | Description |
|---|---|
| target_ | Only policies for this channel. |
Response
200 · The policies. · list of object
Request
curl \
"https://cs.growthdept.ai/api/sla-policies?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/sla-policies",
"data": [
{}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Create an SLA policy
POST/api/sla-policies
Adds a policy ahead of the others. First response must be shorter than resolution, voice can't share a policy with other channels, and a helpdesk has one voice policy. Admins only; session only.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| metrics | array of object | |
| active | boolean | |
| target_ | array of string | |
| business_ | boolean | |
| filters | array of object | |
| target | number or null |
Response
201 · The new policy. · object
Request
curl -X POST "https://cs.growthdept.ai/api/sla-policies" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"target_channels": [
""
]
}'Response 201
{}Get an SLA policy
GET/api/sla-policies/{uuid}
One policy, deleted ones included (archived_datetime set). Session only.
Parameters
| Name | Description |
|---|---|
| uuidrequiredpath · string | The policy's uuid. |
Response
200 · The policy. · object
Request
curl "https://cs.growthdept.ai/api/sla-policies/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Update an SLA policy
PUT/api/sla-policies/{uuid}
Changes the policy, turns it on or off (active), or moves it (priority). Admins only; session only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| uuidrequiredpath · string | The policy's uuid. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| metrics | array of object | |
| active | boolean | |
| target_ | array of string | |
| business_ | boolean | |
| filters | array of object | |
| target | number or null | |
| priority | number or string |
Response
202 · The policy after the change. · object
Request
curl -X PUT "https://cs.growthdept.ai/api/sla-policies/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"metrics": [
{
"name": "FRT",
"threshold": 0,
"unit": "second"
}
],
"active": true
}'Response 202
{}Delete (archive) an SLA policy
PUT/api/sla-policies/{uuid}/archive
Removes the policy from the list and from new tickets. Tickets it already covers keep their SLA, and reports keep counting them. Admins only; session only.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| uuidrequiredpath · string | The policy's uuid. |
Response
202 · Archived; no body. · object
Request
curl -X PUT \
"https://cs.growthdept.ai/api/sla-policies/1/archive" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 202
{}SMS
SMS lines (one per number), and the numbers that replied STOP. Replies to an SMS ticket go out as texts through the ticket messages endpoint; a number that opted out is never texted until it replies START.
The SmsLine object · 5 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| name | string | |
| phone_ | integer | |
| phone_ | string | |
| registration | object | Listed lines only: the number's carrier registration. |
The SmsOptOut object · 4 fields
| Field | Type | Description |
|---|---|---|
| phone_ | string | |
| opted_ | datetime or null | |
| keyword | string or null | |
| source | keyword, carrier, agent, import |
The CarrierRegistration object · 26 fields
A 10DLC registration (local US numbers) or toll-free verification. Growth Dept reviews it, sends it to the carriers and pays every fee.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| kind | ten_dlc, toll_free | |
| status | draft, in_review, sending, brand_pending, campaign_pending, approved, rejected, withdrawn | draft: not sent. in_review: with Growth Dept. sending: approved, on its way. brand_pending: The Campaign Registry is checking the company. campaign_pending: with the carriers. approved. rejected: turned down; edit and send again. withdrawn. |
| status_ | string | |
| status_ | string | What the status means and what happens next. |
| status_ | string or null | The latest step, in a sentence. |
| details | object | The business and campaign details. Below admin, the EIN and the contact's email and phone are masked. |
| phone_ | array of object | |
| problems | object | What stops it being sent, for a draft or a turned-down one. |
| warnings | object | What often gets a registration turned down, without stopping it. |
| review_ | string or null | Growth Dept's note when it sent the registration back. |
| failure_ | string or null | Why the carriers or Telnyx turned it down. |
| failure_ | array of string | Details fields the carriers' feedback points at. |
| carrier | object | |
| history | array of object | |
| fees | object | What the carriers charge Growth Dept for it. Never billed to the helpdesk. |
| can_ | boolean | |
| can_ | boolean | |
| can_ | boolean | |
| submitted_ | datetime or null | |
| reviewed_ | datetime or null | |
| sent_ | datetime or null | |
| approved_ | datetime or null | |
| rejected_ | datetime or null | |
| created_ | datetime or null | |
| updated_ | datetime or null |
List SMS lines
GET/api/sms/lines
Each SMS line receives and sends texts on one number, with whether its number is registered with US carriers (registration.state and a sentence saying what that means for texting). They also appear in GET /api/integrations as type sms.
Response
200 · The lines. · list of SmsLine
Request
curl "https://cs.growthdept.ai/api/sms/lines?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/sms/lines",
"data": [
{
"id": 1,
"name": "Demo Store",
"phone_number_id": 0,
"phone_number": "",
"registration": {
"state": "",
"registration_id": null,
"kind": null,
"sentence": null
}
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Create an SMS line
POST/api/sms/lines
Puts an SMS line on one of the helpdesk's numbers. Texts to US numbers from a local number also need its carrier registration (Settings, SMS, Carrier registration).
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| phone_ | integer |
Response
201 · The line. · SmsLine
Request
curl -X POST "https://cs.growthdept.ai/api/sms/lines" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number_id": 0
}'Response 201
{
"id": 1,
"name": "Demo Store",
"phone_number_id": 0,
"phone_number": "",
"registration": {
"state": "",
"registration_id": null,
"kind": null,
"sentence": null
}
}List numbers that opted out of texts
GET/api/sms/opt-outs
Numbers that replied STOP (or that the carrier reports as opted out), newest first. Nothing is texted to them until they reply START; there is no way to remove one by hand. phone_number checks a single number.
Parameters
| Name | Description |
|---|---|
| phone_ |
Response
200 · Up to 500 numbers. · list of SmsOptOut
Request
curl \
"https://cs.growthdept.ai/api/sms/opt-outs?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/sms/opt-outs",
"data": [
{
"phone_number": "",
"opted_out_datetime": "2026-11-04T09:41:12+00:00",
"keyword": null,
"source": "keyword"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}List carrier registrations
GET/api/telephony/registrations
The helpdesk's 10DLC registrations and toll-free verifications, newest first, withdrawn ones included. Below admin, the EIN and the contact's email and phone are masked.
Response
200 · The registrations. · list of CarrierRegistration
Request
curl \
"https://cs.growthdept.ai/api/telephony/registrations?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/telephony/registrations",
"data": [
{
"id": 1,
"kind": "ten_dlc",
"status": "draft",
"status_label": "",
"status_explanation": "",
"status_detail": null,
"details": {},
"phone_numbers": [
{
"id": 1,
"phone_number": null,
"type": "email",
"status": "open",
"assignment_status": null
}
],
"problems": {},
"warnings": {},
"review_note": null,
"failure_reasons": null,
"failure_fields": [
""
],
"carrier": {
"brand_status": null,
"identity_status": null,
"campaign_status": null,
"toll_free_status": null
},
"history": [
{
"at": "",
"status": "open",
"note": ""
}
],
"fees": {
"paid_by": "growth_dept",
"paid_usd": "",
"schedule": [
{}
],
"source": ""
},
"can_edit": false,
"can_submit": false,
"can_withdraw": false,
"submitted_datetime": "2026-11-04T09:41:12+00:00",
"reviewed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"approved_datetime": "2026-11-04T09:41:12+00:00",
"rejected_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Start a carrier registration
POST/api/telephony/registrations
Starts a draft, prefilled from the helpdesk (name, website, the organization owner as contact, the support mailbox, the linked Shopify store) with suggested wording for a support line. The EIN and legal name are left for you. One registration of each kind can be in progress at a time. Demo helpdesks are refused.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| kindrequired | ten_dlc, toll_free | |
| details | object | Fields to set on top of the prefilled details. |
| phone_ | array of integer | Defaults to every active number of the right kind not on another registration. |
Response
201 · The draft. · CarrierRegistration
Request
curl -X POST \
"https://cs.growthdept.ai/api/telephony/registrations" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "ten_dlc"
}'Response 201
{
"id": 1,
"kind": "ten_dlc",
"status": "draft",
"status_label": "",
"status_explanation": "",
"status_detail": null,
"details": {},
"phone_numbers": [
{
"id": 1,
"phone_number": null,
"type": "email",
"status": "open",
"assignment_status": null
}
],
"problems": {},
"warnings": {},
"review_note": null,
"failure_reasons": null,
"failure_fields": [
""
],
"carrier": {
"brand_status": null,
"identity_status": null,
"campaign_status": null,
"toll_free_status": null
},
"history": [
{
"at": "",
"status": "open",
"note": ""
}
],
"fees": {
"paid_by": "growth_dept",
"paid_usd": "",
"schedule": [
{}
],
"source": ""
},
"can_edit": false,
"can_submit": false,
"can_withdraw": false,
"submitted_datetime": "2026-11-04T09:41:12+00:00",
"reviewed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"approved_datetime": "2026-11-04T09:41:12+00:00",
"rejected_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Get an SMS line
GET/api/sms/lines/{id}
One SMS line with the number it sends and receives on.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The SMS line's id. |
Response
200 · The line. · SmsLine
Request
curl "https://cs.growthdept.ai/api/sms/lines/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"name": "Demo Store",
"phone_number_id": 0,
"phone_number": "",
"registration": {
"state": "",
"registration_id": null,
"kind": null,
"sentence": null
}
}Rename an SMS line
PUT/api/sms/lines/{id}
Changes the name agents see.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The SMS line's id. |
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string |
Response
200 · The line. · SmsLine
Request
curl -X PUT "https://cs.growthdept.ai/api/sms/lines/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store"
}'Response 200
{
"id": 1,
"name": "Demo Store",
"phone_number_id": 0,
"phone_number": "",
"registration": {
"state": "",
"registration_id": null,
"kind": null,
"sentence": null
}
}Delete an SMS line
DELETE/api/sms/lines/{id}
Texts to its number no longer reach the helpdesk. Its tickets stay.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The SMS line's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/sms/lines/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Get a carrier registration
GET/api/telephony/registrations/{id}
One registration with its status, what it means, the carriers' reasons if it was turned down, and its history.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The registration's id. |
Response
200 · The registration. · CarrierRegistration
Request
curl \
"https://cs.growthdept.ai/api/telephony/registrations/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"kind": "ten_dlc",
"status": "draft",
"status_label": "",
"status_explanation": "",
"status_detail": null,
"details": {},
"phone_numbers": [
{
"id": 1,
"phone_number": null,
"type": "email",
"status": "open",
"assignment_status": null
}
],
"problems": {},
"warnings": {},
"review_note": null,
"failure_reasons": null,
"failure_fields": [
""
],
"carrier": {
"brand_status": null,
"identity_status": null,
"campaign_status": null,
"toll_free_status": null
},
"history": [
{
"at": "",
"status": "open",
"note": ""
}
],
"fees": {
"paid_by": "growth_dept",
"paid_usd": "",
"schedule": [
{}
],
"source": ""
},
"can_edit": false,
"can_submit": false,
"can_withdraw": false,
"submitted_datetime": "2026-11-04T09:41:12+00:00",
"reviewed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"approved_datetime": "2026-11-04T09:41:12+00:00",
"rejected_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Change a carrier registration
PUT/api/telephony/registrations/{id}
Changes the details or numbers of a draft or a turned-down registration. On an approved 10DLC registration, send phone_number_ids with new numbers added to put them on its campaign. Anything else is refused while it is with Growth Dept or the carriers.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The registration's id. |
Body
| Field | Type | Description |
|---|---|---|
| details | object | |
| phone_ | array of integer | The helpdesk's numbers to register: local US numbers for ten_dlc, toll-free numbers (up to 5) for toll_free. |
Response
200 · The registration. · CarrierRegistration
Request
curl -X PUT \
"https://cs.growthdept.ai/api/telephony/registrations/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"details": {
"legal_name": "",
"display_name": "",
"ein": "",
"entity_type": "PRIVATE_PROFIT",
"stock_symbol": "",
"stock_exchange": "NASDAQ",
"vertical": "AGRICULTURE",
"street": "",
"city": "",
"state": "",
"postal_code": "",
"country": "US",
"website": "",
"contact": {
"first_name": "",
"last_name": "",
"email": "maya.okafor@example.com",
"phone": ""
},
"use_case": "CUSTOMER_CARE",
"sub_use_cases": [
"CUSTOMER_CARE"
],
"description": "",
"message_flow": "",
"samples": [
""
],
"help_message": "",
"optout_message": "",
"privacy_url": "",
"terms_url": "",
"tf_use_case": "2FA",
"monthly_volume": "10",
"opt_in_image_urls": [
""
],
"use_case_summary": "",
"production_message": "",
"additional_information": ""
},
"phone_number_ids": [
0
]
}'Response 200
{
"id": 1,
"kind": "ten_dlc",
"status": "draft",
"status_label": "",
"status_explanation": "",
"status_detail": null,
"details": {},
"phone_numbers": [
{
"id": 1,
"phone_number": null,
"type": "email",
"status": "open",
"assignment_status": null
}
],
"problems": {},
"warnings": {},
"review_note": null,
"failure_reasons": null,
"failure_fields": [
""
],
"carrier": {
"brand_status": null,
"identity_status": null,
"campaign_status": null,
"toll_free_status": null
},
"history": [
{
"at": "",
"status": "open",
"note": ""
}
],
"fees": {
"paid_by": "growth_dept",
"paid_usd": "",
"schedule": [
{}
],
"source": ""
},
"can_edit": false,
"can_submit": false,
"can_withdraw": false,
"submitted_datetime": "2026-11-04T09:41:12+00:00",
"reviewed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"approved_datetime": "2026-11-04T09:41:12+00:00",
"rejected_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Withdraw a carrier registration
DELETE/api/telephony/registrations/{id}
Withdraws a draft, or a turned-down registration you will not send again. Its record stays, marked withdrawn.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The registration's id. |
Response
204 · Withdrawn.
Request
curl -X DELETE \
"https://cs.growthdept.ai/api/telephony/registrations/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Preview a new registration's details
GET/api/telephony/registrations/prefill
What a new registration of this kind would start with, and the numbers it would cover, without saving anything. kind is ten_dlc or toll_free.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| kindrequiredquery · string | ten_dlc, toll_free |
Response
200 · The prefilled details, the eligible numbers and what is still missing. · object
Request
curl \
"https://cs.growthdept.ai/api/telephony/registrations/prefill?kind=ten_dlc" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Send a carrier registration for review
POST/api/telephony/registrations/{id}/submit
Checks the details and numbers and sends the registration to Growth Dept for review. A 400 lists each field to fix. Growth Dept approves it and sends it to the carriers, or sends it back as a draft with a note.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The registration's id. |
Response
200 · The registration, in review. · CarrierRegistration
Request
curl -X POST \
"https://cs.growthdept.ai/api/telephony/registrations/1/submit" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"kind": "ten_dlc",
"status": "draft",
"status_label": "",
"status_explanation": "",
"status_detail": null,
"details": {},
"phone_numbers": [
{
"id": 1,
"phone_number": null,
"type": "email",
"status": "open",
"assignment_status": null
}
],
"problems": {},
"warnings": {},
"review_note": null,
"failure_reasons": null,
"failure_fields": [
""
],
"carrier": {
"brand_status": null,
"identity_status": null,
"campaign_status": null,
"toll_free_status": null
},
"history": [
{
"at": "",
"status": "open",
"note": ""
}
],
"fees": {
"paid_by": "growth_dept",
"paid_usd": "",
"schedule": [
{}
],
"source": ""
},
"can_edit": false,
"can_submit": false,
"can_withdraw": false,
"submitted_datetime": "2026-11-04T09:41:12+00:00",
"reviewed_datetime": "2026-11-04T09:41:12+00:00",
"sent_datetime": "2026-11-04T09:52:40+00:00",
"approved_datetime": "2026-11-04T09:41:12+00:00",
"rejected_datetime": "2026-11-04T09:41:12+00:00",
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Voice
Voice lines (one per number, each with its call flow), call queues, the agent's softphone (its sign-in token and the heartbeat that lets calls ring it), calling a customer, and acting on a live call: hold, recording, transfer and hang up.
The VoiceLine object · 7 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| name | string | |
| phone_ | integer | |
| phone_ | string | |
| settings | object | |
| flow | object | The call flow: {version: 1, steps: [...]}. Each step has an id and a type: time_rule, customer_lookup, play_message, ivr_menu, route_to_queue, route_to_line, forward, send_to_sms, voicemail or hang_up; branching steps hold their branches' steps. |
| warnings | array of object | Parts of the flow that may not work as meant. |
The VoiceQueue object · 14 fields
| Field | Type | Description |
|---|---|---|
| id | integer | |
| name | string | |
| enabled | boolean | |
| priority | boolean | Calls in priority queues ring before any others. |
| capacity | integer or null | Most callers waiting at once; null for no limit. |
| distribution | round_robin, broadcast | round_robin rings one agent at a time, longest idle first; broadcast rings every available agent. |
| ring_ | integer or null | Only this team's members are rung; null rings every available agent. |
| ring_ | integer | How long each agent is rung. |
| max_ | integer | How long a caller waits before the call flow moves on. |
| wrapup_ | boolean | |
| wrapup_ | integer | |
| hold_ | integer or null | An uploaded recording; null plays the built-in music. |
| waiting | integer | Callers waiting now. |
| lines | array of object | Voice lines whose call flow routes here. |
Agents who can take a call now
GET/api/voice/agents
Agents whose status is available, whose softphone is connected and who are not on or being rung for a call, longest idle first. The call bar's transfer list uses it.
Response
200 · The agents: {id, name}. · object
Request
curl "https://cs.growthdept.ai/api/voice/agents" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Call a customer
POST/api/voice/calls
Starts an outbound call from a voice line, as the agent making the request: their softphone rings first and answers by itself, then the customer's number is dialled and the two are connected when the customer picks up. Give ticket_id to call from a ticket (the customer's number is used unless to is sent), or customer_id or to for a new ticket. The agent's softphone must be connected.
Role: lite-agent or higher
Body
| Field | Type | Description |
|---|---|---|
| to | string | |
| customer_ | integer | |
| ticket_ | integer | |
| integration_ | integer |
Response
201 · The call, ringing. · VoiceCall
Request
curl -X POST "https://cs.growthdept.ai/api/voice/calls" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"integration_id": 2
}'Response 201
{
"id": 1,
"ticket_id": 4182,
"integration_id": 2,
"phone_number_id": null,
"customer_id": 7311,
"direction": "inbound",
"phone_number_source": "",
"phone_number_destination": "",
"status": "ringing",
"outcome": "answered",
"queue_id": null,
"user_id": 12,
"initiated_by_user_id": null,
"started_datetime": "2026-11-04T09:41:12+00:00",
"queued_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null,
"wait_time": null,
"talk_time": null,
"duration": null,
"recording": false,
"on_hold": false,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}List voice lines
GET/api/voice/lines
Each voice line answers one number and runs its call flow. Gorgias calls these phone integrations; they also appear in GET /api/integrations as type phone.
Response
200 · The lines. · list of VoiceLine
Request
curl "https://cs.growthdept.ai/api/voice/lines?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/voice/lines",
"data": [
{
"id": 1,
"name": "Demo Store",
"phone_number_id": 0,
"phone_number": "",
"settings": {
"recording": {
"inbound": false,
"outbound": false,
"notice": ""
},
"transcription": {
"calls": false,
"voicemail": false
},
"emoji": null
},
"flow": {
"version": 0,
"steps": [
{}
]
},
"warnings": [
{
"step_id": null,
"level": "",
"message": ""
}
]
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Create a voice line
POST/api/voice/lines
Puts a voice line on one of the helpdesk's numbers. Without a flow, the line starts with a default one: within business hours a greeting and the first queue (one called Everyone is made if there is none), then voicemail; outside them, voicemail.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| phone_ | integer | |
| settings | object | |
| flow | any |
Response
201 · The line, with warnings about its flow. · VoiceLine
Request
curl -X POST "https://cs.growthdept.ai/api/voice/lines" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number_id": 0
}'Response 201
{
"id": 1,
"name": "Demo Store",
"phone_number_id": 0,
"phone_number": "",
"settings": {
"recording": {
"inbound": false,
"outbound": false,
"notice": ""
},
"transcription": {
"calls": false,
"voicemail": false
},
"emoji": null
},
"flow": {
"version": 0,
"steps": [
{}
]
},
"warnings": [
{
"step_id": null,
"level": "",
"message": ""
}
]
}See calls right now
GET/api/voice/live
What the live calls page shows: each call queue with how many callers wait in it and the longest wait so far, every caller waiting, inbound calls still in the greeting or menu, calls in progress with their agent and how long they have run, and each agent's voice state (ready, on_call, wrap_up or not_ready). Durations are seconds up to now. Callers' numbers are included.
Response
200 · The calls and agents now. · object
Request
curl "https://cs.growthdept.ai/api/voice/live" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"now": "2026-11-04T09:41:12+00:00",
"timezone": "America/Los_Angeles",
"queues": [
{
"id": 1,
"name": "Demo Store",
"enabled": false,
"waiting": 0,
"longest_wait_secs": null
}
],
"waiting": [
{
"call_id": 0,
"queue_id": null,
"queue": null,
"line": null,
"caller": "",
"customer": null,
"customer_id": 7311,
"ticket_id": 4182,
"waited_secs": 0
}
],
"in_flow": 0,
"active": [
{
"call_id": 0,
"direction": "inbound",
"state": "talking",
"line": null,
"queue": null,
"agent_id": null,
"agent": null,
"caller": "",
"customer": null,
"customer_id": 7311,
"ticket_id": 4182,
"on_hold": false,
"recording": false,
"duration_secs": 0
}
],
"agents": [
{
"agent_id": 0,
"name": "Demo Store",
"state": "ready",
"call_id": null,
"wrap_up_secs": null
}
]
}List call queues
GET/api/voice/queues
Each queue with how many callers wait in it now and the lines that route to it.
Response
200 · The queues. · list of VoiceQueue
Request
curl \
"https://cs.growthdept.ai/api/voice/queues?limit=2" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"object": "list",
"uri": "/api/voice/queues",
"data": [
{
"id": 1,
"name": "Demo Store",
"enabled": false,
"priority": false,
"capacity": null,
"distribution": "round_robin",
"ring_team_id": null,
"ring_secs": 0,
"max_wait_secs": 0,
"wrapup_enabled": false,
"wrapup_secs": 0,
"hold_music_file_id": null,
"waiting": 0,
"lines": [
{
"id": 1,
"name": "Demo Store"
}
]
}
],
"meta": {
"prev_cursor": null,
"next_cursor": null
}
}Create a call queue
POST/api/voice/queues
Defaults: switched on, not priority, no capacity limit, round-robin, every available agent, 30 s per agent, 120 s wait, no wrap-up.
Role: admin or higher
Body
| Field | Type | Description |
|---|---|---|
| namerequired | string | |
| enabled | boolean | |
| priority | boolean | |
| capacity | integer or null | |
| distribution | round_robin, broadcast | |
| ring_ | integer or null | |
| ring_ | integer | |
| max_ | integer | |
| wrapup_ | boolean | |
| wrapup_ | integer | |
| hold_ | integer or null |
Response
201 · The queue. · VoiceQueue
Request
curl -X POST "https://cs.growthdept.ai/api/voice/queues" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store"
}'Response 201
{
"id": 1,
"name": "Demo Store",
"enabled": false,
"priority": false,
"capacity": null,
"distribution": "round_robin",
"ring_team_id": null,
"ring_secs": 0,
"max_wait_secs": 0,
"wrapup_enabled": false,
"wrapup_secs": 0,
"hold_music_file_id": null,
"waiting": 0,
"lines": [
{
"id": 1,
"name": "Demo Store"
}
]
}Voice SLA over a period
GET/api/voice/sla
The share of inbound calls answered within the voice SLA's threshold (the SLA policy whose channel is phone), between from and to (ISO dates, to excluded), against its target. A call counts unless the caller hung up within 10 seconds, and, when the policy counts business hours only, only if it came in during them. met is null without a voice SLA or without calls.
Parameters
| Name | Description |
|---|---|
| fromrequiredquery · string | |
| torequiredquery · string |
Response
200 · {policy, counted, satisfied, breached, rate, met}. · object
Request
curl "https://cs.growthdept.ai/api/voice/sla?from=&to=" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}The softphone's status
GET/api/voice/softphone
Whether the requesting agent can take calls here, the voice lines they can call from, whether their softphone counts as ready, and the calls ringing or connected to them now.
Response
200 · The status. · object
Request
curl "https://cs.growthdept.ai/api/voice/softphone" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Get a voice line
GET/api/voice/lines/{id}
The line with its settings, call flow and the flow's warnings.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The voice line's id. |
Response
200 · The line. · VoiceLine
Request
curl "https://cs.growthdept.ai/api/voice/lines/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"name": "Demo Store",
"phone_number_id": 0,
"phone_number": "",
"settings": {
"recording": {
"inbound": false,
"outbound": false,
"notice": ""
},
"transcription": {
"calls": false,
"voicemail": false
},
"emoji": null
},
"flow": {
"version": 0,
"steps": [
{}
]
},
"warnings": [
{
"step_id": null,
"level": "",
"message": ""
}
]
}Change a voice line
PUT/api/voice/lines/{id}
Changes the fields sent. A flow with errors (a menu with no message, a queue that no longer exists) is refused with each problem listed.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The voice line's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| phone_ | integer | |
| settings | object | |
| flow | any |
Response
200 · The line. · VoiceLine
Request
curl -X PUT "https://cs.growthdept.ai/api/voice/lines/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"phone_number_id": 0,
"settings": {}
}'Response 200
{
"id": 1,
"name": "Demo Store",
"phone_number_id": 0,
"phone_number": "",
"settings": {
"recording": {
"inbound": false,
"outbound": false,
"notice": ""
},
"transcription": {
"calls": false,
"voicemail": false
},
"emoji": null
},
"flow": {
"version": 0,
"steps": [
{}
]
},
"warnings": [
{
"step_id": null,
"level": "",
"message": ""
}
]
}Delete a voice line
DELETE/api/voice/lines/{id}
Calls to its number are no longer taken. Its tickets and calls stay.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The voice line's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/voice/lines/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Get a call queue
GET/api/voice/queues/{id}
One call queue with its routing and waiting settings.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The queue's id. |
Response
200 · The queue. · VoiceQueue
Request
curl "https://cs.growthdept.ai/api/voice/queues/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"name": "Demo Store",
"enabled": false,
"priority": false,
"capacity": null,
"distribution": "round_robin",
"ring_team_id": null,
"ring_secs": 0,
"max_wait_secs": 0,
"wrapup_enabled": false,
"wrapup_secs": 0,
"hold_music_file_id": null,
"waiting": 0,
"lines": [
{
"id": 1,
"name": "Demo Store"
}
]
}Change a call queue
PUT/api/voice/queues/{id}
Changes the fields sent. Switching a queue off sends new callers to the next step of the call flow; callers already waiting stay until their wait time runs out.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The queue's id. |
Body
| Field | Type | Description |
|---|---|---|
| name | string | |
| enabled | boolean | |
| priority | boolean | |
| capacity | integer or null | |
| distribution | round_robin, broadcast | |
| ring_ | integer or null | |
| ring_ | integer | |
| max_ | integer | |
| wrapup_ | boolean | |
| wrapup_ | integer | |
| hold_ | integer or null |
Response
200 · The queue. · VoiceQueue
Request
curl -X PUT "https://cs.growthdept.ai/api/voice/queues/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Store",
"enabled": false,
"priority": false
}'Response 200
{
"id": 1,
"name": "Demo Store",
"enabled": false,
"priority": false,
"capacity": null,
"distribution": "round_robin",
"ring_team_id": null,
"ring_secs": 0,
"max_wait_secs": 0,
"wrapup_enabled": false,
"wrapup_secs": 0,
"hold_music_file_id": null,
"waiting": 0,
"lines": [
{
"id": 1,
"name": "Demo Store"
}
]
}Delete a call queue
DELETE/api/voice/queues/{id}
Refused while a call flow routes to it.
Role: admin or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The queue's id. |
Response
204 · Deleted.
Request
curl -X DELETE "https://cs.growthdept.ai/api/voice/queues/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 204
(no body)Softphone heartbeat
POST/api/voice/softphone/ready
ready: true while the requesting agent's softphone is signed in to Telnyx and may ring, sent every 20 seconds; false when it signs out. An agent is rung only within 45 seconds of the last true.
Role: lite-agent or higher
Body
| Field | Type | Description |
|---|---|---|
| readyrequired | boolean |
Response
200 · {ready, offered}: offered counts waiting calls that rang an agent because of this. · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/voice/softphone/ready" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ready": false
}'Response 200
{}Get a softphone sign-in token
POST/api/voice/softphone/token
A short-lived token the requesting agent's browser signs in to Telnyx with, so calls can ring there. Never stored.
Role: lite-agent or higher
Response
200 · {token, sip_username}. · object
Request
curl -X POST \
"https://cs.growthdept.ai/api/voice/softphone/token" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}Act on a live call
POST/api/voice/calls/{id}/actions
action: hold or resume (the caller hears hold music, the recording pauses), record_start, record_pause or record_resume, transfer (to_agent_id: an available agent; to_queue_id: back into a queue; to_number: an outside number), or hangup. Only the agent on the call can act on it.
Role: lite-agent or higher
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The voice call's id. |
Body
| Field | Type | Description |
|---|---|---|
| actionrequired | hold, resume, record_start, record_pause, record_resume, transfer, hangup | |
| to_ | integer | |
| to_ | integer | |
| to_ | string |
Response
200 · The call after the action. · VoiceCall
Request
curl -X POST \
"https://cs.growthdept.ai/api/voice/calls/1/actions" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "hold"
}'Response 200
{
"id": 1,
"ticket_id": 4182,
"integration_id": 2,
"phone_number_id": null,
"customer_id": 7311,
"direction": "inbound",
"phone_number_source": "",
"phone_number_destination": "",
"status": "ringing",
"outcome": "answered",
"queue_id": null,
"user_id": 12,
"initiated_by_user_id": null,
"started_datetime": "2026-11-04T09:41:12+00:00",
"queued_datetime": "2026-11-04T09:41:12+00:00",
"answered_datetime": "2026-11-04T09:41:12+00:00",
"ended_datetime": null,
"wait_time": null,
"talk_time": null,
"duration": null,
"recording": false,
"on_hold": false,
"created_datetime": "2026-11-04T09:41:12+00:00",
"updated_datetime": "2026-11-04T09:52:40+00:00"
}Voice of Customer
What customers write about, read two ways. The overview counts it from the helpdesk on each request: tone from a word list, reasons, products named in customers' own words and words on the rise, against the period before. Reports are the AI agent's own reading of a period, requested here and filed by the agent from the brand's machine, with themes, ticket counts and links, and recommendations.
The VocReport object · 13 fields
The AI agent's reading of what customers wrote in a period.
| Field | Type | Description |
|---|---|---|
| id | integer | |
| period | object | |
| status | pending, done, failed | |
| requested_ | object or null | |
| chat_ | integer or null | The Assistant chat that carried the request. |
| summary | string or null | |
| themes | array of object | |
| recommendations | array of string | |
| tickets_ | integer or null | |
| failure | string or null | |
| created_ | datetime | |
| completed_ | datetime or null | |
| uri | string |
What customers write about
GET/api/voc/overview
For tickets created in the period (helpdesk time zone; default the last 30 days), against the period of the same length before: ticket counts; tone from a word list (negative, neutral, positive; not a model); the contact reason field and tags; products named in the customers' own words, with how many of those tickets were negative and rated; words and two-word phrases on the rise; and tone by day. Counted on each request from at most 5,000 tickets.
Parameters
| Name | Description |
|---|---|
| startquery · string | |
| endquery · string |
Response
200 · The figures. · object
Request
curl "https://cs.growthdept.ai/api/voc/overview" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{}List the AI agent's reports
GET/api/voc/reports
The AI agent's Voice of Customer reports, newest first: pending while it reads, then its summary, themes and recommendations.
Parameters
| Name | Description |
|---|---|
| limitquery · string | At most this many (1 to 100, default 20). |
Response
200 · The reports. · object
Request
curl "https://cs.growthdept.ai/api/voc/reports" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"data": [
{
"id": 1,
"period": {
"start": "",
"end": ""
},
"status": "pending",
"requested_by": {
"id": 1,
"name": "Demo Store"
},
"chat_id": null,
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"themes": [
{
"name": "Demo Store",
"kind": "issue",
"sentiment": "negative",
"tickets": 0,
"ticket_ids": [
0
],
"products": [
""
],
"summary": "Customer asks where order #1042 is; tracking stalled since Monday."
}
],
"recommendations": [
""
],
"tickets_read": null,
"failure": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"completed_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}
]
}Ask the AI agent for a report
POST/api/voc/reports
Queues a request for the helpdesk's AI agent to read what customers wrote in the period and file themes, ticket counts and recommendations. The agent runs on the brand's own machine and usually answers within a few minutes; the request is also a chat in the Assistant, shared with the team. One report at a time. Answers 409 when no AI agent is linked or one is already waiting.
Body
| Field | Type | Description |
|---|---|---|
| startrequired | string | |
| endrequired | string |
Response
201 · The pending report. · VocReport
Request
curl -X POST "https://cs.growthdept.ai/api/voc/reports" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"start": "",
"end": ""
}'Response 201
{
"id": 1,
"period": {
"start": "",
"end": ""
},
"status": "pending",
"requested_by": {
"id": 1,
"name": "Demo Store"
},
"chat_id": null,
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"themes": [
{
"name": "Demo Store",
"kind": "issue",
"sentiment": "negative",
"tickets": 0,
"ticket_ids": [
0
],
"products": [
""
],
"summary": "Customer asks where order #1042 is; tracking stalled since Monday."
}
],
"recommendations": [
""
],
"tickets_read": null,
"failure": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"completed_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}Get a report
GET/api/voc/reports/{id}
One of the AI agent's Voice of Customer reports.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Response
200 · The report. · VocReport
Request
curl "https://cs.growthdept.ai/api/voc/reports/1" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"Response 200
{
"id": 1,
"period": {
"start": "",
"end": ""
},
"status": "pending",
"requested_by": {
"id": 1,
"name": "Demo Store"
},
"chat_id": null,
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"themes": [
{
"name": "Demo Store",
"kind": "issue",
"sentiment": "negative",
"tickets": 0,
"ticket_ids": [
0
],
"products": [
""
],
"summary": "Customer asks where order #1042 is; tracking stalled since Monday."
}
],
"recommendations": [
""
],
"tickets_read": null,
"failure": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"completed_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}File a report (AI agent)
POST/api/voc/reports/{id}/result
The AI agent's reading of the period: summary, themes (name; kind issue, request, praise or question; sentiment; tickets; up to 20 ticket ids from this helpdesk; products; summary), up to 10 recommendations and how many tickets it read. Or failure, in plain words. Only the AI agent's key.
Parameters
| Name | Description |
|---|---|
| idrequiredpath · integer | The object's id. |
Body
| Field | Type | Description |
|---|---|---|
| summary | string | |
| themes | array of object | |
| recommendations | array of string | |
| tickets_ | integer | |
| failure | string |
Response
200 · The report. · VocReport
Request
curl -X POST \
"https://cs.growthdept.ai/api/voc/reports/1/result" \
-u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"themes": [
{
"name": "Demo Store",
"kind": "issue",
"sentiment": "negative",
"tickets": 0,
"ticket_ids": [
0
],
"products": [
""
],
"summary": "Customer asks where order #1042 is; tracking stalled since Monday."
}
],
"recommendations": [
""
]
}'Response 200
{
"id": 1,
"period": {
"start": "",
"end": ""
},
"status": "pending",
"requested_by": {
"id": 1,
"name": "Demo Store"
},
"chat_id": null,
"summary": "Customer asks where order #1042 is; tracking stalled since Monday.",
"themes": [
{
"name": "Demo Store",
"kind": "issue",
"sentiment": "negative",
"tickets": 0,
"ticket_ids": [
0
],
"products": [
""
],
"summary": "Customer asks where order #1042 is; tracking stalled since Monday."
}
],
"recommendations": [
""
],
"tickets_read": null,
"failure": null,
"created_datetime": "2026-11-04T09:41:12+00:00",
"completed_datetime": "2026-11-04T09:41:12+00:00",
"uri": "/api/"
}Questions about the API: support@growthdept.ai.