Skip to content

REST API reference

Read and write conversations, messages, contacts and help center articles of your asktrix workspace. JSON over HTTPS, one token per workspace.

The API is available on the Team and Business plans. It works on exactly one workspace: the one the token belongs to. Changes you make through the API behave like clicks in the app. Your team sees them right away, replies reach the visitor, and webhooks fire.

Prefer a machine-readable description? /api/v1/openapi.json is an OpenAPI 3.1 document generated from the same source as this page. Import it into Postman, Insomnia or a client generator.

Base URL

https://asktrix.org/api/v1

Requests and responses are JSON in UTF-8. Timestamps are ISO 8601 in UTC.

Authentication

Create a token under Settings → Workspace → API & webhooks → Create token. Only owners and admins can do this. Pick a permission and an expiry:

  • Read only tokens can only send GET requests.
  • Read & write tokens can also reply, change status, assignment and labels, and create or change contacts.
  • Expiry: never, 30 days, 90 days or one year. A workspace can have up to 50 active tokens.

The token is shown once. We only store a fingerprint, so a lost token can't be recovered. Revoke it and create a new one. Send it in the Authorization header:

curl "https://asktrix.org/api/v1/me" \
  -H "Authorization: Bearer atx_XXXXXXXX_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

Replies sent with "as": "user" (the default) appear under the name of the teammate who created the token. If that person has left the workspace, they're sent on behalf of the workspace. Internal notes need a creator who is still a member, and snoozing needs a creator whose account still exists.

Plans and rate limits

PlanRequests per minute, per workspace
Free, StartNo API access. Requests answer 402 plan_locked.
Team60
Business300 (can be raised in your contract)

Every response carries X-RateLimit-Limit and X-RateLimit-Remaining. Over the limit you get 429 rate_limited with Retry-After: 60.

Pagination

List endpoints return up to limit items (default 25, maximum 100), newest first, wrapped in data. If hasMore is true, request the next page with cursor=nextCursor. Cursors are opaque. Don't build them yourself.

{
  "data": [ … ],
  "hasMore": true,
  "nextCursor": "MjAyNi0xMS0wNVQx…"
}

Sort order: conversations by their last message, messages and contacts by creation time, articles by their last change. updated_since on conversations filters by the last message, too.

Errors

Errors always have the same shape. For validation errors, field names the field.

