Skip to content
Chat on your store is live, answered from the same inbox.
GROWTH DEPT.HELPDESK

Developers

Growth Dept Helpdesk API

Contents

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 URLhttps://cs.growthdept.ai/api
FormatJSON. Send Content-Type: application/json on writes.
TimesISO 8601 in UTC, in fields ending in _datetime.
IdsIntegers. Paths ending in a slash work the same as without one.
OpenAPIhttps://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.

RoleAdds
observer-agentRead everything: tickets, messages, customers, agents, teams, tags, macros, rules, views, fields, surveys, integrations and events.
lite-agentWork tickets: reply, add notes, tag, assign, snooze, close; create and edit customers; create tags.
lead-agentManage macros, views and view sections; rename, recolour, merge and delete tags.
adminManage 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==" }
}
ParameterWhat it does
limitHow many objects per page, from 1 to 100. The default is 30.
cursorWhere 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_byThe 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."] }
  }
}
StatusMeaning
200, 201It worked. 201 when something was created.
204It worked and there is nothing to return, as after a delete.
400The request is not valid. error.data lists the problem with each field.
401No API key, or a key that is wrong or revoked.
403The key's agent does not have the role this endpoint needs.
404Nothing with that id in this helpdesk.
409The change conflicts with what is stored, such as a setting group that already exists.
413The upload is too large.
429Too 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.

EventSent when
ticket-createdA ticket is opened: by an email arriving, by an agent or through the API.
ticket-updatedA ticket's status, assignee, team, tags, priority, fields or other properties change.
ticket-message-createdA 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/api

What stays the same

Same as Gorgias's REST API
PathsResources live at the same paths under /api/: /api/tickets, /api/tickets/{id}/messages, /api/customers/merge and so on.
FieldsObjects use the same field names and value formats, including the _datetime timestamps and the embedded customer, assignee and tag objects.
ListsLists 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.
ErrorsErrors use the same status codes and an error object with a message and, for invalid requests, the problem with each field.
Sign-inHTTP Basic with the agent's email as the username and an API key as the password.
WebhooksHTTP 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 URLhttps://cs.growthdept.ai/api for every helpdesk, in place of https://<your-domain>.gorgias.com/api.
HelpdeskThere 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 keysAuthorization: Bearer <key> works as well as HTTP Basic.
Rate-limit headerThe 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 offeredPhone and voice (calls, call events and recordings) are not part of this helpdesk.
ReportingReporting 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 feedbackFeedback on a metric card answers 204 with no body, and its comment text is not stored.
AddedView sections have their own endpoints, and the whole API is described in an OpenAPI document at /api/openapi.json.
FilesUploaded 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
FieldTypeDescription
idinteger
created_datetimedatetime
actionread
object_typeCustomer, Ticket, TicketMessage, SatisfactionSurvey, AiDraft, FileWhat was read.
object_idinteger or nullThe object read; null for a list or search.
countintegerHow 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.
routestringThe method and path template, such as GET /api/customers/{id}. Query strings are never kept.
viaapi_key, sessionsession for the app's own pages, api_key for the REST API.
userobject or nullThe agent who read: id, name and email.
api_keyobject or nullThe API key used: id, name and the first characters of the key.
platform_adminbooleanTrue when a Growth Dept admin read the helpdesk's data.
ipstring or nullThe caller's address, as the hosting platform reported it.
The Account object · 12 fields

A helpdesk. Gorgias calls it an account.

FieldTypeDescription
domainstringThe helpdesk's address, as in /app/<domain>.
namestringThe helpdesk's name.
created_datetimedatetime or null
deactivated_datetimedatetime or null
current_subscriptionobject
metaobject
settingsarray of AccountSetting
statusobject
timezonestringIANA time zone.
currencystringISO 4217 currency code.
languagestring
domainsarray of string
The AccountSetting object · 3 fields
FieldTypeDescription
idinteger
typestringSetting group, such as business-hours.
dataanyThe group's settings.
The AuditEntry object · 9 fields
FieldTypeDescription
idstringa:<n> for account changes, e:<n> for helpdesk events.
sourceaccount, helpdesk
created_datetimedatetime
actionstring
object_typestring or null
object_idinteger or string or null
userobject or nullThe agent who acted, when known.
viastring or nullapi_key when the change came through an API key.
detailobject or null
The HelpdeskSettings object · 2 fields

Every helpdesk-level setting type with its current value, defaults filled in.

FieldTypeDescription
dataobjectSetting values by type: business-hours, satisfaction-surveys, ticket-assignment, access, notifications, slas, agent-statuses, auto-merge, auto-split, labs, order-management, analytics.
meobjectThe 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
user_idquery · stringOnly reads by this agent.
object_typequery · stringOnly reads of this kind of object.Customer, Ticket, TicketMessage, SatisfactionSurvey, AiDraft, File
object_idquery · stringWith object_type: reads of one object.
viaquery · stringapi_key for the REST API, session for the app's pages.api_key, session
api_key_idquery · stringOnly reads made with this API key.
fromquery · datetimeAt or after this time.
toquery · datetimeAt 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

NameDescription
typequery · stringOnly 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

FieldTypeDescription
typerequiredstring
datarequiredany

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

NameDescription
sourcequery · stringall, account, helpdeskdefault all
actionquery · string
object_typequery · string
user_idquery · string
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

FieldTypeDescription
typerequiredbusiness-hours, satisfaction-surveys, ticket-assignment, access, notifications, slas, agent-statuses, auto-merge, auto-split, labs, order-management, analytics
datarequiredany
scopehelpdesk, 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
datarequiredany
typestring

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
FieldTypeDescription
idinteger
uristring
external_idstring or null
languagestring or null
statusopen, closed
prioritylow, normal, high, critical
channelstring
viastring
from_agentboolean
customerCustomerSummary or null
assignee_userUserSummary or null
assignee_teamTeamSummary or null
subjectstring or null
summarystring or null
excerptstring or nullThe start of the latest message.
integrationsarray of any
metaobject or null
tagsarray of TagSummary
messages_countinteger
is_unreadboolean
spamboolean
custom_fieldsobjectTicket field values keyed by field id.
created_datetimedatetime or null
updated_datetimedatetime or null
opened_datetimedatetime or null
last_received_message_datetimedatetime or null
last_message_datetimedatetime or null
last_sent_message_not_deliveredboolean
closed_datetimedatetime or null
snooze_datetimedatetime or null
trashed_datetimedatetime or null
The TicketDetail object · 40 fields
FieldTypeDescription
idinteger
uristring
external_idstring or null
languagestring or null
statusopen, closed
prioritylow, normal, high, critical
channelstring
viastring
from_agentboolean
customerCustomerDetail or null
assignee_userUserSummary or null
assignee_teamTeamSummary or null
subjectstring or null
summarystring or null
excerptstring or nullThe start of the latest message.
integrationsarray of any
metaobject or null
tagsarray of TagSummary
messages_countinteger
is_unreadboolean
spamboolean
custom_fieldsobjectTicket field values keyed by field id.
created_datetimedatetime or null
updated_datetimedatetime or null
opened_datetimedatetime or null
last_received_message_datetimedatetime or null
last_message_datetimedatetime or null
last_sent_message_not_deliveredboolean
closed_datetimedatetime or null
snooze_datetimedatetime or null
trashed_datetimedatetime or null
requesterCustomerDetail or null
assignee_user_idinteger or null
assignee_team_idinteger or null
importedboolean or null
messagesarray of Message
eventsarray of any
satisfaction_surveyobject or null
reply_optionsobject
integration_idinteger or nullThe mailbox or channel integration the ticket belongs to.
The CustomFieldValue object · 3 fields
FieldTypeDescription
idintegerThe field's id.
valueanyThe value, typed by the field's definition.
fieldobjectThe 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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_idquery · stringOnly this customer's tickets.
external_idquery · stringOnly the ticket with this external id.
view_idquery · stringOnly the tickets a saved view shows.
ticket_idsquery · string or array of stringOnly these ticket ids, comma-separated.
rule_idquery · stringOnly the tickets this rule has acted on.
trashedquery · stringfalse 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

FieldTypeDescription
channelstring
viastring
statusopen, closed
prioritylow, normal, high, critical
subjectstring or null
languagestring or null
external_idstring or null
from_agentboolean
spamboolean
is_unreadboolean
assignee_userobject or null{id} or {email} of an agent, or null to unassign.
assignee_teamobject or null
tagsarray of objectEach {id} or {name}; unknown names are created.
metaobject or null
custom_fieldsarray of object or object
opened_datetimestring or null
closed_datetimestring or null
snooze_datetimestring or null
trashed_datetimestring or null
customerobject or null{id}, or {email} (a new address creates the customer).
messagesarray of object
importedboolean or null
created_datetimestring 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

NameDescription
idrequiredpath · integerThe object's id.
relationshipsquery · string or array of stringRelated 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
channelstring
viastring
statusopen, closed
prioritylow, normal, high, critical
subjectstring or null
languagestring or null
external_idstring or null
from_agentboolean
spamboolean
is_unreadboolean
assignee_userobject or null{id} or {email} of an agent, or null to unassign.
assignee_teamobject or null
tagsarray of objectEach {id} or {name}; unknown names are created.
metaobject or null
custom_fieldsarray of object or object
opened_datetimestring or null
closed_datetimestring or null
snooze_datetimestring or null
trashed_datetimestring or null
customerobject 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
target_idquery · string
source_idquery · string

Body

FieldTypeDescription
subjectstring or nullThe subject the merged ticket keeps.
customerobject or nullThe 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

NameDescription
limitquery · string
cursorquery · string
order_byquery · string
with_highlightsquery · string
track_total_hitsquery · string

Body

FieldTypeDescription
searchstring or nullThe text to find in subjects, messages and customers.
filtersstringA 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namesarray of string
idsarray 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namesarray of string
idsarray 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namesarray of string
idsarray 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

NameDescription
idrequiredpath · integerThe object's id.
fieldIdrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.
fieldIdrequiredpath · integerThe 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
FieldTypeDescription
idinteger
uristring
ticket_idinteger
message_idstring or nullRFC 5322 Message-ID for email.
external_idstring or null
publicbooleanFalse for internal notes.
channelstringemail, chat, api, internal-note, ...
viastringHow the message reached the helpdesk: email, helpdesk, api, rule, ...
sourceobject
senderUserSummary
receiverUserSummary or null
integration_idinteger or null
rule_idinteger or null
from_agentboolean
subjectstring or null
body_textstring or null
body_htmlstring or null
stripped_textstring or null
stripped_htmlstring or null
stripped_signaturestring or null
attachmentsarray of Attachment or null
actionsany
macrosany
intentsany
headersobject or null
metaobject or null
importedboolean or null
is_retriableboolean
last_sending_errorobject or null
created_datetimedatetime or null
processed_datetimedatetime or null
sent_datetimedatetime or nullWhen the message went out; null while it waits to be sent.
failed_datetimedatetime or null
opened_datetimedatetime or null
deleted_datetimedatetime 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
ticket_idquery · stringOnly 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.
pagequery · integerPage number, starting at 1.default 1
per_pagequery · integerObjects per page, from 1 to 100. Default 30.
pagequery · string
per_pagequery · string

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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
channelstringemail, chat, api, internal-note, ... Defaults to the ticket's channel.
viastringhelpdesk (the default for agents) sends email replies; email means the message was already sent and it is only recorded.
publicbooleanfalse makes an internal note.
from_agentboolean
senderobject or nullWho wrote it: an agent (from_agent true) or a customer, by id or email. Defaults to you.
receiverobject or nullWho it is for. Defaults to the ticket's customer.
sourceobject or null
subjectstring or null
body_textstring or null
body_htmlstring or null
stripped_textstring or null
stripped_htmlstring or null
stripped_signaturestring or null
attachmentsarray of object or null
external_idstring or null
message_idstring or null
integration_idinteger or string
macrosarray of object or null
actionsarray of any or null
intentsarray of any or null
headersobject or null
metaobject or null
mention_idsarray of integer or string or nullAgents an internal note @mentions; each is told through a user-mentioned event.
importedboolean or null
created_datetimestring or null
sent_datetimestring or null
failed_datetimestring or null
opened_datetimestring or null
processed_datetimestring 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

