Recording customer payments
A customer payment is an incoming remittance from a shipper/customer applied against their receivable invoices. It has two levels:- The payment (
pym_…) — the money that arrived: an amount, a currency, a transaction date, and the check/ACH reference it came in on. - Its line items (
pli_…) — how that money is split across your invoices. Each line item applies an amount to a specific invoice (inv_…) for a specific customer (cus_…).
This is the accounts-receivable (money in) side. For paying carriers (money out) the resource is
bill-payments, which is a separate endpoint family. For the AR concepts behind these records — reconciliation, short-pays, and the like — see Remittances Management and Accounts Receivable Management.Create a payment with its line items
The primary flow is a singlePOST /api/rest/customer_payments that inserts the payment and its line items together, using a nested paymentLineItems.data array:
When line items are nested under the payment like this, omit
paymentId on each line item — the parent payment supplies the link. Fields you don’t set come back null.Required fields
Field reference
Payment (pym_…)
Line item (
pli_…)
The line-item amounts don’t have to sum to the payment’s
totalAmount — a remittance can be partially applied and reconciled later. For the complete column list, see the customer_payments and customer_payment_line_items entries in the API Reference.Two different status fields
These are not the same field, and the difference matters:
- Payment
statusis optional and drawn fromPaymentStatusesEnum:PENDING,SUCCEEDED,FAILED,DISPUTED,REFUNDED,PAYMENT_REVERSED— each defined in the Vocabulary. Most payments leave it unset, and an unset status means the payment succeeded, so read it asstatus ?? SUCCEEDED. - Line-item
statusis a required free-form string, not a fixed enum. In practice it carries reconciliation states likeapplied,paid, orcompleted. Don’t assume a closed set of values or a fixed casing — read it as an opaque string and set whatever your workflow uses.
Read payments back
POST /api/rest/customer_payments/search with a Hasura-style where:
Create many at once
POST /api/rest/bulk-customer-payments inserts an array of payments in one call. The response is a Hasura mutation envelope — read the created rows from returning:
Update and delete
Line items on their own
If you’d rather attach line items to an existing payment (or manage them independently), use the line-item endpoints directly —GET/POST /api/rest/customer_payment_line_items and .../customer_payment_line_items/{id}. Here, set paymentId explicitly to link the line item to its payment:
POST /api/rest/bulk-customer-payment-line-items bulk-creates several at once, the same { "inputs": [...] } shape as bulk-customer-payments:
Idempotency and deduplication
If you setsourceSystem and sourceSystemId, the pair is unique per tenant — within your organization no two payments can share it, and no two line items can either. Use your own remittance/transaction reference as sourceSystemId so re-posting the same remittance conflicts instead of creating a duplicate — a simple idempotency key for retried imports.
For the complete request and response schemas, see the
customer_payments and customer_payment_line_items entries in the API Reference. To submit carrier invoices (the payables side) instead, see Submitting carrier invoices via API.
