Delivery and retry semantics

Build an asynchronous, idempotent receiver

Oway delivers at least once. A retry or manual replay keeps the exact event_id and body bytes but
uses a fresh signature timestamp. Store a unique constraint on event_id before enqueueing work.

Events are not ordered across endpoints, shipment facts, retries, or replays. Use occurred_at for
business chronology and recorded_at for when Oway learned the fact. Read the current shipment
from the REST API when a workflow depends on current state.

Response contract

  • Any 2xx completes the delivery.
  • Redirects are not followed and are retried as non-2xx responses.
  • 410 Gone is terminal and pauses the endpoint.
  • A connection, TLS, timeout, or non-2xx result is retried unless the window is exhausted.
  • The complete request, including response headers, must finish within 15 seconds.
  • Response capture is bounded; do not place credentials or sensitive data in error bodies.

Return 204 after durable deduplication and local enqueue. Do not wait for downstream processing.

Retry window

Retries use full jitter with ceilings of immediate, 30 seconds, 2 minutes, 10 minutes, 30 minutes,
2 hours, 6 hours, 12 hours, 24 hours, and 48 hours. No attempt is scheduled beyond 72 hours from
the beginning of the current delivery or replay cycle.

For 429, 503, and 504, Oway honors a valid future Retry-After value up to six hours. Other
responses use the jitter schedule. Exhaustion pauses the endpoint so a persistent failure cannot
create unbounded traffic.

Replays

A manual replay creates a new bounded retry cycle for the retained body. It does not create a new
event, change event_id, or erase prior attempts. Replays are unavailable after the 30-day event
retention boundary.


Did this page help you?