Skip to main content

Managing customer invoices

A customer invoice (inv_…) is what you bill your customer (shipper) for a shipment — the accounts-receivable side. This page covers creating invoices, adding line items and documents, and reading them back.
This is the AR (money in) side. For submitting carrier invoices (money out, AP), see Submitting carrier invoices via API. For the relationship between these objects, see Core concepts & data model.

Prerequisites

Create an invoice

POST /api/rest/invoices creates a customer invoice. The invoice is tied to a shipment and a customer:

Fields

FieldRequiredNotes
balanceYesOutstanding balance in integer cents. For a new invoice, equals totalAmount. NOT NULL with no server default — omitting it is a 400.
customerIdRecommendedLinks the invoice to a customer (cus_…).
invoiceShipmentsRecommendedLinks the invoice to one or more shipments via a nested relation: { "data": [{ "shipmentId": "shi_…" }] }.
numberRecommendedYour invoice number.
totalAmountRecommendedInvoice total in integer cents. $4,500.00450000.
currencyNoISO code, defaults to USD.
issueDateRecommendedThe date on the invoice (YYYY-MM-DD).
dueDateRecommendedPayment due date (YYYY-MM-DD). Drives aging and reminder scheduling.
sourceSystem / sourceSystemIdRecommendedExternal key pair — unique per tenant. See Integration patterns.
customerPoNumber, billOfLadingNumberNoReference numbers.
statusNoSee Invoice lifecycle for the full list. Defaults to CREATED for new invoices.
POST is not retry-safe for invoices — re-posting an existing (sourceSystem, sourceSystemId) pair returns a 400 Uniqueness violation. Use POST for first sync, PUT for updates. See Integration patterns.

Add line items

POST /api/rest/invoice_line_items adds a line item to an existing invoice:
FieldNotes
invoiceIdRequired. The invoice this line item belongs to (inv_…).
lineNumberLine sequence (string).
itemShort description (e.g. charge type).
descriptionLonger description.
quantityQuantity (numeric).
unitPricePer-unit price in integer cents.
totalAmountLine total in integer cents.
sourceSystem / sourceSystemIdYour external key for this line item.
Update with PATCH /api/rest/invoice_line_items/{id}. Delete with DELETE /api/rest/invoice_line_items/{id}.

Attach documents to an invoice

Attach supporting documents (the invoice PDF, BOLs, PODs) to a customer invoice using the same presigned-upload flow as carrier invoices:
1

Request a presigned URL

POST /api/rest/generate-upload-presigned-url with associationType: "INVOICE" and associationId set to the invoice ID.
2

PUT the bytes

Upload the raw file to uploadUrl.
You can also attach documents from the shipment — documents on a shipment are automatically visible on invoices linked to that shipment, so you often don’t need to re-upload. See Working with shipment documents.
Alternatively, POST /api/rest/invoices/{invoiceId}/documents accepts base64-encoded documents directly — convenient for smaller files. For large documents, the presigned-URL flow avoids payload size limits.

Read invoices back

Search by source system

POST /api/rest/invoices/search finds invoices by their external key:
The endpoint accepts a Hasura-style where filter (plus orderBy, limit, offset). The response includes nested invoiceLineItems so you can read the full invoice in one call.

List an invoice’s documents

Update an invoice

PUT /api/rest/invoices/{id} updates by Upwell ID. PUT /api/rest/invoices (without an ID) updates by sourceSystem + sourceSystemId in the body.

Invoice lifecycle

Invoices move through these statuses:
StatusMeaning
CREATEDInvoice record exists but hasn’t been finalized.
OPENInvoice is finalized and ready for delivery.
APPROVEDInvoice has been approved for sending.
PROCESSINGInvoice is being processed for delivery.
SENTInvoice has been delivered to the customer.
DELIVEREDInvoice delivery has been confirmed.
VIEWEDCustomer has viewed the invoice (online portal).
OVERDUEPast due date with an outstanding balance.
PART_PAIDPartially paid — balance is between 0 and totalAmount.
PAIDFully paid — balance is 0.
DISPUTEDCustomer has raised a dispute.
PORTAL_EXCEPTIONThe invoice hit an exception during portal delivery.
PORTAL_RESOLVEDA portal exception has been resolved.
REJECTEDInvoice was rejected.
CANCELLEDInvoice was cancelled.
WRITE_OFFWritten off as uncollectable.
REFUNDEDA refund was issued.
SEND_ERRORInvoice delivery failed.
When a customer payment is applied to an invoice, update the invoice’s balance and status accordingly. Some TMS integrations manage this in Upwell; others update invoices from the TMS when payment is recorded there.

Webhook events

Subscribe to invoice events in the Upwell dashboard to get notified of status changes:
TriggerFires when
create.invoiceAn invoice is created.
update.invoiceAny field change on an invoice.
update.invoice.status.SENTThe invoice was sent to the customer.
update.invoice.status.PORTAL_EXCEPTIONThe invoice hit an exception.
See Outbound webhooks for the delivery model and payload format.

What’s next

Customer payments

Record remittances applied to these invoices.

Statements & reminders

Automated follow-up on outstanding invoices.

Receivables management

The AR dashboard and reconciliation workflow.

Shipment documents

Attach supporting docs to shipments (shared with linked invoices).