> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upwell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Recording customer payments (remittances) via the API

> Create, read, and reconcile customer payments (remittances) and their line items — how a remittance applies to your receivable invoices.

# 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 page covers creating a payment with its line items, reading it back, and reconciling it against receivables.

<Note>
  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](/accounts-receivable/remittances) and [Accounts Receivable Management](/accounts-receivable/receivables).
</Note>

<Warning>
  **All amounts are integer cents.** `totalAmount: 1120000` is **\$11,200.00**, not eleven million dollars. This matches every monetary field in the Upwell API.
</Warning>

## Create a payment with its line items

The primary flow is a single `POST /api/rest/customer_payments` that inserts the payment **and** its line items together, using a nested `paymentLineItems.data` array:

```bash theme={null}
curl -X POST https://api.upwell.com/api/rest/customer_payments \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "input": {
          "totalAmount": 1120000,
          "transactionDate": "2026-07-07",
          "currency": "USD",
          "checkOrAchNumber": "CHK004321",
          "checkDate": "2026-07-07",
          "sourceSystem": "aljex",
          "sourceSystemId": "REMIT-88123",
          "paymentLineItems": {
            "data": [
              {
                "invoiceId": "inv_jkMtQfYE",
                "customerId": "cus_kCRVpEUv",
                "totalAmount": 1120000,
                "status": "applied",
                "transactionDate": "2026-07-07"
              }
            ]
          }
        }
      }'
# -> { "createCustomerPayment": {
#      "id": "pym_LQ-3Nnmq", "totalAmount": 1120000, "currency": "USD",
#      "checkOrAchNumber": "CHK004321", "transactionDate": "...", "createdAt": "...", "updatedAt": "...",
#      "paymentLineItems": [
#        { "id": "pli_qi9RW1Pd", "invoiceId": "inv_jkMtQfYE", "customerId": "cus_kCRVpEUv",
#          "totalAmount": 1120000, "status": "applied", "createdAt": "...", "updatedAt": "..." } ] } }
```

<Note>
  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`.
</Note>

## 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](#idempotency-and-deduplication). |
| `paymentLineItems`                | Nested `{ "data": [ … ] }` array of line items.                                                   |

**Line item (`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`).           |

<Note>
  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](/api-reference/introduction).
</Note>

### Two different `status` fields

These are **not** the same field, and the difference matters:

* **Payment `status`** is optional and drawn from `PaymentStatusesEnum`: `PENDING`, `SUCCEEDED`, `FAILED`, `DISPUTED`, `REFUNDED`, `PAYMENT_REVERSED`. Most payments leave it unset.
* **Line-item `status`** is a **required free-form string**, not a fixed enum. In practice it carries reconciliation states like `applied`, `paid`, or `completed`. 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

```bash theme={null}
# List (newest-first not guaranteed — use search for ordering)
curl "https://api.upwell.com/api/rest/customer_payments?limit=50" \
  -H "Authorization: YOUR_API_KEY"
# -> { "customerPayments": [ { "id": "pym_…", … } ] }

# One payment
curl https://api.upwell.com/api/rest/customer_payments/pym_LQ-3Nnmq \
  -H "Authorization: YOUR_API_KEY"
# -> { "customerPayment": { "id": "pym_LQ-3Nnmq", … } }
```

To filter or sort, use `POST /api/rest/customer_payments/search` with a Hasura-style `where`:

```bash theme={null}
curl -X POST https://api.upwell.com/api/rest/customer_payments/search \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "where": { "sourceSystemId": { "_eq": "REMIT-88123" } },
        "orderBy": { "createdAt": "DESC" }, "limit": 10, "offset": 0 }'
# -> { "customerPayments": [ … ] }
```

## 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`:

```bash theme={null}
curl -X POST https://api.upwell.com/api/rest/bulk-customer-payments \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "inputs": [ { "totalAmount": 3300, "transactionDate": "2026-07-08" },
                    { "totalAmount": 23880, "transactionDate": "2026-07-08" } ] }'
# -> { "createCustomerPayments": { "returning": [ { "id": "pym_…", … } ] } }
```

## Update and delete

```bash theme={null}
# Update — body carries an input object; id comes from the path
curl -X PUT https://api.upwell.com/api/rest/customer_payments/pym_LQ-3Nnmq \
  -H "Authorization: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{ "input": { "checkOrAchNumber": "1234567890" } }'
# -> { "updateCustomerPayment": { "id": "pym_LQ-3Nnmq", "checkOrAchNumber": "1234567890", … } }

# Delete
curl -X DELETE https://api.upwell.com/api/rest/customer_payments/pym_LQ-3Nnmq \
  -H "Authorization: YOUR_API_KEY"
# -> { "deleteCustomerPayment": { "id": "pym_LQ-3Nnmq" } }
```

## 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:

```bash theme={null}
curl -X POST https://api.upwell.com/api/rest/customer_payment_line_items \
  -H "Authorization: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{ "input": { "paymentId": "pym_LQ-3Nnmq", "invoiceId": "inv_jkMtQfYE",
                   "customerId": "cus_kCRVpEUv", "totalAmount": 1120000,
                   "status": "applied", "transactionDate": "2026-07-07" } }'
# -> { "createCustomerPaymentLineItem": { "id": "pli_qi9RW1Pd", … } }
```

## Idempotency and deduplication

If you set `sourceSystem` **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.

<Tip>
  Testing against staging? Use the staging base URL `https://staging.api.upwell.com` with your staging API key — the paths are identical.
</Tip>

<Note>
  For the complete, always-current request and response schemas, see the `customer_payments` and `customer_payment_line_items` entries in the [API Reference](/api-reference/introduction). To submit carrier invoices (the payables side) instead, see [Submitting carrier invoices via API](/api-guides/carrier-invoice-submission).
</Note>
