Respond fast
Reply2xx within 10 seconds and do the actual work afterwards — put the event in
your own queue and return. A slow endpoint times out, is retried and receives the same
event again.
Deduplicate
Delivery is at-least-once: the same event can arrive more than once. The simplest way to make it harmless is to store messages bymessageId and always write with an
upsert.
Messages
data.text ?? null becomes NULL in your table, and if (data.quotedMessageId)
tells whether the message is a reply. sender only exists when someone else wrote:
when fromMe is true there is no sender, so data.sender?.phone is the safe read.
Statuses
messageIds and status: the conversation and the recipient
come from the MESSAGE.SENT of the same message, already in your table.
Use an upsert here too, not an UPDATE: a DELIVERED can arrive before the
MESSAGE.SENT of the same message, and even before your system stores the response
of the send request. An UPDATE would find no row and lose the status.
The rank makes the status only move forward: a repeated DELIVERED, or a DELIVERED
that arrives after the READ, changes nothing.
By event id
Every event also has an id (the webhook-id
header) that is identical in every retry. To deduplicate generically — for example
before putting events in your queue — store the processed ids for 24 hours and drop
repeats.
id identifies the event, not the message: the DELIVERED and the READ of the
same message have different ids. Don’t use messageId to drop events, or you will
drop statuses.
Order
There is no ordering guarantee. Messages sent in a burst (several photos at once) and events retried after a failure can arrive out of order.- To order messages, use
timestamp. - Statuses only move forward (
MESSAGE.SENT→DELIVERED→READ): ignore any status older than the one you already have, as in the upsert above.
Groups
chat.typeisGROUP,chat.ididentifies the group (…@g.us) andsenderis the participant who wrote. Your own messages in the group havefromMe: trueand nosender.- A status means the message reached it for at least one participant:
READis “someone read it”, not “everyone read it”.DELIVEREDandREADeach arrive once per message, not once per participant.
Filtering
To stop receiving group messages or status updates at all, turn on
ignoreGroups
or ignoreStatus in the instance settings:
Connection
If you build your own pairing screen: show the QR Code of each
QRCODE.UPDATED with status: GENERATED (always the latest), offer to try again on
EXPIRED, and close the screen on CONNECTION.UPDATED with status: CONNECTED.
Sending and duplicates
The send endpoints return themessageId; it is what ties your send to the
MESSAGE.SENT and the MESSAGE.STATUS_UPDATED events that follow. Store it.
Zapfy does not deduplicate send requests. If a send request fails without a response
(a timeout, a dropped connection), retrying it may send the message twice. Before
retrying, check the MESSAGE.SENT events of that conversation to see what actually
left your number.