NameDescription
idrequiredpath · integerThe object's id.
messageIdrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.
messageIdrequiredpath · integerThe message's id.

Body

FieldTypeDescription
body_textstring or null
body_htmlstring or null
stripped_textstring or null
stripped_htmlstring or null
subjectstring or null
external_idstring or null
metaobject or null
attachmentsarray of object or null
sent_datetimestring or null
failed_datetimestring or null
opened_datetimestring or null
last_sending_errorobject or null
is_retriableboolean

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

NameDescription
idrequiredpath · integerThe object's id.
messageIdrequiredpath · integerThe 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
FieldTypeDescription
idinteger
uristring
external_idstring or null
activeboolean
emailstring or nullThe preferred email address.
namestring or null
firstnamestring or null
lastnamestring or null
languagestring or null
timezonestring or null
notestring or null
metaobject or null
dataanyFree-form data set through the API.
custom_fieldsobjectCustomer field values keyed by field id.
created_datetimedatetime or null
updated_datetimedatetime or null
The CustomerDetail object · 21 fields
FieldTypeDescription
idinteger
uristring
external_idstring or null
activeboolean
emailstring or nullThe preferred email address.
namestring or null
firstnamestring or null
lastnamestring or null
languagestring or null
timezonestring or null
notestring or null
metaobject or null
dataanyFree-form data set through the API.
custom_fieldsobjectCustomer field values keyed by field id.
created_datetimedatetime or null
updated_datetimedatetime or null
channelsarray of CustomerChannel
integrationsobjectStore and app data keyed by integration id.
external_dataobject
ecommerce_dataobject
customernull
The CustomerChannel object · 9 fields
FieldTypeDescription
idinteger
typestringemail, phone, sms, chat, facebook, instagram, ...
addressstring
preferredboolean
created_datetimedatetime or null
updated_datetimedatetime or null
deleted_datetimedatetime or null
userobject
customerobject

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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc, updated_datetime:asc, updated_datetime:desc
idquery · stringThe customer with this id.
emailquery · stringCustomers with this email address.
external_idquery · stringThe customer with this external id.
namequery · stringCustomers whose name contains this.
channel_typequery · stringWith channel_address: the channel type, such as phone.
channel_addressquery · stringCustomers with this address on a channel.
languagequery · string
timezonequery · string
view_idquery · stringOnly 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

FieldTypeDescription
emailstring or null
namestring or null
firstnamestring or null
lastnamestring or null
external_idstring or null
languagestring or null
timezonestring or null
notestring or null
metaobject or null
dataany
channelsarray of object
activeboolean

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

FieldTypeDescription
idsrequiredarray 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
emailstring or null
namestring or null
firstnamestring or null
lastnamestring or null
external_idstring or null
languagestring or null
timezonestring or null
notestring or null
metaobject or null
dataany
channelsarray of object
activeboolean

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
source_idquery · string
target_idquery · string

Body

FieldTypeDescription
emailstring or null
namestring or null
firstnamestring or null
lastnamestring or null
external_idstring or null
languagestring or null
timezonestring or null
notestring or null
metaobject or null
dataany
channelsarray of object
activeboolean
source_idinteger or string
target_idinteger 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

NameDescription
source_idquery · string
target_idquery · string

Body

FieldTypeDescription
emailstring or null
namestring or null
firstnamestring or null
lastnamestring or null
external_idstring or null
languagestring or null
timezonestring or null
notestring or null
metaobject or null
dataany
channelsarray of object
activeboolean
source_idinteger or string
target_idinteger 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

NameDescription
limitquery · string
order_byquery · string
with_highlightsquery · string

Body

FieldTypeDescription
searchstring or nullPart 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
typerequiredstring
addressrequiredstring
preferredboolean

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
datarequiredany

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

NameDescription
idrequiredpath · integerThe object's id.
channelIdrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.
channelIdrequiredpath · integerThe channel's id.

Body

FieldTypeDescription
typestring
addressstring
preferredboolean

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

NameDescription
idrequiredpath · integerThe object's id.
channelIdrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.
fieldIdrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.
fieldIdrequiredpath · integerThe 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
FieldTypeDescription
dataarray of CustomAvailabilityStatus
The CustomAvailabilityStatus object · 9 fields
FieldTypeDescription
idinteger
uristring
namestringShown in the account menu and next to the agent's name. At most 30 characters.
descriptionstring or nullAt most 70 characters.
duration_minutesinteger or nullMinutes after which an agent in this status is available again (5 to 1440); null to stay until changed.
enabledbooleanSwitched-off statuses are not offered; agents already in one keep it.
positionintegerOrder in the menu, lowest first.
created_datetimedatetime or null
updated_datetimedatetime or null
The User object · 20 fields

An agent. Gorgias calls agents users.

FieldTypeDescription
idinteger
uristring
emailstring
namestring or null
firstnamestring or null
lastnamestring or null
activeboolean
biostring or null
countrystring or null
languagestring or null
timezonestring or null
external_idstring or null
metaobject or null
roleobject
has_passwordboolean
has_2fa_enabledboolean
client_idstring or null
created_datetimedatetime or null
updated_datetimedatetime or null
deactivated_datetimedatetime or null
The AgentAvailability object · 5 fields
FieldTypeDescription
user_idintegerThe agent's id.
availabilityavailable, busy, offlinebusy means away, with the reason in availability_reason.
availability_reasonstring or nullThe status's name, or a reason typed by an older client.
status_idinteger or nullThe custom availability status the agent picked, if any.
availability_untildatetime or nullWhen 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.

FieldTypeDescription
idstring
emailstring
rolestringOrganization role: admin, member or viewer.
agent_idinteger or nullThe agent profile waiting for this person.
agent_rolestring or nullThe helpdesk role they get when they accept.
created_atdatetime
expires_atdatetime
The TwoFactorStatus object · 2 fields
FieldTypeDescription
requiredbooleanThe organization requires two-factor for password sign-ins.
usersobjectAgent 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

NameDescription
enabledquery · stringtrue: 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

FieldTypeDescription
namestringThe status's name, at most 30 characters.
descriptionstring or nullOptional, at most 70 characters.
duration_minutesinteger or nullMinutes after which the agent is available again, 5 to 1440; null to stay until changed.
enabledbooleanWhether agents can pick it. On by default.
positionintegerOrder 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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 · stringThe agent with this email.
external_idquery · string
rolesquery · string or array of stringOnly these roles, comma-separated, such as admin,agent.
searchquery · stringAgents whose name or email contains this.
available_firstquery · stringtrue 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

FieldTypeDescription
emailrequiredstring
namestring or null
firstnamestring or null
lastnamestring or null
roleadmin, lead-agent, agent, basic-agent, lite-agent, observer-agent, bot or object
biostring or null
countrystring or null
languagestring or null
timezonestring or null
external_idstring or null
metaobject 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe status's id.

Body

FieldTypeDescription
namestringThe status's name, at most 30 characters.
descriptionstring or nullOptional, at most 70 characters.
duration_minutesinteger or nullMinutes after which the agent is available again, 5 to 1440; null to stay until changed.
enabledbooleanWhether agents can pick it. On by default.
positionintegerOrder 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

NameDescription
idrequiredpath · integerThe 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

FieldTypeDescription
user_idrequiredintegerThe agent, or 0 for yourself.
availabilityavailable, busy, offlineRequired unless status_id is given.
availability_reasonstring or nullA reason for busy, when no status_id is given.
status_idinteger or nullOne 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

FieldTypeDescription
emailrequiredstring
namestring or null
roleadmin, lead-agent, agent, basic-agent, lite-agent, observer-agent
team_idsarray 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe agent's id, or 0 for yourself.

Body

FieldTypeDescription
emailstring
namestring or null
firstnamestring or null
lastnamestring or null
roleadmin, lead-agent, agent, basic-agent, lite-agent, observer-agent, bot or object
biostring or null
countrystring or null
languagestring or null
timezonestring or null
external_idstring or null
metaobject or null
activeboolean

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · stringThe 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
FieldTypeDescription
idstring
namestring
prefixstringThe first characters of the key, to tell keys apart.
keystringThe full key. Returned once, when the key is created.
user_idinteger
created_datetimedatetime or null
last_used_datetimedatetime or null
revoked_datetimedatetime 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe agent's id, or 0 for yourself.

Body

FieldTypeDescription
namestringA 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

NameDescription
idrequiredpath · integerThe agent's id, or 0 for yourself.
keyIdrequiredpath · stringThe 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
FieldTypeDescription
idinteger
uristring
namestring
descriptionstring or null
decorationobject or nullEmoji and colour.
default_email_integration_idinteger or nullThe mailbox the team's replies go out from.
membersarray of object
created_datetimedatetime or null
updated_datetimedatetime or null

List teams

GET/api/teams

The helpdesk's teams with their members.

Parameters

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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

FieldTypeDescription
namerequiredstring
descriptionstring or null
decorationobject or null
default_email_integration_idinteger or stringThe mailbox the team's replies go out from.
membersarray 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namestring
descriptionstring or null
decorationobject or null
default_email_integration_idinteger or stringThe mailbox the team's replies go out from.
membersarray 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
idsrequiredarray 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
idsrequiredarray 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)

Tags

Tags label tickets for views, rules and reports. Tagging a ticket with a new name creates the tag.

The Tag object · 8 fields
FieldTypeDescription
idinteger
uristring
namestring
descriptionstring or null
decorationobject or nullColour, as {"color": "#rrggbb"}.
usageintegerHow many tickets carry the tag.
created_datetimedatetime or null
deleted_datetimedatetime or null

List tags

GET/api/tags

The helpdesk's tags, newest first unless order_by says otherwise, each with how many tickets carry it (usage). search keeps the tags whose name contains the text.

Parameters

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc, name:asc, name:desc, usage:asc, usage:desc
searchquery · stringOnly tags whose name contains this.

Response

200 · A page of tags. · list of Tag

Request

curl "https://cs.growthdept.ai/api/tags?limit=2" \
  -u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"

Response 200

{
  "object": "list",
  "uri": "/api/tags?limit=2",
  "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
    }
  ],
  "meta": {
    "prev_cursor": null,
    "next_cursor": "WyJuZXh0IiwiMjAyNi0xMS0wNFQwOTo0MToxMiswMDowMCIsNDE4Ml0="
  }
}

Create a tag

POST/api/tags

Adds a tag. Names are unique ignoring case; a name already in use is refused with 400.

Role: lite-agent or higher

Body

FieldTypeDescription
namerequiredstring
descriptionstring or null
decorationobject or null

Response

201 · The new tag. · Tag

Request

curl -X POST "https://cs.growthdept.ai/api/tags" \
  -u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "carrier-trace",
    "description": "Asked the carrier to trace a parcel",
    "decoration": {
      "color": "#2546e8"
    }
  }'

Response 201

{
  "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
}

Delete several tags

