# List messages of a conversation

`GET https://app.pozyskajpacjenta.pl/api/v1/conversations/{id}/messages` · operationId `listMessages` · since 1.14.0 · tag Conversations

The messages of one conversation, newest first; `nextCursor` pages to older ones. A webhook `message.received` names the conversation and the message: the message is on the first page. The first chat message of a chat lead is its enquiry, in `lead.message` of the conversation. 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

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

### Path parameters

- `id` (`string`, required): The conversation id (`conversationId` of webhook events).

### Query parameters

- `cursor` (`string`): `nextCursor` of the previous page; omit for the newest messages.
- `limit` (`integer`): Messages per page, 1 to 100 (default 50).

### cURL

```bash
curl "https://app.pozyskajpacjenta.pl/api/v1/conversations/Vb3nQ8sLk2PzX5wRt9YcE/messages" \
  -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 { messages, nextCursor } = await client.listMessages("Vb3nQ8sLk2PzX5wRt9YcE", {
  limit: 20,
});
```

### PHP

```php
<?php
$response = wp_remote_get(
    'https://app.pozyskajpacjenta.pl/api/v1/conversations/Vb3nQ8sLk2PzX5wRt9YcE/messages',
    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 messages.

- `messages` (`ConversationMessage[]`, required): The messages, newest first.
  - `id` (`string`, required): Message id: the `messageId` of webhook events.
  - `conversationId` (`string`, required): The conversation it belongs to.
  - `channel` (`string`, required): The channel: email, sms, whatsapp, instagram or chat (the chat on the clinic's site). One of `email`, `sms`, `whatsapp`, `instagram`, `chat`.
  - `direction` (`string`, required): inbound: from the patient. outbound: from the clinic (the inbox, an automation or this API). outbound_echo: the clinic replied from the WhatsApp or Instagram app itself. One of `inbound`, `outbound`, `outbound_echo`.
  - `status` (`string`, required): received for every inbound message. Outbound messages move forward only: queued, sent, delivered, read; or failed. One of `queued`, `sent`, `delivered`, `read`, `failed`, `received`.
  - `subject` (`string | null`, required): E-mail subject; null on other channels.
  - `text` (`string | null`, required): The text; null for a message with attachments only.
  - `attachments` (`MessageAttachment[]`, required): Files that came with the message.
    - `filename` (`string`, required): File name.
    - `mime` (`string`, required): Media type, e.g. image/jpeg.
    - `size` (`integer`, required): Size in bytes.
  - `createdAt` (`string (date-time)`, required): When the message was stored.
  - `sentAt` (`string (date-time) | null`, required): Outbound: when the provider accepted it; null otherwise.
  - `deliveredAt` (`string (date-time) | null`, required): Outbound: when it reached the patient's device, where the channel reports it.
  - `readAt` (`string (date-time) | null`, required): Inbound: when someone at the clinic opened it. Outbound: the provider's read receipt, where the channel reports it.
- `nextCursor` (`string | null`, required): Pass it as `cursor` for older messages; null at the first message.

Example (The newest message):

```json
{
  "messages": [
    {
      "id": "gH2jK4lZ6xC8vB0nM1qWe",
      "conversationId": "Vb3nQ8sLk2PzX5wRt9YcE",
      "channel": "sms",
      "direction": "inbound",
      "status": "received",
      "subject": null,
      "text": "Pasuje, dziękuję. Do zobaczenia w czwartek.",
      "attachments": [],
      "createdAt": "2026-10-12T08:02:44.000Z",
      "sentAt": null,
      "deliveredAt": null,
      "readAt": null
    }
  ],
  "nextCursor": "1791792164.gH2jK4lZ6xC8vB0nM1qWe"
}
```

## Errors

| Status | code | When |
| --- | --- | --- |
| 400 | `invalid_query` | limit above 100 |
| 401 |  | No Authorization header |
| 401 |  | Unknown or rotated key |
| 403 | `missing_scope` | The key lacks conversations:read |
| 404 | `not_found` | Unknown id, another clinic's conversation or an archived lead's |
| 429 |  | Over 120 requests in this minute |

400 (limit above 100):

```json
{
  "error": "limit: od 1 do 100",
  "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"
}
```

404 (Unknown id, another clinic's conversation or an archived lead's):

```json
{
  "error": "Nie ma takiej rozmowy.",
  "code": "not_found"
}
```

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.listMessages(conversationId: string, params?: { cursor?, limit? }): Promise<MessageList>`
