Skip to content
Documentation
pozyskajpacjentaDocs

API referenceConversations

Get a conversation

GET/api/v1/conversations/{id}

Since
1.14.0
Auth
Bearer key
operationId
getConversation

One conversation with its patient, the channels a message can go out on now (and why not, for the others), and the clinic's reply templates filled in for this patient (empty when the clinic does not use templates). Use it before POST /conversations/{id}/messages to pick a channel that will be accepted. Needs the scope conversations:read; the read is written to the clinic's audit log. The response holds patient data and is never cached (Cache-Control: no-store); call it from your server only.

Request

Send the clinic's key in Authorization: Bearer (see API keys).

Path parameters

  • idstringrequired

    The conversation id (conversationId of webhook events).

curl "https://app.pozyskajpacjenta.pl/api/v1/conversations/Vb3nQ8sLk2PzX5wRt9YcE" \
  -H "Authorization: Bearer $PP_API_KEY"
import { PozyskajPacjentaClient } from "@pozyskajpacjenta/sdk";

const client = new PozyskajPacjentaClient({
  apiKey: process.env.PP_API_KEY ?? "",
  baseUrl: "https://app.pozyskajpacjenta.pl",
});

const { conversation, channels, templates } = await client.getConversation(
  "Vb3nQ8sLk2PzX5wRt9YcE",
);
<?php
$response = wp_remote_get(
    'https://app.pozyskajpacjenta.pl/api/v1/conversations/Vb3nQ8sLk2PzX5wRt9YcE',
    array(
        'headers' => array( 'Authorization' => 'Bearer ' . getenv( 'PP_API_KEY' ) ),
        'timeout' => 10,
    )
);
if ( is_wp_error( $response ) ) {
    error_log( $response->get_error_message() );
    return;
}
$status = wp_remote_retrieve_response_code( $response );
$data   = json_decode( wp_remote_retrieve_body( $response ), true );

Response

