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
| Level | Required | Notes |
|---|---|---|
| Payment | totalAmount, transactionDate | currency defaults to USD if omitted. id, timestamps, and tenant are set for you. |
| Line item | totalAmount, transactionDate, status | Add invoiceId (+ customerId) to actually apply the amount to a receivable. |
Field reference
Payment (pym_…)
| Field | Meaning |
|---|---|
totalAmount | Amount received, in cents. |
currency | ISO-4217 code (CurrencyCodeEnum, e.g. USD). Defaults to USD. |
transactionDate | Date the payment was transacted (YYYY-MM-DD). |
checkOrAchNumber / checkDate | The check or ACH reference and its date. |
status | Optional payment-level status — see below. |
sourceSystem / sourceSystemId | Your system’s identifier for this remittance — see idempotency. |
paymentLineItems | Nested { "data": [ … ] } array of line items. |
pli_…)
| Field | Meaning |
|---|---|
totalAmount | Amount applied to the invoice, in cents. |
fees | Fees withheld, in cents (defaults to 0). |
invoiceId | The receivable invoice (inv_…) this amount is applied to. |
customerId | The customer (cus_…) the payment is from. |
status | Free-form line-item state — see below. |
transactionDate | Date the line item was transacted (YYYY-MM-DD). |
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, always-current 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. Most payments leave it unset. - 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:
Idempotency and deduplication
If you setsourceSystem and sourceSystemId, the pair is unique per tenant (there’s a uniqueness constraint on (tenant_id, source_system, source_system_id) for both payments and line items). 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, always-current 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.
