Skip to main content
Retrieve the full stored message history (direct and group conversations) for the connected number.

Endpoint

GET https://pilotstatus.com.br/v1/messages/history
Requires a number-scoped API key (ps_*) in the x-api-key header. Tenant-scoped keys return 403. You may also identify the key with x-api-key-id: <api_key_id>.All providers supported: this endpoint works for both unofficial (Pilot Status web) numbers and official Meta Cloud API numbers.
This endpoint is how you read old messages. Your webhook does not replay them: when a number connects, the device’s history is imported into the chat but not delivered as message.received events. See PATCH /v1/numbers/{id} if you want that delivery turned on for a number.

Coexistence: what actually lands here

On a Meta coexistence number, Meta ships the phone’s on-device history after pairing, in chunks, over its internal history webhook. What of it you can read back here is narrower than what Meta sends, in three specific ways.
1 — The import window is 30 days, not six months. Everything Meta delivers is filtered against connectedAt − 30 days (falling back to createdAt for numbers that predate the column). Older messages arrive and are discarded — they are never stored, so no endpoint can return them later. Meta may well send six months; only the last 30 days before the connection survive.
2 — Nothing is stored at all unless historyImportEnabled was true before the number connected. With it off, the whole history delivery is dropped on arrival and this endpoint answers as if the number had no past.A new number is born with true. Numbers created between 2026-08-25 and 2026-09-16 were born false and stay false — the default change does not touch existing rows, because since 25/08 the dashboard asks before connecting and a false there may be a real choice. If the number predates the change, check the value rather than assuming.⛔ Turning it on afterwards does not help. Meta hands the history over once, right after pairing; a later PATCH arrives too late and what the device handed over is already discarded. Send it on POST /v1/numbers/remote-pairing, which accepts the settings block.It cannot be fixed after the fact: Meta hands the history over once, right after pairing, and there is no way to ask for it again. Set it on the pairing call — POST /v1/numbers/remote-pairing accepts the same settings block — not with a PATCH afterwards, which races the burst. See number settings.
Diagnosing an empty result: GET /v1/numbers/{id} → historyImport says whether the history arrived and was dropped (discarded) or whether Meta refused to send it (syncRefused).
3 — On a Meta number, imported history is never delivered to your webhooks, even with webhookHistoricalMessages: true. That flag governs the Evolution (QR) rail, where the replay does dispatch message.received. The Meta history path only persists the rows; it has no webhook dispatch. (history is also one of the nine Meta fields that are never forwarded natively, not even to a "*" subscription.)So for a Meta number this endpoint is the only way to read what was imported. Poll it after pairing rather than waiting for deliveries that will not come.
Contacts have no endpoint of their own. What you get is the peer on each conversation — phone and, when WhatsApp supplied it, the profile name — through GET /v1/conversations and the message rows here. There is no separate contact book import to read.

Query parameters

string
ISO 8601 datetime. Filter messages with providerTimestamp on or after this date.
string
ISO 8601 datetime. Filter messages with providerTimestamp on or before this date.
integer
default:"1"
Page number (≥ 1).
integer
default:"30"
Results per page (1–100).
Both startDate and endDate are optional individually. When supplied, each must be a valid ISO 8601 string and startDate must not be later than endDate; otherwise 400 INVALID_DATE_RANGE is returned. Results are ordered by providerTimestamp descending (newest first). The endpoint returns up to roughly one month of stored history, counted from the number’s connection date.

PII mode effect

The response depends on the PII mode configured for the number (set in the dashboard, on the API Keys page’s Privacy & retention panel or in the number’s settings). The query bounds come solely from your startDate/endDate — the PII window is not applied to the query. Instead, rows that fall outside the retention window are still returned, but redacted: the row is present (keyed on its providerTimestamp) with redacted: true and its text, media, participantName, and participantPhone nulled.

Example

Message object fields

string
required
Pilot Status internal message ID.
string
required
ID of the parent conversation (direct or group).
string
required
"INBOUND" (received) or "OUTBOUND" (sent).
string
required
Provider that handled the message (PILOT_STATUS, META, …).
string | null
Provider message id (e.g. Meta wamid) when available.
string
required
Message status (QUEUED, SENT, DELIVERED, READ, FAILED, …).
string
required
text, image, audio, video, document, location, contacts, sticker, or reaction.
string | null
Where an outbound message came from, when recorded: APP — sent from the WhatsApp Business app on the phone or another tool on the same WABA; CHATWOOT — an agent reply from a native Chatwoot WhatsApp Cloud inbox, sent through the Meta layer; LAYER — sent through the Meta layer by any other client. A message Pilot Status sent itself may carry API or null. null on inbound messages: read direction to tell sent from received. The set grows, so treat a value you do not recognise as outbound.
string | null
Message text or caption when available.
string | null
WhatsApp display name of the counterpart/sender when available.
string | null
Counterpart/sender in E.164 format when available.
string | null
externalMessageId of the message this one replies to, when available.
object | null
Media descriptor { provider, id, url, mimeType, fileName } when the message carries media; null otherwise.
  • media.provider — the delivering provider — "META" for Meta Cloud API numbers, or an internal provider tag for unofficial numbers.
  • media.id — Meta media id. Set on META numbers — pass it to GET /v1/media/{mediaId} to download the bytes; null for unofficial numbers.
  • media.url — Direct download URL when available. META inbound media is mirrored to S3 (so META messages usually carry both id and url); the unofficial provider provides its own link. Best-effort — may be null.
  • media.mimeType — Media MIME type when known (may be null).
  • media.fileName — Media file name when known (may be null).
boolean
true when the row falls outside the number’s PII retention window (or the number is RELAY_ONLY). Redacted rows keep their id, providerTimestamp, and delivery metadata, but text, media, participantName, and participantPhone are null.
string | null
ISO 8601 — when the message was sent.
string | null
ISO 8601 — when the message was delivered.
string | null
ISO 8601 — when the message was read (only when read receipts are enabled).
string
required
ISO 8601 — provider’s timestamp for the message (sort key).
string
required
ISO 8601 — when the record was created in Pilot Status.

Common errors

  • 400 INVALID_DATE_RANGE — startDate or endDate is not a valid ISO 8601 string, or startDate > endDate.
  • 400 NUMBER_NOT_FOUND — the API key is not bound to a WhatsApp number.
  • 401 — missing or invalid x-api-key header.
  • 403 — tenant-scoped key used (number-scoped key required).