200The conversation.

  • conversationConversationrequired

    The conversation.

    Fields (9)
    • idstringrequired

      Conversation id.

    • statusstringrequired

      open or closed. The clinic closes a conversation in its inbox; a new message from the patient opens it again.

      One of openclosed

    • leadConversationLeadrequired

      The patient.

      Fields (9)
      • idstringrequired

        The lead id: the leadId POST /leads returns and webhook events carry.

      • namestring | nullrequired

        The patient's name; null when unknown.

      • phonestring | nullrequired

        The patient's phone; null when unknown.

      • emailstring | nullrequired

        The patient's e-mail; null when unknown.

      • messagestring | nullrequired

        The enquiry the patient sent: a form's message or the first chat message. null when there was none.

      • sourcestringrequired

        Where the lead came from: form, embed, api, manual, inbound or chat.

      • stagestringrequired

        The lead's stage in the clinic's CRM, e.g. new, scheduled, visited, not_interested.

      • locationIdstring | nullrequired

        The clinic location the enquiry is for (GET /locations); null when not known.

      • createdAtstring (date-time)required

        When the lead was created.

    • lastChannelstring | nullrequired

      Channel of the newest message: email, sms, whatsapp, instagram, chat (the chat on the clinic's site) or, since 1.15.0, messenger (the clinic's Facebook Page). null before the first message.

      One of emailsmswhatsappinstagramchatmessenger

    • lastMessageAtstring (date-time) | nullrequired

      Time of the newest message; null before the first one.

    • lastInboundAtstring (date-time) | nullrequired

      Time of the patient's newest message; null when the patient has not written.

    • unreadCountintegerrequired

      The patient's messages nobody at the clinic has opened yet.

    • createdAtstring (date-time)required

      When the conversation began.

    • updatedAtstring (date-time)required

      The later of the conversation's last change (a message, a read, open or closed) and the lead's (stage, contact data). The updated_since filter compares with it; delivery receipts do not change it.

  • channelsConversationChannelState[]required

    Every channel, in a fixed order, with whether a message can go out on it now.

    Fields of each item (3)
    • channelstringrequired

      The channel: email, sms, whatsapp, instagram, chat (the chat on the clinic's site) or, since 1.15.0, messenger (the clinic's Facebook Page).

      One of emailsmswhatsappinstagramchatmessenger

    • availablebooleanrequired

      true when a message sent now would be accepted.

    • reasonstring | nullrequired

      Why not, when available is false: the code a send would get in its 409 (see SendRefused). null when available.

      One of lead_archivedopted_outno_emailemail_domain_not_configuredno_phoneno_smsapi_tokenchat_not_startedmeta_platform_disabledwa_not_configuredwa_window_closedig_not_configuredig_no_user_idig_no_user_threadig_window_closedfb_not_configuredfb_no_user_threadfb_window_closedtemplate_not_foundtemplate_channeladdress_requiredaddress_unknownchat_disabled

  • templatesConversationTemplate[]required

    The clinic's reply templates, filled in for this patient.

    Fields of each item (4)
    • idstringrequired

      Template id: the templateId of POST /conversations/{id}/messages.

    • namestringrequired

      The template's name in the clinic's inbox.

    • textstringrequired

      The text the patient would get.

    • channelsstring[] | nullrequired

      The channels the template suits; null means every channel.

      One of emailsmswhatsappinstagramchatmessenger

  • identitiesConversationIdentity[]required

    Since 1.16.0: the patient's addresses per channel, with the one a message goes to by default.

    Fields of each item (7)
    • channelstringrequired

      sms, whatsapp, email, instagram or messenger (a number is listed for SMS and WhatsApp).

      One of smswhatsappemailinstagrammessenger

    • addressstringrequired

      The number (E.164), the e-mail address (lower case) or the patient's Instagram or Messenger id: the to of POST /conversations/{id}/messages.

    • primarybooleanrequired

      The lead's own phone, e-mail address or Instagram id: reminders and the clinic's other automated messages go there.

    • verifiedbooleanrequired

      The patient wrote from it. An address the clinic added by hand is false until the patient writes from it.

    • optedOutbooleanrequired

      The address opted out of messages on this channel (an SMS STOP from this number): nothing goes to it, the patient's other addresses are not affected.

    • replyDefaultbooleanrequired

      A message on this channel without to goes here.

    • lastInboundAtstring (date-time) | nullrequired

      The patient's newest message from this address on this channel; null when none.

  • mergedEnquiriesConversationMergedEnquiry[]required

    Since 1.18.0: the enquiries of the leads the clinic merged into this conversation's lead, oldest first; empty when none. The clinic's inbox shows them in the conversation at their own time.

    Fields of each item (5)
    • leadIdstringrequired

      The merged lead's own id.

    • textstringrequired

      What the patient wrote: a form's message, the first chat message, a Lead Ads answer. Written by the patient: show it as their words.

    • sourcestringrequired

      Where the merged lead came from, like lead.source: form, embed, api, manual, inbound or chat.

    • channelstring | nullrequired

      For a manual or inbound lead, how it came: phone or in_person (entered by the clinic) or missed_call; null otherwise. New values may be added.

      One of phonein_personmissed_call

    • createdAtstring (date-time)required

      When the patient sent it (the merged lead's creation).

A conversation: SMS available, e-mail opted out (templates trimmed to two)

{
  "conversation": {
    "id": "Vb3nQ8sLk2PzX5wRt9YcE",
    "status": "open",
    "lead": {
      "id": "rS2bIhedVSStSQLc7DL_T",
      "name": "Anna Kowalska",
      "phone": "+48 600 100 200",
      "email": "anna.kowalska@example.com",
      "message": "Proszę o kontakt w sprawie higienizacji.",
      "source": "form",
      "stage": "scheduled",
      "locationId": "loc_wieliczka",
      "createdAt": "2026-10-12T07:41:09.000Z"
    },
    "lastChannel": "sms",
    "lastMessageAt": "2026-10-12T08:02:44.000Z",
    "lastInboundAt": "2026-10-12T08:02:44.000Z",
    "unreadCount": 1,
    "createdAt": "2026-10-12T07:52:10.000Z",
    "updatedAt": "2026-10-12T08:02:44.000Z"
  },
  "channels": [
    {
      "channel": "email",
      "available": false,
      "reason": "opted_out"
    },
    {
      "channel": "sms",
      "available": true,
      "reason": null
    },
    {
      "channel": "whatsapp",
      "available": false,
      "reason": "wa_window_closed"
    },
    {
      "channel": "instagram",
      "available": false,
      "reason": "ig_not_configured"
    },
    {
      "channel": "chat",
      "available": false,
      "reason": "chat_not_started"
    }
  ],
  "templates": [
    {
      "id": "nHv4l_ALArlouEEfxHLOO",
      "name": "Rezerwacja online",
      "text": "Dzień dobry Anna, wolne terminy i rezerwacja online: https://wzorcowa.pozyskajpacjenta.pl Klinika Wzorcowa",
      "channels": null
    },
    {
      "id": "Olz1kaJ9PjjlsZXlBtly3",
      "name": "Jak do nas trafić",
      "text": "Zapraszamy: ul. Przykładowa 12, 00-950 Warszawa. W razie pytań prosimy dzwonić: +48 22 100 20 30. Klinika Wzorcowa",
      "channels": null
    }
  ],
  "identities": [
    {
      "channel": "sms",
      "address": "+48600100200",
      "primary": true,
      "verified": true,
      "optedOut": false,
      "replyDefault": false,
      "lastInboundAt": "2026-10-10T16:20:05.000Z"
    },
    {
      "channel": "sms",
      "address": "+48501300400",
      "primary": false,
      "verified": true,
      "optedOut": false,
      "replyDefault": true,
      "lastInboundAt": "2026-10-12T08:02:44.000Z"
    },
    {
      "channel": "whatsapp",
      "address": "+48600100200",
      "primary": true,
      "verified": true,
      "optedOut": false,
      "replyDefault": true,
      "lastInboundAt": null
    },
    {
      "channel": "whatsapp",
      "address": "+48501300400",
      "primary": false,
      "verified": true,
      "optedOut": false,
      "replyDefault": false,
      "lastInboundAt": null
    },
    {
      "channel": "email",
      "address": "anna.kowalska@example.com",
      "primary": true,
      "verified": false,
      "optedOut": false,
      "replyDefault": true,
      "lastInboundAt": null
    }
  ],
  "mergedEnquiries": [
    {
      "leadId": "Qm7tYd2wPx9LkR4sNc8Ze",
      "text": "Czy higienizację można zrobić w sobotę?",
      "source": "chat",
      "channel": null,
      "createdAt": "2026-10-11T18:12:30.000Z"
    }
  ]
}

Errors

StatuscodeWhen
401No Authorization header
401Unknown or rotated key
403missing_scopeThe key lacks conversations:read
404not_foundUnknown id, another clinic's conversation or an archived lead's
429Over 120 requests in this minute

Branch on the status and code, never on the Polish error text. All statuses in Errors.

401 · No Authorization header
{
  "error": "missing Authorization: Bearer <klucz z panelu Ustawienia>"
}
401 · Unknown or rotated key
{
  "error": "invalid key"
}
403 · The key lacks conversations:read
{
  "error": "Klucz nie ma uprawnienia conversations:read. Placówka nadaje je w panelu: Ustawienia › Integracje › Klucz API.",
  "code": "missing_scope",
  "scope": "conversations:read"
}
404 · Unknown id, another clinic's conversation or an archived lead's
{
  "error": "Nie ma takiej rozmowy.",
  "code": "not_found"
}
429 · Over 120 requests in this minute
{
  "error": "przekroczono limit 120 zapytań/min"
}

Rate limit

  • 120 requests per minute per key, shared by every endpoint.
  • Every response to a valid key carries RateLimit-Remaining and RateLimit-Reset; see Rate limits.

SDK method

client.getConversation(id: string): Promise<ConversationDetail>

Throws ApiError 404 for an unknown conversation; 403 without the scope.

The TypeScript tab above uses it. Install and errors: TypeScript SDK.