{
  "error": {
    "code": "validation_failed",
    "message": "status must be pending, unresolved or resolved.",
    "field": "status"
  }
}
StatusCodeWhen
400invalid_jsonThe body isn't a JSON object.
400invalid_parameterA query parameter has the wrong format (e.g. a date that isn't ISO 8601).
400invalid_cursorThe cursor is malformed.
401unauthorizedThe token is missing, malformed, unknown or revoked.
401token_expiredThe token has expired.
402plan_lockedThe workspace's plan doesn't include the API (Team and up).
403insufficient_scopeA read-only token tried to write.
403suspendedThe workspace is suspended.
404not_foundThe object doesn't exist in this workspace, or the endpoint doesn't exist.
413payload_too_largeThe body is larger than 200 KB.
422validation_failedA field is invalid. error.field names it.
429rate_limitedToo many requests. Wait for Retry-After seconds.
500internal_errorSomething went wrong on our side.

Within v1 we only add fields to responses. We don't rename or remove them, so ignore fields you don't know.

Basics

GET/api/v1/me

Check the workspace and token. Needs a token with read permission.

Request

curl "https://asktrix.org/api/v1/me" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN"

Response

{
  "workspace": {
    "id": "cm1w0…",
    "slug": "acme",
    "name": "Acme"
  },
  "token": {
    "id": "cm9t2…",
    "name": "CRM sync",
    "prefix": "atx_PmybkW4L",
    "scopes": [
      "read",
      "write"
    ],
    "expiresAt": null
  }
}

Conversations

GET/api/v1/conversations

List and filter conversations. Needs a token with read permission.

ParameterInTypeDescription
statusquerypending | unresolved | resolved | openFilter or set the status (open = pending + unresolved)
mailboxquerymain | spam | automated | <mailboxId>Mailbox
labelquerystringOnly with this label
assignee_idqueryuserId | noneAssigned person, none = nobody
contact_idquerystringOnly conversations of this contact
updated_sincequeryISO 8601Only changed since (conversations: last message)
limitquery1–100 (25)Items per page
cursorquerystringnextCursor of the previous page

Request

curl "https://asktrix.org/api/v1/conversations?status=open&limit=10" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN"

Response

{
  "data": [
    {
      "id": "cm4p1…",
      "status": "unresolved",
      "mailbox": "main",
      "channel": "chat",
      "subject": null,
      "assigneeId": "cm3a9…",
      "labels": [
        "billing"
      ],
      "customData": {},
      "aiActive": false,
      "unread": true,
      "lastMessage": "Hi, I was charged twice this month.",
      "lastFrom": "visitor",
      "lastMessageAt": "2026-11-05T10:12:00.000Z",
      "snoozedUntil": null,
      "resolvedAt": null,
      "firstResponseAt": null,
      "createdAt": "2026-11-05T10:11:42.000Z",
      "contactId": "cm2k7…",
      "contact": {
        "id": "cm2k7…",
        "name": "Lena Fischer",
        "email": "[email protected]",
        "country": "DE"
      }
    }
  ],
  "hasMore": true,
  "nextCursor": "MjAyNi0xMS0wNVQx…"
}

GET/api/v1/conversations/{id}

One conversation with its latest 100 messages. Needs a token with read permission.

ParameterInTypeDescription
idrequiredpathstringID from the URL

Request

curl "https://asktrix.org/api/v1/conversations/CONVERSATION_ID" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN"

Response

{
  "data": {
    "id": "cm4p1…",
    "status": "unresolved",
    "mailbox": "main",
    "channel": "chat",
    "subject": null,
    "assigneeId": "cm3a9…",
    "labels": [
      "billing"
    ],
    "customData": {},
    "aiActive": false,
    "unread": true,
    "lastMessage": "Hi, I was charged twice this month.",
    "lastFrom": "visitor",
    "lastMessageAt": "2026-11-05T10:12:00.000Z",
    "snoozedUntil": null,
    "resolvedAt": null,
    "firstResponseAt": null,
    "createdAt": "2026-11-05T10:11:42.000Z",
    "contactId": "cm2k7…",
    "contact": {
      "id": "cm2k7…",
      "name": "Lena Fischer",
      "email": "[email protected]",
      "country": "DE"
    },
    "messages": [
      {
        "id": "cm5d3…",
        "conversationId": "cm4p1…",
        "from": "teammate",
        "type": "text",
        "content": "Sorry about that. I've refunded the second charge.",
        "internal": false,
        "author": {
          "id": "cm3a9…",
          "name": "Jamie Weber"
        },
        "readAt": null,
        "editedAt": null,
        "createdAt": "2026-11-05T10:14:08.000Z"
      }
    ]
  }
}

PATCH/api/v1/conversations/{id}

Change status, assignment, labels or snooze. Needs a token with write permission.

ParameterInTypeDescription
idrequiredpathstringID from the URL
statusbodypending | unresolved | resolvedFilter or set the status (open = pending + unresolved)
assigneeIdbodyuserId | nullAssign a teammate, null unassigns
labelsbodystring[]Replace all labels
addLabelsbodystring[]Add labels
removeLabelsbodystring[]Remove labels
snoozedUntilbodyISO 8601 | nullSnooze until, null ends the snooze

Request

curl -X PATCH "https://asktrix.org/api/v1/conversations/CONVERSATION_ID" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status":"resolved","addLabels":["billing"]}'

Response

{
  "data": {
    "id": "cm4p1…",
    "status": "resolved",
    "mailbox": "main",
    "channel": "chat",
    "subject": null,
    "assigneeId": "cm3a9…",
    "labels": [
      "billing"
    ],
    "customData": {},
    "aiActive": false,
    "unread": true,
    "lastMessage": "Hi, I was charged twice this month.",
    "lastFrom": "visitor",
    "lastMessageAt": "2026-11-05T10:12:00.000Z",
    "snoozedUntil": null,
    "resolvedAt": null,
    "firstResponseAt": null,
    "createdAt": "2026-11-05T10:11:42.000Z",
    "contactId": "cm2k7…",
    "contact": {
      "id": "cm2k7…",
      "name": "Lena Fischer",
      "email": "[email protected]",
      "country": "DE"
    }
  }
}

GET/api/v1/conversations/{id}/messages

All messages of a conversation, page by page. Needs a token with read permission.

ParameterInTypeDescription
idrequiredpathstringID from the URL
limitquery1–100 (25)Items per page
cursorquerystringnextCursor of the previous page

Request

curl "https://asktrix.org/api/v1/conversations/CONVERSATION_ID/messages?limit=10" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN"

Response

{
  "data": [
    {
      "id": "cm5d3…",
      "conversationId": "cm4p1…",
      "from": "teammate",
      "type": "text",
      "content": "Sorry about that. I've refunded the second charge.",
      "internal": false,
      "author": {
        "id": "cm3a9…",
        "name": "Jamie Weber"
      },
      "readAt": null,
      "editedAt": null,
      "createdAt": "2026-11-05T10:14:08.000Z"
    }
  ],
  "hasMore": true,
  "nextCursor": "MjAyNi0xMS0wNVQx…"
}

POST/api/v1/conversations/{id}/messages

Reply or write an internal note. Needs a token with write permission.

ParameterInTypeDescription
idrequiredpathstringID from the URL
contentrequiredbodystringMessage text (Markdown)
typebodytext | notenote = internal note, visible to the team only
asbodyuser | workspaceuser = as the token's creator, workspace = on behalf of the workspace

Request

curl -X POST "https://asktrix.org/api/v1/conversations/CONVERSATION_ID/messages" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"Thanks, we found your order.","as":"user"}'

