Skip to navigation

Receiving Deliveries

The request

Each delivery is an HTTPS POST with a JSON body.

HeaderValue
Content-Typeapplication/json; charset=utf-8
User-AgentRushOrder-Webhooks/1.0
webhook-idThe delivery ID, a UUID, identical on every retry of the delivery.
webhook-timestampWhen this attempt was sent, in Unix seconds.
webhook-signatureSpace-separated signatures, each v1,<Base64 value>.
Body fieldDescription
typeThe event type.
timestampWhen the event happened, ISO 8601 in UTC (2026-09-21T23:31:00+00:00).
rushOrderMomCodeThe Rush Order client code of the account, such as ABC.
dataThe event’s fields, described in the event reference. Fields without a value are null.

The event reference shows a complete body for each event type. Events can gain new fields and values over time, so ignore fields you don’t recognize.

Verifying a delivery

Verify every delivery before acting on it:

  1. The signed content is {webhook-id}.{webhook-timestamp}.{body}: the two header values and the raw body, joined by periods.
  2. The key is the part of the secret after whsec_, Base64-decoded.
  3. The expected signature is the HMAC-SHA256 of the signed content with that key, Base64-encoded.
  4. The delivery is authentic when the expected signature equals the value after v1, in any of the header’s signatures.
Verify the raw body

The signature covers the body exactly as received. Verify the raw bytes before parsing them; JSON that is parsed and re-serialized will not match.

Reject a webhook-timestamp more than five minutes from the current time, to stop old deliveries from being replayed.

The scheme follows the Standard Webhooks specification, so the Standard Webhooks libraries verify deliveries in many languages. The example below needs only the Python standard library (3.6 or later).

import base64
import hashlib
import hmac
import time
TOLERANCE_SECONDS = 5 * 60
def signature_matches(secret: str, message_id: str, timestamp: str,
signature_header: str, body: bytes) -> bool:
key = base64.b64decode(secret[len('whsec_'):])
signed_content = f'{message_id}.{timestamp}.'.encode() + body
expected = base64.b64encode(
hmac.new(key, signed_content, hashlib.sha256).digest())
for signature in signature_header.split(' '):
version, _, value = signature.partition(',')
if version == 'v1' and hmac.compare_digest(value.encode(), expected):
return True
return False
def verify_webhook(secret: str, headers: dict, body: bytes) -> bool:
"""headers: the request's headers, keyed by lower-case name.
body: the raw request body, exactly as received."""
timestamp = headers['webhook-timestamp']
if abs(time.time() - int(timestamp)) > TOLERANCE_SECONDS:
return False
return signature_matches(secret, headers['webhook-id'], timestamp,
headers['webhook-signature'], body)

These values check an implementation of the signature step on its own (the timestamp is too old to pass the five-minute check):

InputValue
Secretwhsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw
webhook-idmsg_p5jXN8AQM9LWM0D4loKWxJek
webhook-timestamp1614265330
Body{"test": 2432232314}
Expected signaturev1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=

Responses and retries

Your responseResult
2xx within 30 secondsDelivered.
408, 429, 5xx, no response within 30 seconds, or a connection or TLS failureRetried: up to six attempts in all, immediately and then 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours after each failure.
3xx or any other 4xxNot retried.

Each retry uses the subscription’s current URL and secret. Pausing or deleting a subscription cancels its pending retries.

Respond quickly

Return a 2xx as soon as the delivery is verified and stored, and do slower work afterward, so long processing doesn’t run past the 30-second limit.

Duplicates and ordering

Delivery is at least once. A repeated delivery carries the same webhook-id, so use it to skip deliveries you have already processed.

A new event for the same order or package has a new webhook-id: order.shipped again when a package gains a tracking number, and order.whready again when an order re-enters the warehouse system under a new order number.

Deliveries can arrive out of order. timestamp gives the time each event happened.