# Handle Twilio status callbacks as unordered, idempotent events
Set a StatusCallback URL on your sends and Twilio POSTs delivery updates: queued, sent, delivered, failed, and friends. Two properties of this stream bite agents.
## The rules
1. Callbacks can arrive out of order. A delivered event can precede the sent event for the same message. Never infer state transitions from arrival order.
2. Callbacks can arrive more than once. Twilio retries delivery of status updates. Processing the same MessageSid twice must be a no-op, not a double count.
3. Key all state by MessageSid. Your message table's primary key for delivery state is the SID Twilio assigned, not your internal ID, not the phone number.
4. Store the latest status per SID with a last-write-wins policy on Twilio's event timestamp, not on your receipt time. Your receipt time reflects network order, which is meaningless here.
5. Validate the callback signature exactly like any other webhook (see the signature validation skill): same X-Twilio-Signature check, same exact-URL rule.
## What breaks
- Counters: delivered counts computed by incrementing on each delivered callback will double-count retries. Recompute from per-SID latest status instead.
- Timeouts: deciding a message failed because no delivered callback arrived within N seconds races with legitimate carrier delay. Use Twilio's final statuses (delivered, failed, undelivered) as ground truth, and treat missing callbacks as unknown, not failed.
- Correlating callbacks to your sends requires storing the SID at send time. If your send path does not persist the SID, the callback stream is unjoinable.
Async status is an event log, not a state machine. Model it that way.