Skip to content
Wazapin
Esc
navigateopen⌘Jpreview
On this page

Message lifecycle and idempotency

Delivery status lifecycle, retry boundaries, and idempotency patterns for reliable messaging.

Use this guide to build retry-safe integrations.

Message lifecycle

Typical state flow:

queued -> sent -> delivered -> read
   \-> failed
  • queued: accepted and waiting for dispatch.
  • sent: handed off to provider.
  • delivered: delivered to recipient device/provider state.
  • read: read receipt observed.
  • failed: dispatch failed or provider rejected.

Retry boundaries

  1. Retry on 429 and 5xx only.
  2. Do not retry validation failures (400, 422) before fixing payload.
  3. Use bounded exponential backoff with jitter.

Client idempotency pattern

  • Generate an operation key in your app per send intent.
  • Save operation_key -> message_id mapping.
  • If the same operation is retried, return existing message_id from your store.

Webhook deduplication pattern

Use the delivery id from webhook headers (svix-id or webhook-id) to avoid duplicate processing:

if delivery_id already processed:
  return 200
store delivery_id
enqueue processing
return 200

For message.new / message.status_update, also key business logic on message_id inside the JSON body.

Reconciliation flow

Send message request

Call POST /v1/messages and persist request metadata.

Track status

Query GET /v1/messages/{messageID} or consume webhook events.

Resolve final state

Treat read and failed as terminal states for most workflows.

Was this page helpful?