DELETE/api/tags

Deletes the tags given as {ids: [...]} and removes them from every ticket.

Role: lead-agent or higher

Body

FieldTypeDescription
idsrequiredarray of integer or string

Response

204 · Deleted.

Request

curl -X DELETE "https://cs.growthdept.ai/api/tags" \
  -u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      0
    ]
  }'

Response 204

(no body)

Get a tag

GET/api/tags/{id}

One tag with how many tickets carry it.

Parameters

NameDescription
idrequiredpath · integerThe object's id.

Response

200 · The tag. · Tag

Request

curl "https://cs.growthdept.ai/api/tags/12" \
  -u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"

Response 200

{
  "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
}

Update a tag

PUT/api/tags/{id}

Renames a tag or changes its description or colour (decoration {color}). Tickets keep the tag under its new name.

Role: lead-agent or higher

Parameters

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namestring
descriptionstring or null
decorationobject or null

Response

202 · The tag after the change. · Tag

Request

curl -X PUT "https://cs.growthdept.ai/api/tags/12" \
  -u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Demo Store",
    "description": null,
    "decoration": {
      "color": "#2546e8"
    }
  }'

Response 202

{
  "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
}

Delete a tag

DELETE/api/tags/{id}

Deletes the tag and removes it from every ticket.

Role: lead-agent or higher

Parameters

NameDescription
idrequiredpath · integerThe object's id.

Response

204 · Deleted.

Request

curl -X DELETE "https://cs.growthdept.ai/api/tags/12" \
  -u "$HELPDESK_EMAIL:$HELPDESK_API_KEY"

Response 204

(no body)

Merge tags into this one (POST)

POST/api/tags/{id}/merge

Puts this tag on every ticket that carries one of the source tags ({source_tags_ids: [...]}), then deletes the source tags.

Role: lead-agent or higher

Parameters

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
source_tags_idsrequiredarray of integer or stringThe tags to merge into this one.

Response

202 · The tag that remains. · Tag

Request

curl -X POST "https://cs.growthdept.ai/api/tags/12/merge" \
  -u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source_tags_ids": [
      31,
      44
    ]
  }'

Response 202

{
  "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
}

Merge tags into this one

PUT/api/tags/{id}/merge

Puts this tag on every ticket that carries one of the source tags ({source_tags_ids: [...]}), then deletes the source tags.

Role: lead-agent or higher

Parameters

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
source_tags_idsrequiredarray of integer or stringThe tags to merge into this one.

Response

202 · The tag that remains. · Tag

Request

curl -X PUT "https://cs.growthdept.ai/api/tags/12/merge" \
  -u "$HELPDESK_EMAIL:$HELPDESK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source_tags_ids": [
      31,
      44
    ]
  }'

Response 202

{
  "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
}

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.

FieldTypeDescription
idinteger
uristring
external_idstring or null
namestring
intentstring or null
languagestring or null
actionsarray of objectWhat the macro does, in order.
usageintegerHow many times agents have used it.
created_datetimedatetime or null
updated_datetimedatetime or null
archived_datetimedatetime or null
The MacroApplication object · 8 fields
FieldTypeDescription
replyobject or nullThe drafted reply: body_text, body_html and attachments.
patchobjectTicket fields the macro changes.
addTagsarray of string
removeTagsarray of string
customFieldsarray of object
internalNotesarray of object
forwardsarray of object
actionsarray 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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 · stringWords in the macro's name, reply text or tags. Every word must appear.
archivedquery · stringArchived or active macros only.0, 1, true, false
languagesquery · string or array of stringOnly macros written in these languages, comma-separated, such as en,fr.
tagsquery · string or array of stringOnly macros that add one of these tags, comma-separated.
ticket_idquery · stringThe ticket the macros are for; needed for relevance ordering and predictions.
message_idquery · stringA message of that ticket. Accepted so Gorgias clients keep working.
number_predictionsquery · stringHow 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

FieldTypeDescription
idsrequiredarray 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

FieldTypeDescription
idsrequiredarray 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

NameDescription
idrequiredpath · integerThe macro's id.

Body

FieldTypeDescription
ticket_idrequiredinteger

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.

FieldTypeDescription
idinteger
uristring
namestring
descriptionstring or null
typeuser, system, managed
event_typesstringComma-separated: ticket-created, ticket-updated, ticket-message-created.
codestringThe rule in the expression language: if blocks and Action(...) calls.
code_astobject or nullThe parsed code (an ESTree Program).
settingsobject or null
priorityintegerRules with a higher priority run first.
created_datetimedatetime or null
updated_datetimedatetime or null
deactivated_datetimedatetime 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
searchquery · stringOnly 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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.

FieldTypeDescription
idinteger
uristring
namestring
privateboolean
decorationobject or null
display_orderinteger
created_datetimedatetime or null
updated_datetimedatetime or null
The View object · 22 fields

A saved list of tickets or customers.

FieldTypeDescription
idinteger
uristring
namestring
slugstring
typeticket-list, customer-list
categorysystem, user, team
visibilitypublic, private, sharedpublic: every agent. private: its owner. shared: its owner, shared_with_users and members of shared_with_teams.
filtersstringThe filter expression, for example eq(ticket.status, "open") && isEmpty(ticket.assignee_user.id).
filters_astobject or nullThe parsed filter (an ESTree Program).
searchstring or nullWords the items must also match.
order_bystringThe field items are sorted by.
order_dirasc, desc
fieldsarray of stringColumns shown in the list.
decorationobject or nullEmoji and colour.
section_idinteger or null
shared_with_usersarray of integer
shared_with_teamsarray of integer
display_orderinteger
owner_user_idinteger or nullThe agent who created the view.
created_datetimedatetime or null
updated_datetimedatetime or null
deactivated_datetimedatetime or null
The ViewCount object · 4 fields
FieldTypeDescription
idintegerThe view's id.
countintegerItems in the view, up to the cap.
cappedbooleanTrue when the view holds more than 10,000 items.
errorstring or nullSet when the view's filter could not be read.
The ViewItems object · 2 fields
FieldTypeDescription
dataarray of objectTickets (or customers) in list form.
metaobject

List view sections

GET/api/view-sections

The sidebar sections the caller can see: every shared section and the caller's private ones.

Parameters

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
categoryquery · stringsystem, 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idsquery · string or array of stringView 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

FieldTypeDescription
idsrequiredarray 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

NameDescription
idrequiredpath · integerThe view's id.
limitquery · string
cursorquery · string
directionquery · stringnext, prev
order_byquery · string
ignored_itemquery · string

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

NameDescription
idrequiredpath · integerThe view's id.
limitquery · string
cursorquery · string
directionquery · stringnext, prev
order_byquery · string
ignored_itemquery · string

Body

FieldTypeDescription
viewobject

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
FieldTypeDescription
idinteger
uristring
external_idstring or null
object_typeTicket, Customer
labelstring
descriptionstring or null
priorityinteger
requiredboolean
requirement_typevisible, required, conditional
managed_typestring or null
definitionobject
created_datetimedatetime or null
updated_datetimedatetime or null
deactivated_datetimedatetime 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default priority:desc.priority:asc, priority:desc
object_typerequiredquery · string
searchquery · stringOnly fields whose label contains this.
archivedquery · string0, 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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
FieldTypeDescription
idinteger
uristring
ticket_idinteger
customer_idinteger or null
scoreinteger or null1 to 5.
body_textstring or nullThe customer's comment.
metaobject or null
created_datetimedatetime or null
should_send_datetimedatetime or null
sent_datetimedatetime or null
scored_datetimedatetime or null

List satisfaction surveys

GET/api/satisfaction-surveys

Surveys waiting to go out, sent and answered, newest first. Filter by ticket_id.

Parameters

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
ticket_idquery · stringOnly 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

FieldTypeDescription
ticket_idinteger or stringThe ticket the survey is about. Required when creating.
customer_idinteger or stringThe customer asked. Required when creating.
scoreinteger or null1 to 5, or null. Needs scored_datetime.
body_textstring or nullThe customer's comment. Needs a score.
metaobject or null
created_datetimestring or null
should_send_datetimestring or nullWhen 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_datetimestring or nullWhen it went out; set it to record a survey sent elsewhere.
scored_datetimestring or nullWhen 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe survey's id.

Body

FieldTypeDescription
ticket_idinteger or stringThe ticket the survey is about. Required when creating.
customer_idinteger or stringThe customer asked. Required when creating.
scoreinteger or null1 to 5, or null. Needs scored_datetime.
body_textstring or nullThe customer's comment. Needs a score.
metaobject or null
created_datetimestring or null
should_send_datetimestring or nullWhen 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_datetimestring or nullWhen it went out; set it to record a survey sent elsewhere.
scored_datetimestring or nullWhen 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
FieldTypeDescription
idinteger
uristring
typestringhttp, gmail, resend (a forwarded support address), email, shopify, ...
namestring
descriptionstring or null
decorationobject or null
metaobject
httpobject or nullFor type http: url, method, headers, request_content_type, response_content_type, form, triggers.
userobject or null
managedboolean
application_idstring or null
business_hours_idinteger or null
created_datetimedatetime or null
updated_datetimedatetime or null
deactivated_datetimedatetime or null
locked_datetimedatetime or null
The HttpIntegrationTest object · 8 fields
FieldTypeDescription
okbooleanThe receiver answered with a 2xx status.
statusinteger or null
duration_msinteger
response_excerptstring or nullThe first 2,000 characters of the response body.
errorstring or null
signedboolean
delivery_idstring
requestobjectWhat was sent. Header values other than content type and the helpdesk's own headers are masked.
The WebhookDelivery object · 12 fields
FieldTypeDescription
idinteger
integration_idinteger
event_idinteger or null
event_typestring
object_typestring or null
object_idinteger or null
attemptinteger
statussucceeded, failed, refused
status_codeinteger or null
errorstring or null
duration_msinteger or null
created_datetimedatetime 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
typequery · string
purposequery · stringWith 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

NameDescription
idrequiredpath · integerThe integration's id.
include_review_providersquery · stringFor a Shopify store: include its review apps.0, 1, true, false
include_shopify_integrationquery · stringFor 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

FieldTypeDescription
event_typeticket-created, ticket-updated, ticket-message-created
httprequiredobject

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

NameDescription
idrequiredpath · integerThe integration's id.
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
event_typeticket-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
FieldTypeDescription
idinteger
uristring
public_idstringThe random id in the form's public address.
namestringThe form's name, shown to agents.
languageen, fr, de, esThe language of the form's labels and of the tickets it opens.
integration_idinteger or nullThe mailbox that answers submissions.
mailboxobject or nullThe mailbox that answers submissions, with active false once it is disconnected.
settingsobjectWhat the public form shows.
urlstringThe hosted form.
embed_urlstringThe form without page margins, for an iframe.
script_urlstringA script that adds the form's iframe where the script tag stands.
created_datetimedatetime or null
updated_datetimedatetime or null
deleted_datetimedatetime or null
The ContactFormSubmitted object · 1 fields
FieldTypeDescription
oktrue

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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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

FieldTypeDescription
namestringThe form's name, shown to agents.
languageen, fr, de, esThe language of the form's labels and the tickets it opens.
integration_idinteger or stringThe mailbox that answers submissions: a Gmail mailbox or a forwarding mailbox in this helpdesk. null for none.
settingsobjectWhat 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe contact form's id.

Body

