Knowing when a carrier invoice is processed
After you submit a carrier invoice, Upwell works on it asynchronously. This page explains how to learn when that work is done.There’s no single “processed” flag. You read the existing fields on the invoice — its
status, its exceptions, and the matched shipmentId — plus the type on each attached document. You can read them by polling the GET endpoints or by receiving webhooks. Most production integrations use webhooks for timeliness and polling as a reconciliation backstop.Two phases of processing
It helps to separate two things:- Ingestion (automatic, seconds after create). Upwell stamps provenance (
source_system = "API"), matches the invoice to a shipment/carrier/bill from your references, and runs the exception audit. Thestatususually staysRECEIVEDthrough this phase — ingestion populatesshipmentId/billId/carrierIdand updatesexceptions, it doesn’t move the status. - Review & approval (later; may involve your rules or a human). The invoice moves toward
APPROVEDor an exception state. This is wherestatuschanges.
The signals
Status values
The generated Vocabulary page lists every enum value the API can produce, including the ones not defined below.When a linked bill moves the status
Once a carrier invoice is linked to a bill, the bill’sstatus can move the invoice. The mapping depends on the bill’s source_system. Strings are exact, including case.
Fully paid and partially paid bill statuses apply for every source:
These bill statuses are removed for every source, and the carrier invoice goes to
AWAITING_BILL: DELETED, VOID, Canceled.
Approval that is not itself a payment is per source. A bill synced by one of Upwell’s TMS integrations moves the invoice to APPROVED only on that TMS’s own approval statuses. For example:
TRANSPORT_PRO and transport-pro use the literal APPROVED on purpose. That is the same text Revenova stores; it is listed for Transport Pro rather than borrowed from Revenova. A status that only another TMS uses for approval does not approve: a Turvo bill whose status is APPROVED, or a Revenova bill whose status is Approved, leaves the invoice where it is (an invoice in AWAITING_BILL moves to RECEIVED, because it now has a bill).
Bills you submit through the API (source_system = "API") use the combined list, because partner-authored bills keep bill status as the source of truth. So does a bill with no source_system, or one whose source_system has no list of its own. The combined list approves on AGING, SELECTED, Unpaid, APPROVED, Approved, Billed, and Transferred to Settlement; the paid and partially paid rows above apply as usual.
A carrier invoice in AWAITING_INVOICE does not move because of the bill. The invoice document has to arrive first.
Approach 1 — Polling
Read the invoice and its documents on an interval. Wait for ingestion (the row’supdatedAt advances past createdAt), then read the outcome.
Approach 2 — Webhooks
Subscribe once and let Upwell push the changes to you. Configure subscriptions in the Upwell dashboard (see Outbound webhooks for the model, payload shape, and auth).
The webhook event catalog is the source of truth for trigger
strings and dispatch rules (each change fires at most one trigger — the most specific that
applies).
Which should I use?
Webhooks
Best when you can host an HTTPS endpoint. Near-real-time, no polling load.
Polling
Best when you can’t receive inbound requests, or as a backstop. Read
GET /carrier_invoices/{id} (+ /documents) with backoff.Webhook delivery retries on
5xx and can be delayed under load. A robust integration uses webhooks for timeliness and reconciles with a periodic poll so a missed delivery never leaves an invoice stuck in your system. Both approaches are shown above, and Outbound webhooks covers the delivery and retry behavior in full.