Response

{
  "data": {
    "id": "cm5d3…",
    "conversationId": "cm4p1…",
    "from": "teammate",
    "type": "text",
    "content": "Sorry about that. I've refunded the second charge.",
    "internal": false,
    "author": {
      "id": "cm3a9…",
      "name": "Jamie Weber"
    },
    "readAt": null,
    "editedAt": null,
    "createdAt": "2026-11-05T10:14:08.000Z"
  }
}

Contacts

GET/api/v1/contacts

List and search contacts. Needs a token with read permission.

ParameterInTypeDescription
emailquerystringE-mail address
qquerystringFull-text search
labelquerystringOnly with this label
identifiedquerytrueOnly contacts with a name, e-mail or phone
updated_sincequeryISO 8601Only changed since (conversations: last message)
limitquery1–100 (25)Items per page
cursorquerystringnextCursor of the previous page

Request

curl "https://asktrix.org/api/v1/contacts?limit=10" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN"

Response

{
  "data": [
    {
      "id": "cm2k7…",
      "name": "Lena Fischer",
      "displayName": "Lena Fischer",
      "email": "[email protected]",
      "phone": null,
      "avatarUrl": null,
      "company": {
        "name": "Fischer Design"
      },
      "labels": [
        "vip"
      ],
      "customData": {
        "plan": "pro"
      },
      "city": "Hamburg",
      "country": "DE",
      "timezone": "Europe/Berlin",
      "languages": [
        "de",
        "en"
      ],
      "blocked": false,
      "unsubscribed": false,
      "marketingConsent": false,
      "consentAt": null,
      "consentSource": null,
      "lastSeenAt": "2026-11-05T10:11:40.000Z",
      "createdAt": "2026-10-02T08:30:00.000Z",
      "updatedAt": "2026-11-05T10:11:42.000Z"
    }
  ],
  "hasMore": true,
  "nextCursor": "MjAyNi0xMS0wNVQx…"
}

POST/api/v1/contacts

Create a contact. If the e-mail already exists, the existing contact comes back (200). Needs a token with write permission.

ParameterInTypeDescription
emailbodystringE-mail address
namebodystringName
phonebodystringPhone number
companybodystringCompany name
citybodystringCity
countrybodyISO 3166-1 alpha-2Country
labelsbodystring[]Replace all labels
customDatabodyobjectCustom data (text, number, yes/no)
marketingConsentbodybooleanDocumented consent to marketing emails (source "api"). Only contacts with consent receive email campaigns.
consentTextbodystringWording the contact agreed to (proof)

Request

curl -X POST "https://asktrix.org/api/v1/contacts" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","name":"Lena Fischer","labels":["vip"],"customData":{"plan":"pro"}}'

Response (201 when created, 200 when the email already existed)

{
  "data": {
    "id": "cm2k7…",
    "name": "Lena Fischer",
    "displayName": "Lena Fischer",
    "email": "[email protected]",
    "phone": null,
    "avatarUrl": null,
    "company": {
      "name": "Fischer Design"
    },
    "labels": [
      "vip"
    ],
    "customData": {
      "plan": "pro"
    },
    "city": "Hamburg",
    "country": "DE",
    "timezone": "Europe/Berlin",
    "languages": [
      "de",
      "en"
    ],
    "blocked": false,
    "unsubscribed": false,
    "marketingConsent": false,
    "consentAt": null,
    "consentSource": null,
    "lastSeenAt": "2026-11-05T10:11:40.000Z",
    "createdAt": "2026-10-02T08:30:00.000Z",
    "updatedAt": "2026-11-05T10:11:42.000Z"
  },
  "existed": false
}

GET/api/v1/contacts/{id}

Get one contact. Needs a token with read permission.

ParameterInTypeDescription
idrequiredpathstringID from the URL

Request

curl "https://asktrix.org/api/v1/contacts/CONTACT_ID" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN"

Response