FieldTypeDescription
namestringThe form's name, shown to agents.
languageen, fr, de, esThe language of the form's labels and the tickets it opens.
integration_idinteger or stringThe mailbox that answers submissions: a Gmail mailbox or a forwarding mailbox in this helpdesk. null for none.
settingsobjectWhat 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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
FieldTypeDescription
idinteger
uristring
typestringticket-created, ticket-updated, ticket-message-created, ...
object_typestringTicket, TicketMessage, Customer, User, ...
object_idinteger or null
user_idinteger or nullThe agent who acted; null for customers and the system.
contextstring or nullEvents caused by the same request share a context.
dataobject or nullWhat changed. Never message text.
created_datetimedatetime 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
object_typequery · stringThe kind of object: Ticket, TicketMessage, Customer, User, Team, Tag, CustomField, Macro, Rule, View, Widget, Integration, SatisfactionSurvey and the other types Gorgias lists.
object_idquery · stringWith object_type: one object's events.
typesquery · string or array of stringEvent types, comma-separated, such as ticket-created,ticket-updated.
user_idsquery · string or array of stringOnly events these agents caused, comma-separated agent ids.
created_datetimequery · objectNot a value: use created_datetime[gte], [gt], [lte] or [lt].
created_datetime[gte]query · datetimeOnly events at or after this time.
created_datetime[gt]query · datetimeOnly events after this time.
created_datetime[lte]query · datetimeOnly events at or before this time.
created_datetime[lt]query · datetimeOnly 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

NameDescription
idrequiredpath · integerThe 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.

FieldTypeDescription
idinteger
uristring
typebigcommerce, custom, customer_external_data, http, magento2, recharge, shopify, smile, standalone, yotpo, klaviyo, stripe, woocommerce
contextticket, customer, userThe sidebar it shows in.
integration_idinteger or nullThe integration whose data it lays out.
app_idstring or nullThe app whose data it lays out, for app widgets.
orderintegerPosition in the sidebar, lowest first.
templateobject or nullThe layout, a tree such as {"type": "wrapper", "widgets": [...]}.
created_datetimedatetime or null
updated_datetimedatetime or null
deactivated_datetimedatetime or nullSet 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc, order:asc, order:desc
integration_idquery · stringOnly this integration's widgets.
app_idquery · stringOnly 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

FieldTypeDescription
typebigcommerce, custom, customer_external_data, http, magento2, recharge, shopify, smile, standalone, yotpo, klaviyo, stripe, woocommerce
contextticket, customer, user
integration_idinteger or string
app_idstring or null
orderinteger
templateobject
deactivated_datetimestring 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe widget's id.

Body

FieldTypeDescription
typebigcommerce, custom, customer_external_data, http, magento2, recharge, shopify, smile, standalone, yotpo, klaviyo, stripe, woocommerce
contextticket, customer, user
integration_idinteger or string
app_idstring or null
orderinteger
templateobject
deactivated_datetimestring 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

NameDescription
idrequiredpath · integerThe 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.

FieldTypeDescription
idinteger
uristring
typeapplyMacro, deleteTicket, exportTicket, importMacro, exportMacro, updateTicket, exportTicketDrilldown, exportConvertCampaignSalesDrilldownupdateTicket, applyMacro and deleteTicket run here.
statusscheduled, pending, running, done, errored, fatal_errored, cancel_requested, cancelederrored: finished, but some tickets could not be changed. fatal_errored: the job could not run; info.error says why.
paramsobjectWhat to change (updates, macro_id, apply_and_close) and which tickets (ticket_ids, view_id or view).
metaobject or nullWhatever the client sent as meta, returned as is.
infoobject
user_idinteger or nullThe agent who started it; the job acts as them.
created_datetimedatetime or null
updated_datetimedatetime or null
scheduled_datetimedatetime or null
started_datetimedatetime or null
ended_datetimedatetime or null
locked_datetimedatetime or nullSet while a run is working on it.
cancel_requested_datetimedatetime or null
cancelled_datetimedatetime or null
failed_datetimedatetime 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
statusquery · stringscheduled, pending, running, done, errored, fatal_errored, cancel_requested, canceled
typequery · stringapplyMacro, 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

FieldTypeDescription
typerequiredapplyMacro, deleteTicket, exportTicket, importMacro, exportMacro, updateTicket, exportTicketDrilldown, exportConvertCampaignSalesDrilldown
paramsrequiredobject
metaobject or null
scheduled_datetimestring 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe job's id.

Body

FieldTypeDescription
paramsobject
metaobject or null
scheduled_datetimestring or null
statusscheduled, 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

NameDescription
idrequiredpath · integerThe 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
FieldTypeDescription
urlstringWhere the file is served; put it in a message's attachments.
namestring
sizeintegerBytes.
content_typestring

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

NameDescription
typequery · stringWhat 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

NameDescription
idrequiredpath · integerThe object's id.
tokenrequiredpath · stringThe 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

NameDescription
file_typerequiredpath · stringOne of attachment, public_attachment, profile_picture, widget_picture.
domain_hashrequiredpath · stringAny value; not checked.
resource_namerequiredpath · stringThe 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)

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
FieldTypeDescription
dataobjectThe 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}]]}.
metaobject

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

NameDescription
limitquery · stringHow many rows to return, from 1 to 10000. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.

Body

FieldTypeDescription
queryrequiredobject

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

NameDescription
namerequiredpath · stringThe 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

FieldTypeDescription
filtersrequiredobject

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

NameDescription
namerequiredpath · stringThe statistic's name.

Body

FieldTypeDescription
filtersrequiredobject

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
FieldTypeDescription
slugstringThe card's id, such as median-first-response-time.
categorysupport-performance, quality, ticket-insights
titlestring
statuspublished, deprecated
definition_revised_atstringWhen the definition last changed.
publicobject
apiobjectThe POST /api/reporting/stats query that returns the figure.
aliasesarray of stringOther names people use for the figure.
relatedarray of object
replacesarray of stringSlugs of older cards this one replaces.
used_in_reportsarray of stringThe analytics reports that show the figure.
used_in_reports_linksarray of stringLinks 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

NameDescription
categoryquery · stringOnly cards in this category: support-performance, quality, ticket-insights.support-performance, quality, ticket-insights
statusquery · stringOnly cards with this status.published, deprecated
qquery · stringWords that must all appear in the card's slug, title, definition, formula or other names.
includequery · stringdeprecated: 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

NameDescription
slugrequiredpath · stringThe 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

NameDescription
slugrequiredpath · stringThe card's slug.

Body

FieldTypeDescription
disagreement_typerequireddefinition_unclear, formula_seems_wrong, edge_case_missing, otherWhat is wrong with the definition.
metric_categoryrequiredstringThe card's category, such as support-performance.
commentstringMore 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
FieldTypeDescription
idinteger
call_idinteger
ticket_idinteger or null
typestringincoming, flow_step, menu_choice, queued, ringing_agent, agent_missed, agent_declined, answered, recording_started, hold, resumed, transferred, voicemail_left, transcribed, ended, ...
user_idinteger or null
queue_idinteger or null
dataobject
created_datetimedatetime or null
The VoiceCallRecording object · 10 fields
FieldTypeDescription
idinteger
call_idinteger
ticket_idinteger or null
typecall, voicemail
urlstring or nullThe audio file; anyone with the link can play it.
durationinteger or null
transcriptionstring or null
transcription_statusnone, pending, done, skipped, failed
started_datetimedatetime or null
created_datetimedatetime or null
The VoiceCall object · 24 fields
FieldTypeDescription
idinteger
ticket_idinteger or null
integration_idinteger or nullThe voice line.
phone_number_idinteger or null
customer_idinteger or null
directioninbound, outbound
phone_number_sourcestring
phone_number_destinationstring
statusringing, in_flow, queued, connected, ended
outcomeanswered, missed, abandoned, cancelled, voicemail, forwarded, sms, rejected, no_answer, busy, failed, null or null
queue_idinteger or null
user_idinteger or nullThe agent who answered or placed the call.
initiated_by_user_idinteger or null
started_datetimedatetime or null
queued_datetimedatetime or null
answered_datetimedatetime or null
ended_datetimedatetime or null
wait_timeinteger or nullSeconds in the queue.
talk_timeinteger or nullSeconds connected to an agent.
durationinteger or nullSeconds from first ring to hangup.
recordingboolean
on_holdboolean
created_datetimedatetime or null
updated_datetimedatetime 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
call_idquery · stringOnly this call's events.
ticket_idquery · stringOnly 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
call_idquery · stringOnly this call's recordings.
ticket_idquery · stringOnly 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default created_datetime:desc.created_datetime:asc, created_datetime:desc
ticket_idquery · stringOnly 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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.

FieldTypeDescription
triageobjectKeyword and tag signals, VIP and high-value tags, channel points and targets, the wait clock and band thresholds.
draftingobjectenabled, voice_notes, redraft, auto_draft.
drafting_stateAiDraftingState
built_in_signalsarray of object
The AiTriage object · 14 fields

A ticket's triage score and the reasons it is made of.

FieldTypeDescription
ticket_idinteger
scoreinteger0 to 100.
bandurgent, high, normal, low
reasonsarray of AiTriageReason
awaiting_replybooleanTrue when the customer's message is the newest word on the thread.
awaiting_sincedatetime or nullThe customer message we owe a reply to.
wait_minutesinteger or nullMinutes the customer has waited, on the wait clock.
wait_clockbusiness, calendar
sla_due_datetimedatetime or nullWhen the next reply is due.
sla_sourcestring or nullWhat set the target: policy:<name>, channel:<channel> or band:<band>.
overdueboolean
noisebooleanSpam, trash or machine mail.
computed_datetimedatetime or null
uristring
The AiDraft object · 17 fields

A reply drafted for a person to review. Never sent automatically.

FieldTypeDescription
idinteger
ticket_idinteger
statusready, used, discarded, superseded
body_textstringThe drafted reply.
confidencenumber or null
needs_reviewboolean
notesstring or nullWhat to check before sending.
placeholdersarray of string
sourcesobject
providerstring
modelstring
thread_throughdatetime or null
currentbooleanFalse when a person wrote on the ticket after the draft was made.
triggeragent, redraft, auto, ai_agentai_agent: the helpdesk's AI agent wrote it with its own model.
authorobject or nullThe AI agent that wrote the draft, for ai_agent drafts.
created_datetimedatetime or null
uristring
The AiCommitments object · 2 fields

What the team already promised on a ticket.

FieldTypeDescription
ticket_idinteger
dataarray of AiCommitment
The AiDraftEnvelope object · 4 fields
FieldTypeDescription
ticket_idinteger
draftingAiDraftingState
draftAiDraft or null
ai_agentobjectThe 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.

FieldTypeDescription
ticket_idinteger
keywordsarray of string
dataarray 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

FieldTypeDescription
triageobject
draftingobject

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

NameDescription
ticket_idsrequiredquery · string or array of stringTicket 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
statusrequiredused, discardedused 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
body_textstring
notesstring or null
confidencenumber or null
skill_idsarray 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

NameDescription
idrequiredpath · integerThe object's id.
limitquery · stringHow 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

NameDescription
idrequiredpath · integerThe 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.

FieldTypeDescription
idinteger
namestring
descriptionstring
base_urlstring
auth_kindnone, header, bearer, basic
auth_headerstring or null
auth_usernamestring or null
secret_savedbooleanA key, token or password is saved. It is never returned.
needs_secretboolean
docs_urlstring or null
steps_countinteger
created_datetimedatetime or null
updated_datetimedatetime or null
uristring
The AiActionStep object · 16 fields

A reusable HTTP step.

