Build and operate
Idempotency and references
Your IDs make every call safe to repeat.
In a nutshell
Use your own IDs everywhere - external_id for businesses, reference for messages, the delivery ID for callbacks. Repeating a request with the same ID never creates a second business or sends a second message.
Three IDs, three guarantees
| ID | Where | Guarantee |
|---|---|---|
external_id |
POST /businesses |
Same ID = same business. Repeating updates it. |
reference |
POST .../messages |
Same reference for the same business = same message. Repeating returns the original (200) and sends nothing. |
X-PaalChat-Delivery |
Callbacks | Same ID = same event. Process it once. |
Idempotency-Key header |
Any write (POST, PUT, PATCH, DELETE) |
Same key + same request within 24 hours = the first response again, nothing done twice. |
The Idempotency-Key header
Any write accepts an Idempotency-Key header - your own unique ID for that request
(1-255 printable characters). A retry with the same key and the same body gets the
first response back, with Idempotent-Replayed: true, and nothing happens twice.
- The same key with a different request is refused:
409 idempotency_key_reused. - A retry while the first request is still running gets
409 idempotency_in_progress- wait a moment and retry with the same key. - Keys are kept for 24 hours, per product and per environment (live and test).
- Server errors (
5xx) and429are not kept, so retrying with the same key works. - For messages,
referencedoes the same job without a time limit - use both if you like.
References for messages
Use your own database ID for the message, for example notification-4411 or
m8812. Rules: 1-191 printable characters, no spaces, unique per business.
First call POST .../messages reference=notification-4411 → 202 Accepted (queued)
Retry POST .../messages reference=notification-4411 → 200 OK (the same message, not sent again)
Warning
Never generate a new reference for a retry. A new reference is a new message.
Without a reference, every call sends a new message - a retry after a timeout may send it twice. Always send one.
References in callbacks
message.status callbacks carry your
reference, so you can update your own row without storing PaalChat's IDs. The
platform's message_id and Meta's wamid are included too.
Callbacks can repeat
A callback can arrive more than once (retries, resends) and out of order. Store
X-PaalChat-Delivery and skip deliveries you have processed. For messages, also
key on wamid and apply statuses only forward.