{
  "data": {
    "id": "cm2k7…",
    "name": "Lena Fischer",
    "displayName": "Lena Fischer",
    "email": "[email protected]",
    "phone": null,
    "avatarUrl": null,
    "company": {
      "name": "Fischer Design"
    },
    "labels": [
      "vip"
    ],
    "customData": {
      "plan": "pro"
    },
    "city": "Hamburg",
    "country": "DE",
    "timezone": "Europe/Berlin",
    "languages": [
      "de",
      "en"
    ],
    "blocked": false,
    "unsubscribed": false,
    "marketingConsent": false,
    "consentAt": null,
    "consentSource": null,
    "lastSeenAt": "2026-11-05T10:11:40.000Z",
    "createdAt": "2026-10-02T08:30:00.000Z",
    "updatedAt": "2026-11-05T10:11:42.000Z"
  }
}

PATCH/api/v1/contacts/{id}

Change a contact. customData is merged, null removes a key. Needs a token with write permission.

ParameterInTypeDescription
idrequiredpathstringID from the URL
namebodystring | nullName
emailbodystring | nullE-mail address
phonebodystring | nullPhone number
citybodystring | nullCity
countrybodystring | nullCountry
companybodystring | object | nullCompany name
labelsbodystring[]Replace all labels
customDatabodyobjectCustom data (text, number, yes/no)
blockedbodybooleanBlock the contact
marketingConsentbodybooleanDocumented consent to marketing emails (source "api"). Only contacts with consent receive email campaigns.
consentTextbodystringWording the contact agreed to (proof)

Request

curl -X PATCH "https://asktrix.org/api/v1/contacts/CONTACT_ID" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"labels":["vip","newsletter"],"customData":{"plan":"business","trial":null}}'

Response

{
  "data": {
    "id": "cm2k7…",
    "name": "Lena Fischer",
    "displayName": "Lena Fischer",
    "email": "[email protected]",
    "phone": null,
    "avatarUrl": null,
    "company": {
      "name": "Fischer Design"
    },
    "labels": [
      "vip",
      "newsletter"
    ],
    "customData": {
      "plan": "business"
    },
    "city": "Hamburg",
    "country": "DE",
    "timezone": "Europe/Berlin",
    "languages": [
      "de",
      "en"
    ],
    "blocked": false,
    "unsubscribed": false,
    "marketingConsent": false,
    "consentAt": null,
    "consentSource": null,
    "lastSeenAt": "2026-11-05T10:11:40.000Z",
    "createdAt": "2026-10-02T08:30:00.000Z",
    "updatedAt": "2026-11-05T10:11:42.000Z"
  }
}

Help center

GET/api/v1/help-center/articles

Help center articles, published ones by default. Needs a token with read permission.

ParameterInTypeDescription
statusquerypublished | draft | allFilter or set the status (open = pending + unresolved)
localequeryen, de, …Language
category_idquerystringCategory
qquerystringFull-text search
updated_sincequeryISO 8601Only changed since (conversations: last message)
limitquery1–100 (25)Items per page
cursorquerystringnextCursor of the previous page

Request

curl "https://asktrix.org/api/v1/help-center/articles?limit=10" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN"

Response

{
  "data": [
    {
      "id": "cm6b8…",
      "locale": "en",
      "slug": "reset-your-password",
      "title": "Reset your password",
      "description": "Get a new password if you can't sign in.",
      "status": "published",
      "hidden": false,
      "featured": false,
      "category": {
        "id": "cm6a1…",
        "name": "Account"
      },
      "url": "https://asktrix.org/help/acme/en/reset-your-password",
      "views": 412,
      "helpful": 37,
      "unhelpful": 2,
      "publishedAt": "2026-09-14T12:00:00.000Z",
      "createdAt": "2026-09-14T11:40:00.000Z",
      "updatedAt": "2026-10-28T09:05:00.000Z"
    }
  ],
  "hasMore": true,
  "nextCursor": "MjAyNi0xMS0wNVQx…"
}

GET/api/v1/help-center/articles/{id}

One article with its content as HTML and text. Needs a token with read permission.

ParameterInTypeDescription
idrequiredpathstringID from the URL

Request

curl "https://asktrix.org/api/v1/help-center/articles/ARTICLE_ID" \
  -H "Authorization: Bearer $ASKTRIX_TOKEN"

Response

{
  "data": {
    "id": "cm6b8…",
    "locale": "en",
    "slug": "reset-your-password",
    "title": "Reset your password",
    "description": "Get a new password if you can't sign in.",
    "status": "published",
    "hidden": false,
    "featured": false,
    "category": {
      "id": "cm6a1…",
      "name": "Account"
    },
    "url": "https://asktrix.org/help/acme/en/reset-your-password",
    "views": 412,
    "helpful": 37,
    "unhelpful": 2,
    "publishedAt": "2026-09-14T12:00:00.000Z",
    "createdAt": "2026-09-14T11:40:00.000Z",
    "updatedAt": "2026-10-28T09:05:00.000Z",
    "contentHtml": "<p>…</p>",
    "contentText": "…"
  }
}