FieldTypeDescription
idinteger
app_idinteger or null
app_namestring or null
namestring
descriptionstring
methodGET, POST, PUT, PATCH, DELETE
urlstringA path on the app, or a full https URL; {{variables}} allowed in the path and query.
headersarray of object
bodystringA JSON template.
inputsarray of AiActionInput
outputsarray of object
used_byarray of object
created_by_agent_idinteger or null
created_datetimedatetime or null
updated_datetimedatetime or null
uristring
The AiAgent object · 10 fields
FieldTypeDescription
namestring
linkedboolean
agentobject or null
keysarray of object
linked_datetimestring or null
skillsdraft, active
actionsobject
channelsobjectWhether the AI agent works on each channel: email, chat, contact_form, sms, phone, other.
skill_countsobject
youobject
The AiCustomAction object · 24 fields

An action the helpdesk built: steps in order, with the information to collect and the conditions.

FieldTypeDescription
idinteger
keystringcustom.<id>: the key skills use.
customboolean
appstring
namestring
descriptionstringNot shown to customers. Says when to use the action and when not.
modeon, ask, off
kindread, change, customer, money
appsarray of string
customer_confirmationbooleanThe customer must agree before it runs.
based_onstring or nullThe built-in action it was customized from.
inputsarray of AiActionInput
conditionsAiActionConditions
stepsarray of AiActionStepRef
statusin_use, not_in_use, off, needs_setup, failing
problemsarray of string
used_inarray of object
last_runobject or null
created_byobject or null
created_by_ai_agentboolean
updated_byobject or null
created_datetimedatetime or null
updated_datetimedatetime or null
uristring
The AiSkill object · 22 fields

How the helpdesk wants a situation handled, for the drafter and the AI agent to follow.

FieldTypeDescription
idinteger
namestring
when_to_usestringThe situations the skill is for, in the team's words. Drafting matches tickets against it.
intentsarray of string
instructionsstringThe steps, plain text. "If ..., then ..." steps work best; [BRACKETS] mark facts still to fill in.
actionsarray of string
use_knowledgebooleanFalse: the drafter follows the steps and the conversation only, without macros or earlier replies.
statusdraft, active, archived
sourceperson, ai_agent, generatedWho wrote it: a person, the AI agent, or generated from earlier replies.
template_keystring or null
replaces_skill_idinteger or nullSet on a proposed change to an active skill.
pending_approvalbooleanA draft waiting for a person.
generationobject or nullCounts only, for generated skills.
versioninteger
created_byobject or null
updated_byobject or null
activated_byobject or null
activated_datetimedatetime or null
created_datetimedatetime or null
updated_datetimedatetime or null
archived_datetimedatetime or null
uristring
The AiActionRun object · 16 fields

One run of a custom action, with each step's outcome: the event log.

FieldTypeDescription
idinteger
action_idinteger
action_namestring or null
ticket_idinteger or null
skillobject or null
run_byobject or null
by_ai_agentboolean
dry_runboolean
statussuccess, error, refused
customer_confirmedboolean
inputsobject
stepsarray of object
errorstring or null
created_datetimedatetime or null
finished_datetimedatetime or null
uristring
The AiActionStepTest object · 8 fields

What a test request sent and got back.

FieldTypeDescription
okboolean
http_statusinteger or null
errorstring or null
requestobject
responseanyThe app's answer: JSON, or {text} when it is not JSON.
outputsobjectEach output's value read from the answer.
msinteger
order_notestring or null
The AiQuestion object · 19 fields

A question a person asked the AI agent from the app, and its answer.

FieldTypeDescription
idinteger
chat_idinteger or nullThe chat this turn belongs to.
modeask_first, autoask_first: propose changes and wait for Approve. auto: make them within the agent's rules.
kindquestion, approval, rejection, routineapproval and rejection are a person's decision on the agent's last proposal; routine is a scheduled run.
proposalbooleanThe answer proposes changes and waits for the person's decision.
decisionapproved, rejected, null or null
decided_datetimedatetime or null
asked_byobject
textstring
pagestring or nullThe app path the person asked from.
ticket_idinteger or nullThe ticket they were on, if any.
statuspending, answering, answered, failed, cancelled
answerstring or null
failurestring or nullWhy the AI agent could not answer, in plain words.
answered_by_agent_idinteger or null
claimed_datetimedatetime or null
answered_datetimedatetime or null
created_datetimedatetime or null
uristring

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

FieldTypeDescription
namerequiredstring
descriptionstring
base_urlrequiredstring
auth_kindnone, header, bearer, basic
auth_headerstring or null
auth_usernamestring or null
secretstring or nullThe API key, token or password. Write-only: it is never returned.
docs_urlstring 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

FieldTypeDescription
app_idinteger or null
namerequiredstring
descriptionstring
methodGET, POST, PUT, PATCH, DELETE
urlrequiredstring
headersarray of object
bodystring
inputsarray of object
outputsarray 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

FieldTypeDescription
namestring
skillsdraft, active
actionsobject
channelsobject

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

FieldTypeDescription
namerequiredstring
descriptionstring
modeon, ask, off
customer_confirmationboolean
based_onstring or null
inputsarray of object
conditionsobject
stepsrequiredarray 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default name:asc.created_datetime:asc, created_datetime:desc, updated_datetime:asc, updated_datetime:desc, name:asc, name:desc
statusquery · stringOnly skills with this status.draft, active, archived
sourcequery · stringOnly skills written this way.person, ai_agent, generated
pending_approvalquery · stringOnly drafts waiting for a person.0, 1, true, false
searchquery · stringWords 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

FieldTypeDescription
namerequiredstring
when_to_usestring
intentsarray 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
instructionsrequiredstring
actionsarray of string
use_knowledgeboolean
statusdraft, active
template_keystring or null
sourcegenerated
generationobject 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namestring
descriptionstring
base_urlstring
auth_kindnone, header, bearer, basic
auth_headerstring or null
auth_usernamestring or null
secretstring or nullReplaces the saved key; null removes it; leave it out to keep it.
docs_urlstring 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
app_idinteger or null
namestring
descriptionstring
methodGET, POST, PUT, PATCH, DELETE
urlstring
headersarray of object
bodystring
inputsarray of object
outputsarray 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

NameDescription
idrequiredpath · integerThe 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

FieldTypeDescription
steprequiredobject
valuesobject
ticket_idinteger 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
}

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

NameDescription
openquery · stringAI agent only: false lists all recent questions, not just the waiting ones.0, 1, true, false
limitquery · stringAt 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

