Polling list endpoints
Integrators that poll GET /v1/{phone_number_id}/conversations on a
fixed interval do not need to change their request shape — Kirimdev
applies three layers of efficiency on the server and in the HTTP
contract.
Short-lived response cache
Section titled “Short-lived response cache”List responses are cached in Redis for 8 seconds per unique query
(org, account, filters, cursor, limit, and updated_since). Repeated
polls inside that window are served from cache instead of re-running
the heavy inbox join.
The cache is invalidated immediately when a conversation row on that account changes (inbound message, outbound send, assignment, status patch, and similar writes).
Delta sync with updated_since
Section titled “Delta sync with updated_since”Pass an ISO 8601 timestamp to fetch only conversations whose
updated_at is strictly after that instant:
GET /v1/106540352242922/conversations?updated_since=2026-06-19T10:00:00.000Z&limit=25Authorization: Bearer kdv_live_...When nothing changed, the response is a normal 200 with
data: []. Store the newest updated_at from each non-empty page and
send it on the next poll.
Sort order: requests with updated_since order by
updated_at DESC (most recently mutated first). Requests without it
keep the inbox order last_message_at DESC. Cursors are only valid for
the same query shape — do not reuse a cursor across modes.
Works alongside cursor pagination and the usual status /
contact_id filters.
Conditional GET (ETag / 304)
Section titled “Conditional GET (ETag / 304)”Every list response includes a weak ETag derived from the newest
updated_at, max unread_count, row count, and whether another page
exists:
HTTP/1.1 200 OKETag: W/"2026-06-19T11:00:00.000Z:2:1"On the next poll, send the value back:
GET /v1/106540352242922/conversationsIf-None-Match: W/"2026-06-19T11:00:00.000Z:2:1"When nothing changed, Kirimdev responds 304 Not Modified with
no JSON body — saving bandwidth and client parse time. Rate-limit
headers are still attached.
Combine updated_since (smaller DB result sets) with If-None-Match
(cheap unchanged responses) for the lowest overhead polling loop.
Message status polling (GET /messages/{id})
Section titled “Message status polling (GET /messages/{id})”Integrators that poll a single message by msg_* id to watch delivery
status get the same server-side protections without changing their
code:
| Status | Cache TTL | Why |
|---|---|---|
pending, sent | 5 s | Status changes quickly |
delivered | 10 s | One step from terminal |
read, failed | 60 s | Terminal — pollers often keep checking |
The cache key is per (org, account, message id) and is dropped
immediately when the worker applies a status webhook or send pipeline
update.
Responses include a weak ETag derived from status and error
fields. Send it as If-None-Match to receive 304 Not Modified
when the message has not changed.
For new integrations, prefer a message.status webhook
subscription instead of polling — but existing poll loops are safe on
the platform.
Related
Section titled “Related”- Pagination — opaque cursors and page iteration
- Rate limits — per-org read/write budgets
- Messages list —
created_afterfor message delta sync