Outbound webhooks
Upwell can POST a JSON event to a URL you host whenever something changes — a carrier invoice is created, matched to a shipment, approved, and so on. Webhooks are the push counterpart to polling.Subscribing
Webhook subscriptions are configured in the Upwell dashboard (there’s no public REST endpoint to create one). A subscription has:url— your HTTPS receiver.triggers— the list of event types you want delivered.authSettings— how Upwell proves the delivery came from Upwell (see Authenticating deliveries).retryAttempts— how many times Upwell retries a failed delivery (0–10).
What you can subscribe to
The webhook event catalog is the single source of truth for every trigger string, across all resources — invoices, carrier invoices, documents, payments, exceptions, remittances, and approval requests. Two rules to internalize before subscribing:- Each change fires exactly one trigger — the most specific that applies. A tracked status
transition fires only its
.status.{STATUS}trigger, not also the genericupdate.{resource}; the generic trigger fires for changes that are neither a tracked status nor a named sub-event. Subscribe to every trigger you care about. - A few triggers exist in the dispatcher but are not self-service in the dashboard subscription form (they’re marked in the catalog) — contact support to enable those.
For carrier invoices specifically: “ingestion done” (matched + audited) is best observed via
*.shipment_updated or the generic update.carrier_invoice; the *.status.APPROVED /
*.status.EXCEPTION triggers reflect the later review lifecycle. See
Knowing when a carrier invoice is processed.The delivery envelope
Every delivery is a single JSON object. The deprecatedtable field is included for compatibility with existing receivers. Use trigger to select the payload format and handler when building or updating an integration. No removal date is scheduled. A future sunset date will be published here and communicated to API consumers before the field is removed.
Plus delivery bookkeeping:
tenantId, webhookSubscriptionId, createdAt, updatedAt,
scheduledAt, processedAt, retryOfId (points to the original event, never the previous
retry; null on the original event), and retries (retry events spawned from this one).
The payload shape varies by trigger
Status-change events (update.carrier_invoice.status.APPROVED / .EXCEPTION) — payload.carrierInvoice with the invoice and its matched relations nested:
update.carrier_invoice.shipment_updated) — raw new/old snapshots (snake_case columns):
Note
new.source_system = "API" and new.integration_id are stamped by Upwell — confirming the invoice was API-submitted. source_system_id is null for API submissions.Authenticating deliveries
You choose how Upwell authenticates to your receiver when you create the subscription. Three options:Custom header (recommended)
Custom header (recommended)
You pick a header name and a secret value; Upwell sends that header on every delivery. A common choice is a token header:Your receiver compares the header against the secret you configured and rejects mismatches. The header name is your choice —
X-Upwell-Token is a convention, not a built-in.Basic auth
Basic auth
Upwell sends
Authorization: Basic base64(username:password) using the credentials you configure.None
None
No auth header. Rely on URL secrecy / network controls. Not recommended for production.
Content-Type: application/json and a User-Agent of UpwellWebhookService/<version> (https://www.upwell.com).
There is no payload signing (HMAC) or replay protection — authentication is the static
header or Basic credentials you configure above. Treat the shared secret like a password:
rotate it if it leaks, and always compare it on every delivery.
Reliability
- What retries: deliveries that return
5xx, time out, or fail at the network level are retried, up to the subscription’sretryAttempts. - What does NOT retry: a
4xxresponse is treated as delivered — it is recorded as successful and never retried. A misconfigured receiver (broken auth check, wrong route) that 4xxes will silently lose every event while Upwell’s side shows success. Alert on your receiver’s 4xx rate, and reconcile with polling (below). - Retry schedule: exponential backoff starting at 1 minute and doubling each attempt (1, 2, 4, 8, … minutes).
retryAttemptscounts retries beyond the first attempt —retryAttempts: 3(the default) means up to 4 total deliveries. The dashboard form accepts 0–10.- Each delivery attempt has a 15-second timeout. Return a
2xxquickly; do slow work asynchronously. - Build an idempotent receiver: dedupe on the delivery
id, and treat a non-nullretryOfIdas a redelivery of the original event. - After retries exhaust there is no automatic replay — pair webhooks with a periodic reconciliation poll so a missed delivery never strands a record (see Knowing when a carrier invoice is processed).
Example receiver
See it end-to-end
Pair the receiver above with a polling fallback, and walk the full submit → attach → process flow in the submission guide.

