> For the complete documentation index, see [llms.txt](https://docs.moderncollections.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.moderncollections.io/rest-api/payments.md).

# Payments

Payments enter the platform through two paths:

1. **Stripe-processed** — the debtor pays via the portal (`POST /v1/portal/payment-intents` creates a Stripe PaymentIntent). Stripe webhooks notify the platform; the payment is reconciled automatically.
2. **Out-of-band** — payment received outside the platform (ACH to the creditor, wire, paper check, etc.). Recorded by the creditor via `POST /v1/placements/{id}/payment-received`.

## Payment commitment vs. payment attempt vs. remittance

| Concept                                      | Meaning                                                                                               |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| **Payment commitment** (`PaymentCommitment`) | A *promise* — captured during a call or via the portal. Surfaces in dashboard and triggers follow-up. |
| **Payment attempt** (`PaymentAttempt`)       | A Stripe `pi_*` interaction. Status enum: `requires_payment_method`, `succeeded`, `failed`, etc.      |
| **Remittance** (`Remittance`)                | The creditor-facing payout row: `recovered_amount`, `fee_amount`, `net_remit_amount`, status.         |

## Endpoints

| Method | Path                                             | Purpose                                                                                                                      |
| ------ | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/v1/payments`                                   | List commitments + recent attempts for the authenticated creditor. Query: `page`, `page_size` (max 200).                     |
| `GET`  | `/v1/payments/{placement_id}/attempts`           | All Stripe payment attempts for a placement.                                                                                 |
| `GET`  | `/v1/placements/{placement_id}/payments`         | All payment commitments for a placement.                                                                                     |
| `POST` | `/v1/placements/{placement_id}/payment-received` | Record an out-of-band payment. Body: `{"amount": <decimal>}`.                                                                |
| `GET`  | `/v1/creditors/me/remittances`                   | Remittance ledger for the authenticated creditor. Filters: `status`, `created_after`, `created_before`, `page`, `page_size`. |
| `GET`  | `/v1/placements/{placement_id}/remittance`       | All remittance rows for one placement.                                                                                       |

There is no `POST /v1/payments` endpoint, no `/v1/payment_plans` endpoint, and no `payments.record` operation today.

## Recording an out-of-band payment

```bash
curl -X POST https://<api-host>/v1/placements/$PLACEMENT_ID/payment-received \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"amount": 7500.00}'
```

Response:

```json
{
  "placement_id": "550e8400-...",
  "recovered_amount": 7500.00,
  "fee_amount": 375.00,
  "status": "paid"
}
```

The fee amount is computed from the creditor's `contingency_pct` snapshot. The endpoint accepts `amount` as a string, `Decimal`, integer, or float (routed through `Decimal(str(...))` to avoid binary drift). Amounts ≤ 0 return `400 {"detail": "amount must be positive"}`.

## Payment commitment shape

```json
{
  "id": "<uuid>",
  "type": "lump_sum",
  "total_amount": 7500.00,
  "installments": [],
  "committed_at": "2026-04-15T10:00:00Z",
  "next_followup_at": "2026-04-22T10:00:00Z",
  "status": "pending"
}
```

Commitment `status` values seen today: `pending` (created from a call or settlement), `fulfilled` (marked paid via `payment-received`), `completed` (recorded off a successful Stripe payment). Commitment `type` values: `full_payment`, `payment_plan`, `partial`.

## Payment attempt shape

```json
{
  "id": "<uuid>",
  "amount_cents": 750000,
  "currency": "usd",
  "status": "succeeded",
  "method": "card",
  "failure_code": null,
  "created_at": "2026-04-15T10:00:00Z",
  "stripe_payment_intent_id": "pi_..."
}
```

Note: payment attempts use `amount_cents` (integer); recorded payments and remittances use decimal amounts. This is intentional — Stripe APIs deal in cents.

## Remittance shape

```json
{
  "id": "<uuid>",
  "placement_id": "<uuid>",
  "payment_attempt_id": "<uuid>",
  "recovered_amount": 7500.00,
  "fee_amount": 375.00,
  "net_remit_amount": 7125.00,
  "currency": "USD",
  "status": "paid",
  "stripe_transfer_id": "tr_...",
  "failure_reason": null,
  "created_at": "2026-04-15T11:00:00Z",
  "paid_at": "2026-04-16T08:00:00Z",
  "metadata": {"contingency_pct_snapshot": "5.00"}
}
```

The remittance list response also returns an `aggregates` block (totals across the filtered set) so a dashboard's "you've been paid out $X" tile doesn't go stale as the operator pages.

### When a remittance lands in `manual_required`

Automatic disbursement requires **both** a linked Stripe Connect account **and** `payouts_enabled = true` on the creditor. If payouts are not enabled, the remittance is created with `status = "manual_required"` rather than being transferred automatically — the funds are held for operator-driven payout instead of moving to your bank. A linked Connect account alone is no longer sufficient. Ask your account manager to enable payouts once your Connect onboarding is complete.

## Payment plans

A `PaymentCommitment` with a multi-installment `installments` array represents a plan, but there is no dedicated `POST /v1/payment_plans` endpoint today. Plans are created internally via voice/email agent flows.

## See also

* [Webhooks: payment.commitment\_made](/webhooks/events/payment.commitment_made.md)
* [Guides: reconcile payments back to accounting](/integration-guides/reconcile-payments-back-to-accounting.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.moderncollections.io/rest-api/payments.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
