# List conversations

`GET https://app.pozyskajpacjenta.pl/api/v1/conversations` · operationId `listConversations` · since 1.14.0 · tag Conversations

The clinic's conversations with patients, newest activity first, each with its patient. Filter by status, location, channel of the newest message and `updated_since`; page with `cursor`. To keep a copy in your system in step, store the time you start a sync and pass it as `updated_since` next time. Needs the scope conversations:read; every page you read is written to the clinic's audit log with the ids it showed. The response holds patient data and is never cached (`Cache-Control: no-store`); call it from your server only.

## Request

Authorization: `Bearer <the clinic's key>`.

### Query parameters

- `status` (`string`): Only open or only closed conversations. One of `open`, `closed`.
- `location` (`string`): A location id from GET /locations. The primary location also takes the conversations whose location is not known.
- `channel` (`string`): Only conversations whose newest message is on this channel. One of `email`, `sms`, `whatsapp`, `instagram`, `chat`.
- `updated_since` (`string (date-time)`): Only conversations changed at or after this time (ISO 8601): a new message, a read, open or closed, or a change of the lead.
- `cursor` (`string`): `nextCursor` of the previous page; omit for the first page.
- `limit` (`integer`): Conversations per page, 1 to 100 (default 50).

### cURL

```bash
curl "https://app.pozyskajpacjenta.pl/api/v1/conversations?status=open&location=loc_wieliczka&channel=sms&updated_since=2026-10-12T08%3A00%3A00Z" \
  -H "Authorization: Bearer $PP_API_KEY"
```

### TypeScript

```ts
import { PozyskajPacjentaClient } from "@pozyskajpacjenta/sdk";

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

const { conversations, nextCursor } = await client.listConversations({
  status: "open",
  updatedSince: "2026-10-12T08:00:00Z",
});
```

### PHP

```php
<?php
$response = wp_remote_get(
    'https://app.pozyskajpacjenta.pl/api/v1/conversations?status=open&location=loc_wieliczka&channel=sms&updated_since=2026-10-12T08%3A00%3A00Z',
    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

### 200: A page of conversations.

- `conversations` (`Conversation[]`, required): The conversations, newest activity first.
  - `id` (`string`, required): Conversation id.
  - `status` (`string`, required): open or closed. The clinic closes a conversation in its inbox; a new message from the patient opens it again. One of `open`, `closed`.
  - `lead` (`ConversationLead`, required): The patient.
    - `id` (`string`, required): The lead id: the `leadId` POST /leads returns and webhook events carry.
    - `name` (`string | null`, required): The patient's name; null when unknown.
    - `phone` (`string | null`, required): The patient's phone; null when unknown.
    - `email` (`string | null`, required): The patient's e-mail; null when unknown.
    - `message` (`string | null`, required): The enquiry the patient sent: a form's message or the first chat message. null when there was none.
    - `source` (`string`, required): Where the lead came from: form, embed, api, manual, inbound or chat.
    - `stage` (`string`, required): The lead's stage in the clinic's CRM, e.g. new, scheduled, visited, not_interested.
    - `locationId` (`string | null`, required): The clinic location the enquiry is for (GET /locations); null when not known.
    - `createdAt` (`string (date-time)`, required): When the lead was created.
  - `lastChannel` (`string | null`, required): Channel of the newest message: email, sms, whatsapp, instagram or chat (the chat on the clinic's site). null before the first message. One of `email`, `sms`, `whatsapp`, `instagram`, `chat`.
  - `lastMessageAt` (`string (date-time) | null`, required): Time of the newest message; null before the first one.
  - `lastInboundAt` (`string (date-time) | null`, required): Time of the patient's newest message; null when the patient has not written.
  - `unreadCount` (`integer`, required): The patient's messages nobody at the clinic has opened yet.
  - `createdAt` (`string (date-time)`, required): When the conversation began.
  - `updatedAt` (`string (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.
- `nextCursor` (`string | null`, required): Pass it as `cursor` for the next page; null on the last page.

Example (Open conversations, one per page):

```json
{
  "conversations": [
    {
      "id": "Hm6pD1fGz4KqW8nLs2BvT",
      "status": "open",
      "lead": {
        "id": "Kq8vN2xWc0bLd4Te7YhJm",
        "name": "Piotr",
        "phone": "+48 601 200 300",
        "email": null,
        "message": null,
        "source": "inbound",
        "stage": "new",
        "locationId": null,
        "createdAt": "2026-10-12T09:15:20.000Z"
      },
      "lastChannel": "whatsapp",
      "lastMessageAt": "2026-10-12T09:15:20.000Z",
      "lastInboundAt": "2026-10-12T09:15:20.000Z",
      "unreadCount": 1,
      "createdAt": "2026-10-12T09:15:20.000Z",
      "updatedAt": "2026-10-12T09:15:20.000Z"
    }
  ],
  "nextCursor": "1791796520.Hm6pD1fGz4KqW8nLs2BvT"
}
```

## Errors

| Status | code | When |
| --- | --- | --- |
| 400 | `invalid_query` | An unknown channel |
| 401 |  | No Authorization header |
| 401 |  | Unknown or rotated key |
| 403 | `missing_scope` | The key lacks conversations:read |
| 403 | `feature_disabled` | Conversations are not switched on for the clinic |
| 429 |  | Over 120 requests in this minute |

400 (An unknown channel):

```json
{
  "error": "channel: jeden z email, sms, whatsapp, instagram, chat",
  "code": "invalid_query"
}
```

401 (No Authorization header):

```json
{
  "error": "missing Authorization: Bearer <klucz z panelu Ustawienia>"
}
```

401 (Unknown or rotated key):

```json
{
  "error": "invalid key"
}
```

403 (The key lacks conversations:read):

```json
{
  "error": "Klucz nie ma uprawnienia conversations:read. Placówka nadaje je w panelu: Ustawienia › Integracje › Klucz API.",
  "code": "missing_scope",
  "scope": "conversations:read"
}
```

403 (Conversations are not switched on for the clinic):

```json
{
  "error": "Rozmowy w API nie są włączone dla tej placówki.",
  "code": "feature_disabled"
}
```

429 (Over 120 requests in this minute):

```json
{
  "error": "przekroczono limit 120 zapytań/min"
}
```

## Rate limit

- 120 requests per minute per key, shared by every endpoint.

## SDK method

`client.listConversations(params?: { status?, locationId?, channel?, updatedSince?, cursor?, limit? }): Promise<ConversationList>`

Throws ApiError 403 with `code: "missing_scope"` when the key lacks conversations:read.
