---
title: "List messages for the account with cursor pagination"
method: GET
path: "/v2/messages"
tags: ["messages-v2"]
---

# List messages for the account with cursor pagination

`GET /v2/messages`

## Request

- Base URL: `https://api.tracklysms.com/api`
- URL: `https://api.tracklysms.com/api/v2/messages`
- Auth: API key in header `X-Api-Key`

Default order is newest-first by
timestamp (browse / initial full load). When updated_since is set it is an incremental change
feed: rows are filtered, sorted, and paginated by the updated_at watermark ASCENDING, so a row
changed mid-pagination is never skipped — pre-updated_at legacy rows are not part of the feed
(capture those once via the initial full list).

An external_location_id the caller does not own yields an empty page, never another tenant's
rows; params are validated first so that path still rejects a bad limit / cursor / date.

## Query parameters

- `limit` string
- `cursor` string
- `external_location_id` string
- `updated_since` string
- `date_to` string
- `date_from` string
- `status` string
- `to` string
- `list_number` string
- `sending_list_id` string
- `api_key` 'me'

## Response `200`

Success

- MessagesListResponse
  - `messages` MessageRow[]
    - `api_key_id` string, nullable: ID of the API key that sent the message; null for dashboard, scheduled, or journey sends
    - `body` string: Message body text
    - `cost_state` string: estimated | settled | billed | refunded
    - `dlr_status` string: Normalized carrier DLR status
    - `encoding` string: GSM-7 or UCS-2, derived from body text
    - `error_code` string: Normalized carrier error code
    - `error_description` string: Normalized carrier error description
    - `external_ids` object: Partner-supplied external ids echoed from the account
    - `from_number` string: Sender number (E.164)
    - `id` string: Message ID
    - `is_delivered` boolean: Normalized delivered flag
    - `is_terminal` boolean: Whether the DLR is a terminal state
    - `message_type` string: mms for MMS records; omitted for legacy SMS
    - `provider_message_id` string: Carrier/provider message id from the delivery receipt (present when the provider pmid is globally unique)
    - `replied_at` string: Reply timestamp (ISO8601)
    - `reply_id` string: AllReplies ID if the recipient replied
    - `reply_kind` string, nullable: human | reaction | stop | start | help | keyword; null when there is no reply or the reply predates classification
    - `reply_text` string, nullable: Text of the most recent linked inbound reply, capped at 1600 characters; null when there is no reply and when the reply carried no text (media-only or reaction), so use reply_id to tell the two apart
    - `segment_count` integer: Billed SMS segment count
    - `sending_list_id` integer: Sending list ID
    - `status` string: Lifecycle status
    - `status_detail` string: Status detail / drop reason
    - `timestamp` string: Send timestamp (ISO8601)
    - `to_number` string: Recipient number (E.164)
    - `updated_at` string: Last-mutated timestamp (ISO8601); falls back to timestamp on legacy rows
  - `pagination` MessagesV2Pagination
    - `has_more` boolean: Whether another page is available
    - `limit` integer: Page size
    - `next_cursor` string: Opaque cursor for the next page; null on the last page

## Other responses

- `400`: Validation error
- `401`: Authentication error

---

[API](https://skmtc.dev/tracklysms/apis/trackly-sms-api.md) · [All operations](https://skmtc.dev/tracklysms/apis/trackly-sms-api/llms.txt) · [OpenAPI document](https://skmtc.dev/tracklysms/apis/trackly-sms-api/revisions/ac1ad22cb2a9?raw)