FieldTypeDescription
textrequiredstring
pagestring or null
ticket_idinteger or null
chat_idinteger or nullContinue this chat; a new chat starts when it is left out.
modeask_first, autoask_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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namestring
descriptionstring
modeon, ask, off
customer_confirmationboolean
inputsarray of object
conditionsobject
stepsarray 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namestring
when_to_usestring
intentsarray 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
instructionsstring
actionsarray of string
use_knowledgeboolean

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
valuesobjectValues for the step's inputs.
ticket_idinteger or nullA 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
ticket_idrequiredinteger
order_idstring or integerThe order the action is about: its name (#1001), number or id. Needed when a step acts on an order.
inputsobject
customer_confirmedbooleanThe customer agreed in the conversation. Needed when the action asks for confirmation.
skill_idinteger or nullThe skill that called for the action, for the usage report.
dry_runbooleanCheck 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

NameDescription
idrequiredpath · integerThe object's id.
statusquery · stringsuccess, error, refused
ticket_idquery · stringOnly runs on this ticket.
sincequery · datetimeFrom this time (ISO 8601).
untilquery · datetimeBefore this time.
dry_runquery · stringtrue: only dry runs; false: only real runs.0, 1, true, false
limitquery · stringAt 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
answerstring
failurestring
proposalboolean

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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.

FieldTypeDescription
idintegerThe ACR campaign id.
namestring
objectivestring
objective_labelstring
journeystring or nullcart_abandoned, post_purchase, after_delivery, win_back or one_off.
statusdraft, published, paused, archived
display_statussetup_not_completed, running, paused, archived
has_unpublished_changesboolean
agent_namestring or null
published_atdatetime or null
changed_atdatetime
statsobject
acr_urlstringThe campaign's setup in ACR.
The JourneyConnection object · 8 fields

The ACR store AI Journey uses. connected false when none.

FieldTypeDescription
connectedboolean
storeobject
roleviewer, member, admin, owner
can_draftbooleanThe key may make and edit drafts (member and up).
key_prefixstring
last_ok_datetimedatetime or null
last_errorstring or null
connected_datetimedatetime
The CustomerSegment object · 10 fields

A saved group of customers by their store data.

FieldTypeDescription
idinteger
namestring
descriptionstring or null
rulesarray of object
acrobject
customersinteger or nullCustomers the helpdesk knows who match, from its copy of the store data.
customers_knowninteger or nullCustomers with store data in the helpdesk.
cappedbooleanTrue when more than 50,000 customers have store data and only the first 50,000 were counted.
created_datetimedatetime
updated_datetimedatetime
The JourneyTest object · 4 fields

A simulated conversation run by ACR. Nothing is sent to anyone.

FieldTypeDescription
test_idstring
statusqueued, running, done, failed
transcriptarray of object
notestring

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

NameDescription
rangequery · stringlast_7_days, last_14_days, last_30_days, all_timedefault last_30_days
campaign_idquery · stringOnly 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

FieldTypeDescription
namerequiredstring
journeyrequiredcart_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

FieldTypeDescription
keyrequiredstring

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

FieldTypeDescription
namerequiredstring
descriptionstring or null
rulesrequiredarray 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namestring
descriptionstring or null
rulesarray 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
segment_idrequiredinteger

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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
smsstring
emailstring

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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
reasonstring 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
first_namerequiredstring
channelsms, email, call
languagestring 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
goalstring 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

NameDescription
idrequiredpath · integerThe object's id.
test_idrequiredpath · integer

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.

FieldTypeDescription
idinteger
titlestring
kindchat, routine
routineobject or null
ownerobject
yoursboolean
sharedbooleanTeammates can open the chat and add to it.
turnsinteger
waitingintegerTurns waiting for the AI agent.
proposalsintegerProposals waiting for a decision.
last_textstring or null
created_datetimedatetime or null
updated_datetimedatetime or null
uristring
messagesarray of AiQuestion
The AiRoutine object · 19 fields

A question the AI agent answers on a schedule.

FieldTypeDescription
idinteger
ownerobject
namestring
instructionsstring
frequencydaily, weekdays, weekly, monthly
hourinteger
minuteinteger
weekdayinteger or null1 Monday .. 7 Sunday, for weekly routines.
monthdayinteger or null1..28, for monthly routines.
timezonestring
schedulestringThe schedule in words.
modeask_first, auto
template_keystring or null
pausedboolean
next_run_datetimedatetime or null
last_run_datetimedatetime or null
created_datetimedatetime or null
updated_datetimedatetime or null
uristring

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

NameDescription
searchquery · stringWords in the title, a question or an answer.
kindquery · stringchat, routine
routine_idquery · stringRuns of this routine.
limitquery · stringAt 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

FieldTypeDescription
textrequiredstring
modeask_first, auto
titlestring or null
sharedboolean
pagestring or null
ticket_idinteger 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

FieldTypeDescription
namerequiredstring
instructionsrequiredstring
frequencydaily, weekdays, weekly, monthly
hourinteger
minuteinteger
weekdayinteger or null
monthdayinteger or null
timezonestring
modeask_first, auto
template_keystring or null
pausedboolean

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
titlestring
sharedboolean

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namestring
instructionsstring
frequencydaily, weekdays, weekly, monthly
hourinteger
minuteinteger
weekdayinteger or null
monthdayinteger or null
timezonestring
modeask_first, auto
pausedboolean

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
decisionrequiredapproved, rejected
reasonstring 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
textrequiredstring
modeask_first, auto
pagestring or null
ticket_idinteger 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

NameDescription
idrequiredpath · integerThe 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

FieldTypeDescription
agentobject
chatsarray 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

NameDescription
namequery · stringOnly 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

FieldTypeDescription
namerequiredstring
business_hours_configrequiredobject
assigned_integrationsobject

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

FieldTypeDescription
namerequiredstring
start_daterequiredstring
end_daterequiredstring
holiday_hours_configobject or null
repeats_yearlyboolean
assigned_integrationsarray 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe schedule's id.

Body

FieldTypeDescription
namestring
business_hours_configobject
assigned_integrationsobject

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe holiday's id.

Body

FieldTypeDescription
namestring
start_datestring
end_datestring
holiday_hours_configobject or null
repeats_yearlyboolean
assigned_integrationsarray 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

FieldTypeDescription
start_daterequiredstring
end_daterequiredstring
repeats_yearlyboolean
holiday_hours_configany
integration_idsarray of integer or object
holiday_hours_idinteger 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
FieldTypeDescription
modeoff, growth_dept, standaloneoff: not billed. growth_dept: Telnyx's cost passed through to the Growth Dept billing account. standalone: cost plus a markup.
telephony_enabledbooleanWhether Growth Dept switched voice and SMS on for this helpdesk.
openbooleanWhether invoices can be made now.
closed_reasonmode_off, no_key, bad_key, live_gate, no_customer, other_mode, null or null
closed_textstring or null
stripe_modetest, live, null or null
markup_pctnumber
customer_linkedboolean
cardobject or nullThe card that pays calls and texts: its brand, last four digits and expiry, never the number.
pay_bycard, invoicecard: the monthly invoice charges the card. invoice: Stripe emails the invoice to pay within 14 days.
wordingobject
gd_billobjectThe tick that lets the same card pay the brand's Growth Dept bill.
usageobjectThis month so far, in the helpdesk's time zone.
invoicesarray of TelephonyBillingInvoice
covered_by_growth_deptarray of string
can_manageboolean
The TelephonyBillingCardOption object · 10 fields
FieldTypeDescription
payment_method_idstring
brandstring
last4string
exp_monthinteger
exp_yearinteger
fundingstring or null
labelstring
gd_bill_defaultbooleanThe card Growth Dept's invoices are charged to now.
in_usebooleanThe card that pays calls and texts.
wordingstringThe 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

FieldTypeDescription
pay_bycard, invoice
card_for_gd_billboolean
wording_seenstringThe 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

FieldTypeDescription
payment_method_idrequiredstring
wording_seenrequiredstringThe 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
FieldTypeDescription
widgetsintegerChat widgets in the helpdesk.
online_agentsintegerAgents online for chat now.
me_onlinebooleanWhether you count as online: status available and a role that answers chats.
availabilityavailable, busy, offlineYour status.
availability_reasonstring or nullYour away reason or status name, while away.
status_idinteger or nullThe status you picked, if any.
availability_untildatetime or nullWhen your status ends, for a status with a duration.
auto_assignbooleanAuto-assignment is on: keep calling every minute, even from a hidden tab, to stay eligible.
The ChatWidget object · 19 fields
FieldTypeDescription
idinteger
uristring
public_idstringThe random id in the widget's public addresses.
namestringThe widget's name, shown to agents.
default_languageen, fr, de, esThe language visitors get when the widget does not offer theirs.
languagesarray of en, fr, de, esThe languages the window offers, the default first.
integration_idinteger or nullThe mailbox for offline messages and replies to customers who left.
mailboxobject or null
help_center_idinteger or nullThe help center the window links to.
help_centerobject or null
allowed_originsarray of stringSites the widget may run on. Empty: any site.
settingsobject
script_urlstringThe script a site adds to show the launcher.
chat_urlstringThe chat page the script frames; it also works on its own.
snippetstringThe script tag to paste before </body>.
statusobjectWhether the chat is live now and why not.
created_datetimedatetime or null
updated_datetimedatetime or null
deleted_datetimedatetime or null
The ArticleSuggestionTest object · 4 fields
FieldTypeDescription
help_center_idinteger or nullThe help center searched; null when the chat has none.
languagestring or nullThe language searched.
thresholdnumberThe lowest score the chat's strength suggests.
articlesarray of object
The ChatTicketLive object · 2 fields
FieldTypeDescription
chatobject or nullThe ticket's chat conversation; null for a ticket that did not come from chat.
messagesarray of MessageMessages after the one given, notes included.
The ChatVisitorState object · 5 fields
FieldTypeDescription
statuslive, offline
conversationobject
messagesarray of object
agent_typingstring or nullThe name of the agent typing, or null.
suggestionobject or nullHelp 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
FieldTypeDescription
statuslive, offline
conversationobject
messagesarray of object
agent_typingstring or nullThe name of the agent typing, or null.
suggestionobject or nullHelp center articles suggested for the first message and waiting for an answer: on the start, and on a poll from the beginning (after=0).
tokenstringThe visitor token: send it as Authorization: Bearer on later calls.
The ChatOrders object · 2 fields
FieldTypeDescription
emailstringThe verified address.
ordersarray of object
The ChatStatus object · 1 fields
FieldTypeDescription
statuslive, offline
The ChatVisitorMessage object · 1 fields
FieldTypeDescription
messageobject
The ChatFlowView object · 5 fields

What the chat window shows after starting a flow or answering a step.

FieldTypeDescription
flowobject
runobject
answerstring or nullWhat the visitor answered, to show as their message.
messagesarray of object
nextobjectWhat 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
FieldTypeDescription
verificationstringSend it back with the code.
expires_inintegerSeconds the code works.
The ChatOrderSession object · 2 fields
FieldTypeDescription
tokenstringThe order session: send it as Authorization: Bearer.
expires_inintegerSeconds it lasts.
The ChatSuggestionAnswer object · 2 fields
FieldTypeDescription
outcomeresolved, escalated
closedbooleanThe 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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

FieldTypeDescription
namestringThe widget's name, shown to agents.
default_languageen, fr, de, esThe language visitors get when the widget does not offer theirs.
languagesarray of en, fr, de, esThe languages the window offers; it follows the visitor's browser among them.
integration_idinteger or stringThe mailbox for offline messages and replies to customers who left: a Gmail or forwarding mailbox in this helpdesk. null for none.
help_center_idinteger or stringA help center whose newest articles the window links to while it is live. null for none.
allowed_originsarray of stringSites the widget may run on, such as https://shop.example.com. Empty: any site.
settingsobjectLook, 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe chat widget's id.

Body

FieldTypeDescription
namestringThe widget's name, shown to agents.
default_languageen, fr, de, esThe language visitors get when the widget does not offer theirs.
languagesarray of en, fr, de, esThe languages the window offers; it follows the visitor's browser among them.
integration_idinteger or stringThe mailbox for offline messages and replies to customers who left: a Gmail or forwarding mailbox in this helpdesk. null for none.
help_center_idinteger or stringA help center whose newest articles the window links to while it is live. null for none.
allowed_originsarray of stringSites the widget may run on, such as https://shop.example.com. Empty: any site.
settingsobjectLook, 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe chat widget's id.

Body

FieldTypeDescription
messagerequiredstringA first message as a visitor might write it.
languageen, fr, de, esThe visitor's language; the chat's default when left out.
help_center_idinteger or stringTry another help center than the saved one; null tries the chat's own help center.
strengthbroad, balanced, strictTry another strength than the saved one.
excludearray of integer or stringTry 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

NameDescription
idrequiredpath · integerThe ticket's id.
afterquery · stringOnly 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
idrequiredpath · integerThe ticket's id.

Body

FieldTypeDescription
typingbooleanfalse 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe widget's public id.
run_idrequiredpath · integerThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe widget's public id.
suggestion_idrequiredpath · integerThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe widget's public id.
flow_idrequiredpath · integerThe 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

NameDescription
helpdeskrequiredpath · stringThe helpdesk's slug.
public_idrequiredpath · stringThe widget's public id.
order_idrequiredpath · integerThe 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
FieldTypeDescription
idinteger
uristring
namestringAgents see it in the list; visitors see it on the flow's button.
languageen, fr, de, es
enabledbooleanOff hides the flow from every chat.
stepsarray of FlowStep
step_countintegerSteps in the whole tree.
widgetsarray of objectThe chats that offer this flow.
created_datetimedatetime or null
updated_datetimedatetime or null

List flows

GET/api/flows

The helpdesk's flows, by name, each with its steps and the chats that offer it.

Parameters

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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

FieldTypeDescription
namestringThe flow's name: agents see it in the list, visitors on the flow's button in the chat window.
languageen, fr, de, esThe language the flow is written in. A chat shows it to visitors whose window is in this language.
enabledbooleanOff hides the flow from every chat.
stepsarray of anyThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe flow's id.

Body

FieldTypeDescription
namestringThe flow's name: agents see it in the list, visitors on the flow's button in the chat window.
languageen, fr, de, esThe language the flow is written in. A chat shows it to visitors whose window is in this language.
enabledbooleanOff hides the flow from every chat.
stepsarray of anyThe 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

NameDescription
idrequiredpath · integerThe 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
FieldTypeDescription
idinteger
uristring
namestringShown to agents.
slugstringThe last part of the public address, /hc/<helpdesk>/<slug>.
default_languageen, fr, de, esThe language the help center's own address shows.
languagesarray of en, fr, de, esEvery language the help center publishes in, the default first.
livebooleanCustomers can open the public site only while this is true.
urlstringThe public home page in the default language.
urlsobjectThe public home page in each language.
contactobjectThe contact card at the bottom of the home and article pages.
settingsobject
articles_countinteger
published_articles_countintegerArticles published in at least one of the help center's languages.
created_datetimedatetime or null
updated_datetimedatetime or nullWhen the help center, or anything in it, last changed.
The HelpCenterSearchHit object · 11 fields
FieldTypeDescription
article_idinteger
help_center_idinteger
help_center_namestring
languageen, fr, de, es
titlestringThe published title.
excerptstringThe excerpt, or the body's first words.
snippetstringA passage around the words found; U+0001 and U+0002 surround each match.
category_idinteger or null
category_namestring or null
urlstringThe article's public page.
published_datetimedatetime or null
The HelpCenterArticle object · 9 fields
FieldTypeDescription
idinteger
uristring
help_center_idinteger
category_idinteger or nullnull when uncategorized.
positionintegerOrder within its category, lowest first.
translationsobjectThe article in each language it has.
created_by_agent_idinteger or null
created_datetimedatetime or null
updated_datetimedatetime or null
The HelpCenterCategory object · 8 fields
FieldTypeDescription
idinteger
uristring
help_center_idinteger
positionintegerOrder on the home page, lowest first.
translationsobjectThe category's words in each language it has.
articles_countinteger
created_datetimedatetime or null
updated_datetimedatetime 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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

FieldTypeDescription
namestringThe help center's name, shown to agents. Also the brand name until one is set.
slugstringThe last part of the public address, /hc/<helpdesk>/<slug>. Made from the name when left out.
default_languageen, fr, de, esThe language the help center's own address shows.
languagesarray of en, fr, de, esEvery language the help center publishes in, the default included.
livebooleanCustomers can open the public site only while this is true.
contact_form_idinteger or stringThe contact form the contact card opens. null for none.
contact_integration_idinteger or stringA mailbox whose address the contact card links to when no contact form is set. null for none.
settingsobjectLook, 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe help center's id.

Body

FieldTypeDescription
namestringThe help center's name, shown to agents. Also the brand name until one is set.
slugstringThe last part of the public address, /hc/<helpdesk>/<slug>. Made from the name when left out.
default_languageen, fr, de, esThe language the help center's own address shows.
languagesarray of en, fr, de, esEvery language the help center publishes in, the default included.
livebooleanCustomers can open the public site only while this is true.
contact_form_idinteger or stringThe contact form the contact card opens. null for none.
contact_integration_idinteger or stringA mailbox whose address the contact card links to when no contact form is set. null for none.
settingsobjectLook, 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
qquery · stringWords to find in titles, excerpts and bodies. Partial words match their beginning.
languagequery · stringOnly articles in this language.en, fr, de, es
help_center_idquery · stringOnly this help center.
limitquery · stringAt 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

NameDescription
idrequiredpath · integerThe help center's id.
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort field and direction. Default position:asc.position:asc, position:desc, created_datetime:asc, created_datetime:desc, updated_datetime:asc, updated_datetime:desc
category_idquery · "none" or stringA category id, or none for uncategorized articles.
languagequery · stringOnly articles with a translation in this language.en, fr, de, es
statequery · stringpublished: published in language (or in any language). draft: not.draft, published
searchquery · stringWords 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

NameDescription
idrequiredpath · integerThe help center's id.

Body

FieldTypeDescription
languagestringWhich language the title, slug, excerpt and body are in. Defaults to the help center's default language.
titlestringRequired when the article has no translation in this language yet.
slugstringThe 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.
excerptstring or nullA short summary shown in lists and search results. Without one, the body's first words are used.
body_htmlstringThe article in HTML. Scripts, styles, event handlers and links other than http(s), mailto and tel are removed when it is saved.
category_idinteger or stringThe category the article is in; null for none.
positionintegerOrder within its category, lowest first.
publishbooleantrue 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

NameDescription
idrequiredpath · integerThe help center's id.
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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

NameDescription
idrequiredpath · integerThe help center's id.

Body

FieldTypeDescription
languagestringWhich language the name, slug and description are in. Defaults to the help center's default language.
namestringThe category's name in that language. Required when the category has no name in it yet.
slugstringThe last part of the category's address in that language. Made from the name when left out.
descriptionstring or nullA line under the name on the help center's home page.
positionintegerOrder 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe help center's id.
articleIdrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe help center's id.
articleIdrequiredpath · integerThe article's id.

Body

FieldTypeDescription
languagestringWhich language the title, slug, excerpt and body are in. Defaults to the help center's default language.
titlestringRequired when the article has no translation in this language yet.
slugstringThe 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.
excerptstring or nullA short summary shown in lists and search results. Without one, the body's first words are used.
body_htmlstringThe article in HTML. Scripts, styles, event handlers and links other than http(s), mailto and tel are removed when it is saved.
category_idinteger or stringThe category the article is in; null for none.
positionintegerOrder within its category, lowest first.
publishbooleantrue 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

NameDescription
idrequiredpath · integerThe help center's id.
articleIdrequiredpath · integerThe article's id.
languagequery · stringDelete 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

NameDescription
idrequiredpath · integerThe help center's id.

Body

FieldTypeDescription
category_idrequiredinteger or stringThe category the listed articles are in after the move; null for uncategorized.
article_idsrequiredarray of integer or stringArticle 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

NameDescription
idrequiredpath · integerThe help center's id.
categoryIdrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe help center's id.
categoryIdrequiredpath · integerThe category's id.

Body

FieldTypeDescription
languagestringWhich language the name, slug and description are in. Defaults to the help center's default language.
namestringThe category's name in that language. Required when the category has no name in it yet.
slugstringThe last part of the category's address in that language. Made from the name when left out.
descriptionstring or nullA line under the name on the help center's home page.
positionintegerOrder 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

NameDescription
idrequiredpath · integerThe help center's id.
categoryIdrequiredpath · integerThe category's id.
languagequery · stringDelete 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

NameDescription
idrequiredpath · integerThe help center's id.

Body

FieldTypeDescription
category_idsrequiredarray of integer or stringCategory 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

NameDescription
idrequiredpath · integerThe help center's id.
articleIdrequiredpath · integerThe article's id.

Body

FieldTypeDescription
languagestringThe 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

NameDescription
idrequiredpath · integerThe help center's id.
articleIdrequiredpath · integerThe article's id.

Body

FieldTypeDescription
languagestringThe 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.

FieldTypeDescription
idinteger
uristring
typegorgias, zendeskWhere the import copies from.
statuspending, running, done, failed, cancelled
paramsobject
metaobject
userobject or nullThe agent who started it.
created_datetimedatetime or null
updated_datetimedatetime or null
started_datetimedatetime or null
ended_datetimedatetime 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.

FieldTypeDescription
idinteger
uristring
integration_idintegerThe Gmail mailbox (an integration of type gmail).
addressstring or nullThe mailbox's address.
sincedatetimeMail received from this moment...
untildatetime...up to, not including, this one.
statuspending, running, done, failed, cancelled
close_ticketsbooleanWhether the tickets it opens start closed.
progressobject
errorstring or nullWhy it stopped, when it failed.
userobject or nullThe agent who started it.
created_datetimedatetime or null
updated_datetimedatetime or null
started_datetimedatetime or null
ended_datetimedatetime 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

NameDescription
limitquery · integerHow many objects to return, from 1 to 100. Default 30.
cursorquery · stringWhere to continue: meta.next_cursor or meta.prev_cursor from the previous page.
order_byquery · stringSort 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

FieldTypeDescription
sourcegorgias, zendeskWhere to import from: gorgias (the default) or zendesk.
domainrequiredstringThe account's subdomain: acme for acme.gorgias.com or acme.zendesk.com.
emailrequiredstringGorgias: the email of the person the API key belongs to. Zendesk: the email of the admin the API token belongs to.
api_keyrequiredstringA Gorgias REST API key, or a Zendesk API token, used only for this import.
objectsarray of customers, tickets, tags, macros, views, rulesWhat 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

FieldTypeDescription
integration_idrequiredintegerThe Gmail mailbox's integration id.
sincerequiredstringThe first day, such as 2025-01-01 (UTC), or an ISO time.
untilrequiredstringThe last day, included, such as 2025-06-30 (UTC), or an ISO time, not included.
close_ticketsbooleanOpen 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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.

FieldTypeDescription
idinteger
chatobject
namestring
languagestring
statusdraft, active, paused
runningbooleanActive and inside its dates.
conditionsarray of object
delay_secondsinteger
deviceall, desktop, mobile
allow_repliesboolean
include_unknownbooleanWith customer conditions, also show to visitors the store does not know.
fromobject or null
variantsarray of object
discount_codestring or null
productsarray of object
email_captureboolean
starts_datetimedatetime or null
ends_datetimedatetime or null
template_keystring or null
created_datetimedatetime
updated_datetimedatetime
uristring

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

NameDescription
chat_idquery · stringOnly 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

FieldTypeDescription
widget_idrequiredinteger
namerequiredstring
languagestring
conditionsarray of object
delay_secondsinteger
deviceall, desktop, mobile
allow_repliesboolean
include_unknownboolean
from_agent_idinteger or null
variantsrequiredarray of object
discount_codestring or null
productsarray of object
email_captureboolean
starts_datetimedatetime or null
ends_datetimedatetime or null
statusdraft, active, paused
template_keystring 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

FieldTypeDescription
enabledboolean
chatsarray of integer
max_per_visitinteger
minutes_betweeninteger
hide_days_after_closeinteger

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

NameDescription
sincequery · datetime
untilquery · datetime
ordersquery · stringInclude 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
widget_idinteger
namestring
languagestring
conditionsarray of object
delay_secondsinteger
deviceall, desktop, mobile
allow_repliesboolean
include_unknownboolean
from_agent_idinteger or null
variantsarray of object
discount_codestring or null
productsarray of object
email_captureboolean
starts_datetimedatetime or null
ends_datetimedatetime or null
statusdraft, active, paused
template_keystring 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
goalstring 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
FieldTypeDescription
settingsobject
storeobject or nullThe store orders come from; null when none is connected.
mailobject
widgetsarray 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

FieldTypeDescription
settingsrequiredany

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
FieldTypeDescription
idinteger
phone_numberstringE.164, such as +14155550123.
namestring
countrystring
typelocal, toll_free, mobile, national
statuspending, active, failed, releasedpending until Telnyx finishes the order, usually seconds.
status_detailstring or null
capabilitiesarray of string
costobjectWhat the number costs Growth Dept. It is never billed to the helpdesk.
registrationobject
integrationsarray of object
created_datetimedatetime or null
updated_datetimedatetime or null
The AvailablePhoneNumber object · 6 fields
FieldTypeDescription
e164string
regionstring or null
localitystring or null
upfront_cost_usdstring or null
monthly_cost_usdstring or null
featuresarray 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

FieldTypeDescription
phone_numberrequiredstring
namestring
countryUS, 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe phone number's id.

Body

FieldTypeDescription
namerequiredstring

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
countryquery · stringUS, CAdefault US
typequery · stringlocal, toll_freedefault local
area_codequery · string
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.

FieldTypeDescription
idintegerThe integration id.
typestringAlways shopify.
namestring
shopstringThe store's myshopify.com domain.
shop_namestring or null
statusactive, uninstalled, disconnected, redacted, token_invalid
activebooleanTrue when the helpdesk can read the store now.
install_typeoauth, custom_app, gd_connectHow 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.
currencystring or nullThe store's currency.
timezonestring or null
scopesarray of stringScopes the token holds.
missing_read_scopesarray of stringRead scopes the sidebar needs and the token lacks.
missing_action_scopesarray of stringScopes order actions need and the token lacks.
missing_extra_scopesarray of stringScopes for editing orders, discount codes and syncing customers to Shopify that the token lacks; only those actions are refused.
actions_enabledbooleanOrder actions are on. They start on when the store links with the scopes they need, as Gorgias's Shopify actions do.
agents_can_execute_moneybooleanAgents (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.
webhooksarray of stringShopify topics that notify the helpdesk of changes.
webhook_notestring or nullWhy notifications are missing, when they are.
fleet_slugstring or nullThe Growth Dept brand a gd_connect store belongs to.
refreshwebhooks, pollingHow changes in the store reach the helpdesk: Shopify's notifications, or, for a gd_connect store, a check every few minutes.
polled_datetimedatetime or nullWhen the helpdesk last looked for changes (polling stores).
poll_errorstring or nullWhy the last check for changes did not finish.
last_errorstring or null
connected_datetimedatetime or null
checked_datetimedatetime or null
created_datetimedatetime or null
deactivated_datetimedatetime or null
admin_urlstringThe store's Shopify admin.
The ShopifyActionLogEntry object · 15 fields
FieldTypeDescription
idinteger
integration_idinteger or null
plan_idstring or null
actionstring
outcomeplanned, requested, done, failed, refused, replayed
order_idstring or null
order_namestring or null
ticket_idinteger or null
customer_idinteger or null
user_idinteger or null
moneyboolean
amountstring or null
currencystring or null
detailanyIds, codes and short reasons.
created_datetimedatetime or null
The ShopifyProduct object · 5 fields

An active product and its variants.

FieldTypeDescription
idinteger or string
titlestring
image_urlstring or null
tracks_inventoryboolean
variantsarray of object
The ShopifyLinkTicket object · 2 fields

A one-time link for connecting the store to a helpdesk.

FieldTypeDescription
urlstringThe link page, with the ticket. Open it in a new tab.
expires_inintegerSeconds until the ticket expires.
The ShopifyEmbeddedSession object · 9 fields

What the Shopify app's page shows.

FieldTypeDescription
shopstringThe store's myshopify.com domain, from the ID token.
shop_namestring or null
scopesarray of stringScopes Shopify granted the app on this store.
missing_scopesarray of stringRead scopes the sidebar needs that Shopify has not granted.
missing_action_scopesarray of stringScopes order actions need that Shopify has not granted.
token_exchangedbooleanTrue when this call exchanged the ID token for a new access token.
helpdeskobject or nullThe helpdesk the store is linked to, or null.
planShopifyPlan
plan_requiredbooleanTrue 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.

FieldTypeDescription
billingshopify, not_checked, outside_shopifyshopify: 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.
stateactive, none, unknown, null or nullactive: the store has a plan. none: it has not chosen one. unknown: Shopify did not answer; try again.
namestring or nullThe plan's name in Shopify.
handlestring or nullThe plan's handle in Shopify.
billing_periodstring or nullEVERY_30_DAYS or ANNUAL.
trial_ends_datetimedatetime or nullWhen the free trial ends, during a trial.
current_period_end_datetimedatetime or nullWhen the current billing period ends.
cancel_at_period_endbooleanTrue when the plan stops at the end of the current period.
plans_urlstring or nullShopify's page for choosing or changing the plan. Open it at the top level of the Shopify admin.
checked_datetimedatetime or nullWhen Shopify was asked.
messagestring or nullWhy 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.

FieldTypeDescription
previewbooleanAlways true: nothing was stored.
actionrefund, cancel, duplicate, replacement, edit_address, resend_confirmation, edit_note, edit_tags, edit_order, remove_item, replace_item, create_order, sync_customer, create_discount
labelstring
moneybooleanMoves money or gives goods away.
integration_idinteger
orderobject or nullThe order, for an order action: id and name.
effectanyWhat the action would do, as in a plan, with its figures.
The ShopifyMetafields object · 3 fields
FieldTypeDescription
orderobjectThe order, for an order's metafields.
shopify_customer_idinteger or string or nullThe Shopify customer, for a customer's metafields.
dataarray of object
The ShopifyCustomerSummary object · 3 fields

A customer's data from every connected store.

FieldTypeDescription
customer_idinteger
storesarray of ShopifyStoreSummary
problemobject or nullSet 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
FieldTypeDescription
orderobject
estimated_delivery_datetimedatetime or nullThe latest expected date of the shipments still on their way.
delivered_datetimedatetime or nullWhen the last shipment arrived, once all have.
shipmentsarray of object
The ShopifyOrderReturns object · 2 fields
FieldTypeDescription
orderobject
dataarray of object
The ShopifyOrderTimeline object · 2 fields
FieldTypeDescription
orderobject
dataarray 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

FieldTypeDescription
shoprequiredstringThe store's myshopify.com domain or its admin URL.
access_tokenrequiredstringThe custom app's Admin API access token (shpat_...).
api_secretstring or nullThe 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

NameDescription
ticket_idquery · string
customer_idquery · string
order_idquery · string
limitquery · stringAt 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

NameDescription
integration_idquery · stringThe 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

NameDescription
searchquery · string
integration_idquery · stringThe 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

NameDescription
queryquery · stringWords from the title, a SKU or a barcode.
integration_idquery · stringThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
namestring
actions_enabledboolean
agents_can_execute_moneyboolean

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

NameDescription
idrequiredpath · integerThe 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

FieldTypeDescription
shoprequiredstringThe store's myshopify.com domain or its admin URL.
actionsbooleanAsk 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

NameDescription
fresh_planquery · string1 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

NameDescription
actionrequiredpath · stringcreate_order | sync_customer | create_discount

Body

FieldTypeDescription
plan_idrequiredstring
confirm_anotherbooleanMake 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

NameDescription
actionrequiredpath · stringcreate_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

NameDescription
actionrequiredpath · stringcreate_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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.
refreshquery · stringAsk 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

NameDescription
idrequiredpath · integerThe object's id.
integration_idquery · stringThe 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

NameDescription
idrequiredpath · integerThe object's id.
refreshquery · stringRead from Shopify now instead of using the copy.0, 1, true, false
integration_idquery · stringOnly 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
integration_idintegerThe store, when the helpdesk has more than one.
addarray of stringTags to add to the Shopify customer.
removearray of stringTags 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

NameDescription
idrequiredpath · stringShopify's numeric order id.
ticket_idquery · stringThe ticket; its customer must own the order.
customer_idquery · stringThe helpdesk customer, when there is no ticket.
integration_idquery · stringThe 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

NameDescription
idrequiredpath · stringShopify's numeric order id.
ticket_idquery · stringThe ticket; its customer must own the order.
customer_idquery · stringThe helpdesk customer, when there is no ticket.
integration_idquery · stringThe 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

NameDescription
idrequiredpath · stringShopify's numeric order id.
ticket_idquery · stringThe ticket; its customer must own the order.
customer_idquery · stringThe helpdesk customer, when there is no ticket.
integration_idquery · stringThe 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

NameDescription
idrequiredpath · stringShopify's numeric order id.
ticket_idquery · stringThe ticket; its customer must own the order.
customer_idquery · stringThe helpdesk customer, when there is no ticket.
integration_idquery · stringThe 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

NameDescription
idrequiredpath · stringShopify's numeric order id.
actionrequiredpath · stringrefund | cancel | duplicate | replacement | edit_address | resend_confirmation | edit_note | edit_tags | edit_order | remove_item | replace_item

Body

FieldTypeDescription
plan_idrequiredstring
confirm_anotherbooleanMake 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

NameDescription
idrequiredpath · stringShopify's numeric order id.
actionrequiredpath · stringrefund | 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

NameDescription
idrequiredpath · stringShopify's numeric order id.
actionrequiredpath · stringrefund | 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

NameDescription
target_channelquery · stringOnly 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

FieldTypeDescription
namerequiredstring
metricsarray of object
activeboolean
target_channelsrequiredarray of string
business_hours_onlyboolean
filtersarray of object
targetnumber 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

NameDescription
uuidrequiredpath · stringThe 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

NameDescription
uuidrequiredpath · stringThe policy's uuid.

Body

FieldTypeDescription
namestring
metricsarray of object
activeboolean
target_channelsarray of string
business_hours_onlyboolean
filtersarray of object
targetnumber or null
prioritynumber 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

NameDescription
uuidrequiredpath · stringThe 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
FieldTypeDescription
idinteger
namestring
phone_number_idinteger
phone_numberstring
registrationobjectListed lines only: the number's carrier registration.
The SmsOptOut object · 4 fields
FieldTypeDescription
phone_numberstring
opted_out_datetimedatetime or null
keywordstring or null
sourcekeyword, 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.

FieldTypeDescription
idinteger
kindten_dlc, toll_free
statusdraft, in_review, sending, brand_pending, campaign_pending, approved, rejected, withdrawndraft: 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_labelstring
status_explanationstringWhat the status means and what happens next.
status_detailstring or nullThe latest step, in a sentence.
detailsobjectThe business and campaign details. Below admin, the EIN and the contact's email and phone are masked.
phone_numbersarray of object
problemsobjectWhat stops it being sent, for a draft or a turned-down one.
warningsobjectWhat often gets a registration turned down, without stopping it.
review_notestring or nullGrowth Dept's note when it sent the registration back.
failure_reasonsstring or nullWhy the carriers or Telnyx turned it down.
failure_fieldsarray of stringDetails fields the carriers' feedback points at.
carrierobject
historyarray of object
feesobjectWhat the carriers charge Growth Dept for it. Never billed to the helpdesk.
can_editboolean
can_submitboolean
can_withdrawboolean
submitted_datetimedatetime or null
reviewed_datetimedatetime or null
sent_datetimedatetime or null
approved_datetimedatetime or null
rejected_datetimedatetime or null
created_datetimedatetime or null
updated_datetimedatetime 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

FieldTypeDescription
namestring
phone_number_idrequiredinteger

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

NameDescription
phone_numberquery · string

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

FieldTypeDescription
kindrequiredten_dlc, toll_free
detailsobjectFields to set on top of the prefilled details.
phone_number_idsarray of integerDefaults 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe SMS line's id.

Body

FieldTypeDescription
namerequiredstring

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe registration's id.

Body

FieldTypeDescription
detailsobject
phone_number_idsarray of integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
kindrequiredquery · stringten_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

NameDescription
idrequiredpath · integerThe 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
FieldTypeDescription
idinteger
namestring
phone_number_idinteger
phone_numberstring
settingsobject
flowobjectThe 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.
warningsarray of objectParts of the flow that may not work as meant.
The VoiceQueue object · 14 fields
FieldTypeDescription
idinteger
namestring
enabledboolean
prioritybooleanCalls in priority queues ring before any others.
capacityinteger or nullMost callers waiting at once; null for no limit.
distributionround_robin, broadcastround_robin rings one agent at a time, longest idle first; broadcast rings every available agent.
ring_team_idinteger or nullOnly this team's members are rung; null rings every available agent.
ring_secsintegerHow long each agent is rung.
max_wait_secsintegerHow long a caller waits before the call flow moves on.
wrapup_enabledboolean
wrapup_secsinteger
hold_music_file_idinteger or nullAn uploaded recording; null plays the built-in music.
waitingintegerCallers waiting now.
linesarray of objectVoice 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

FieldTypeDescription
tostring
customer_idinteger
ticket_idinteger
integration_idrequiredinteger

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

FieldTypeDescription
namestring
phone_number_idrequiredinteger
settingsobject
flowany

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

FieldTypeDescription
namerequiredstring
enabledboolean
priorityboolean
capacityinteger or null
distributionround_robin, broadcast
ring_team_idinteger or null
ring_secsinteger
max_wait_secsinteger
wrapup_enabledboolean
wrapup_secsinteger
hold_music_file_idinteger 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

NameDescription
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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe voice line's id.

Body

FieldTypeDescription
namestring
phone_number_idinteger
settingsobject
flowany

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe queue's id.

Body

FieldTypeDescription
namestring
enabledboolean
priorityboolean
capacityinteger or null
distributionround_robin, broadcast
ring_team_idinteger or null
ring_secsinteger
max_wait_secsinteger
wrapup_enabledboolean
wrapup_secsinteger
hold_music_file_idinteger 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

NameDescription
idrequiredpath · integerThe 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

FieldTypeDescription
readyrequiredboolean

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

NameDescription
idrequiredpath · integerThe voice call's id.

Body

FieldTypeDescription
actionrequiredhold, resume, record_start, record_pause, record_resume, transfer, hangup
to_agent_idinteger
to_queue_idinteger
to_numberstring

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.

FieldTypeDescription
idinteger
periodobject
statuspending, done, failed
requested_byobject or null
chat_idinteger or nullThe Assistant chat that carried the request.
summarystring or null
themesarray of object
recommendationsarray of string
tickets_readinteger or null
failurestring or null
created_datetimedatetime
completed_datetimedatetime or null
uristring

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

NameDescription
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

NameDescription
limitquery · stringAt 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

FieldTypeDescription
startrequiredstring
endrequiredstring

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

NameDescription
idrequiredpath · integerThe 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

NameDescription
idrequiredpath · integerThe object's id.

Body

FieldTypeDescription
summarystring
themesarray of object
recommendationsarray of string
tickets_readinteger
failurestring

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.