BluetickedDeveloper docs

Conversations

5 endpoints, each with examples that open in the console prefilled.

All resourcesGuide: Conversations
GET/api/v1/conversationsconversations:readTry in console

List conversations

Read conversation state for inbox, CRM sync, or support tooling.

  • Use cursor pagination when syncing large inboxes.
  • Page with ?limit= (max 200, default 50) and ?cursor= (the previous page's next_cursor: the oldest last_message_at on the page).
  • Filter by ?status= (open | pending | resolved).
curl -X GET "https://app.blueticked.com/api/v1/conversations" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "data": [
    {
      "id": "fa3efd47-67b2-428c-b75f-17d1dd2e9790",
      "contact_id": "ff506e53-e2f0-4d92-884a-dab77d628bad",
      "business_id": "8070c984-41f6-4bfa-900b-1ce8750ad439",
      "channel": "whatsapp",
      "status": "open",
      "last_message_at": "2026-05-22T10:30:00.000Z",
      "last_message_preview": "Yes, 2pm works",
      "unread_count": 1,
      "created_at": "2026-05-20T09:00:00.000Z",
      "updated_at": "2026-05-22T10:30:00.000Z"
    }
  ],
  "next_cursor": null,
  "has_more": false,
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
PATCH/api/v1/conversations/{id}conversations:writeTry in console

Update conversation

Assign, resolve, or reopen a conversation from support tooling.

Body parameters
statusstring
assigned_tonull
  • status: open | pending | resolved. assigned_to: a workspace user id, or null to unassign.
  • The assignee must be a current member of this workspace who can open the conversation: access to its business, or an owner or admin when it has none. Otherwise the call answers validation_failed with details.reason assignee_not_member or assignee_cannot_open, and nothing changes.
  • Resolving hands the conversation back to flow, as Done in the Inbox does: a hand-over pause is lifted, so flows answer the customer's next message. While a ticket on the conversation is open or in progress, the hand-over stays.
  • To reply into a conversation, use POST /api/v1/messages; the send pipeline routes by contact.
curl -X PATCH "https://app.blueticked.com/api/v1/conversations/{id}" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "resolved",
  "assigned_to": null
}'
Response
{
  "conversation": {
    "business_id": "8070c984-41f6-4bfa-900b-1ce8750ad439",
    "contact_id": "ff506e53-e2f0-4d92-884a-dab77d628bad",
    "unread_count": 0,
    "last_message_at": "2026-05-22T10:30:00.000Z",
    "created_at": "2026-05-20T09:00:00.000Z",
    "updated_at": "2026-05-22T10:30:00.000Z",
    "id": "fa3efd47-67b2-428c-b75f-17d1dd2e9790",
    "channel": "whatsapp",
    "status": "resolved",
    "assigned_to": null
  },
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
GET/api/v1/conversations/{id}conversations:readTry in console

Get a conversation

Fetch a single conversation's state.

  • The conversation is wrapped under conversation.
curl -X GET "https://app.blueticked.com/api/v1/conversations/{id}" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "conversation": {
    "business_id": "8070c984-41f6-4bfa-900b-1ce8750ad439",
    "contact_id": "ff506e53-e2f0-4d92-884a-dab77d628bad",
    "unread_count": 0,
    "last_message_at": "2026-05-22T10:30:00.000Z",
    "created_at": "2026-05-20T09:00:00.000Z",
    "updated_at": "2026-05-22T10:30:00.000Z",
    "id": "fa3efd47-67b2-428c-b75f-17d1dd2e9790",
    "channel": "whatsapp",
    "status": "open",
    "assigned_to": null
  },
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
GET/api/v1/conversations/{id}/messagesconversations:readTry in console

List conversation messages

Read the message history (inbound and outbound) for one conversation, oldest first.

Query parameters
limitstring
  • This is how you read inbound replies; for a real-time feed subscribe to the message.received webhook instead of polling.
  • Messages come oldest first and the cursor walks forward, so ?limit=1 returns the first message in the conversation, not the newest reply. Take the newest reply from the message.received webhook (it carries message_id and the body), or page through to the end; the SDK's messagesAll() walks every page for you.
  • Always branch on has_media, not on body. A customer who sends a photo or a PDF with no caption produces an empty body. Without has_media that is indistinguishable from an empty text message, and the attachment is silently missed.
  • media_status is pending while we fetch the asset from WhatsApp, downloaded once it is stored, and failed when the download permanently gave up. Treat failed as terminal: WhatsApp's media handle has expired by then and the asset cannot be recovered. Poll or wait for the webhook rather than assuming a null media_url means there is no attachment.
  • To fetch a file, call media_download_path with your API key (GET /api/v1/conversations/{id}/messages/{messageId}/media): it answers with a signed URL that works for five minutes. media_download_path is null when the message has no file.
  • media_url is deprecated and will be removed on 2027-04-15: use media_download_path. Until then it is a signed link minted for each read that works for one hour (it was the stored link before, which for files you sent stayed valid for seven days). Never store it: read it again, or call the download path, when you need the file.
curl -X GET "https://app.blueticked.com/api/v1/conversations/{id}/messages?limit=50" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "data": [
    {
      "id": "763c4dc3-d46b-4c10-8bd4-3f233a933ea0",
      "direction": "inbound",
      "body": "Yes, 2pm works",
      "status": "delivered",
      "is_draft": false,
      "created_at": "2026-05-22T10:30:00.000Z",
      "updated_at": "2026-05-22T10:30:00.000Z",
      "has_media": false,
      "media_type": null,
      "media_mime": null,
      "media_filename": null,
      "media_status": null,
      "media_download_path": null,
      "media_url": null
    },
    {
      "id": "089542d5-2dc1-4619-8063-38a4eda42716",
      "direction": "inbound",
      "body": "",
      "status": "delivered",
      "is_draft": false,
      "created_at": "2026-05-22T10:31:00.000Z",
      "updated_at": "2026-05-22T10:31:00.000Z",
      "has_media": true,
      "media_type": "document",
      "media_mime": "application/pdf",
      "media_filename": "invoice-4471.pdf",
      "media_status": "downloaded",
      "media_download_path": "/api/v1/conversations/fa3efd47-67b2-428c-b75f-17d1dd2e9790/messages/089542d5-2dc1-4619-8063-38a4eda42716/media",
      "media_url": "https://…/storage/v1/object/sign/inbound-media/…/invoice-4471.pdf?token=…"
    }
  ],
  "next_cursor": null,
  "has_more": false,
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
GET/api/v1/conversations/{id}/messages/{messageId}/mediaconversations:readTry in console

Get a message's file

A short-lived signed URL for one message's photo, video, audio, sticker or document, with its type, MIME type and filename.

  • The URL works for five minutes (until expires_at) and is minted for each call: download the file straight away, and call again when you need it later. Files are private; a URL is never reused.
  • Take the path from a message's media_download_path in the messages list. A message with no file, or one in a conversation your key cannot see, answers 404 not_found.
  • While the file is still being fetched from the channel (media_status pending) the answer is 409 conflict with details.reason media_pending: retry in a few seconds. When the fetch failed for good (media_status failed) it is 404 not_found with details.reason media_unavailable.
curl -X GET "https://app.blueticked.com/api/v1/conversations/{id}/messages/{messageId}/media" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "data": {
    "url": "https://…/storage/v1/object/sign/inbound-media/…/invoice-4471.pdf?token=…",
    "expires_at": "2026-05-22T10:36:00.000Z",
    "media_type": "document",
    "media_mime": "application/pdf",
    "media_filename": "invoice-4471.pdf"
  },
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}