# Reconciling with your accounting

Reconciliation matches the payments we recovered against the invoices in your books. Done correctly, your AR ledger reflects what's been collected, what's outstanding, and what's been paid to ai-collect in fees.

This page covers two reconciliation patterns:

1. **QuickBooks Online writeback** — your QBO is connected and we post a Payment to your invoice automatically each time a debtor payment clears.
2. **Manual reconciliation** — you import our CSV exports and post entries yourself.

## QuickBooks Online writeback

If you've [connected QuickBooks Online](/for-creditor-partners/creditor-onboarding/connecting-your-accounting.md), every successful debtor payment triggers an automatic writeback to QBO:

* We POST a `Payment` to the original Invoice using the QBO API. The invoice balance moves down by the recovered amount.
* The writeback runs **at the payment moment** — right after we mint the Remittance ledger row, not after the disbursement worker eventually transfers funds to your bank.
* The payment carries a memo stamp (`[ai-collect:placement={id}]`) so our inbound out-of-band classifier can recognise its own write on the return trip.
* The mapping between our `payment_attempts` row and the resulting QBO `Payment.Id` is recorded so a duplicate webhook delivery cannot post twice.

Writeback failures (QBO down, token expired, validation error) are recorded as `failed` mapping rows and surfaced as audit events. The Stripe webhook never crashes on a writeback failure — the reconciliation worker re-attempts on the next tick.

**No journal-entry mapping UI.** The writeback posts a QBO `Payment` against the existing invoice — we do not let you map fees, payouts, or clearing accounts to your chart of accounts today. A configurable account-mapping surface is planned but not yet available; for now, fees and disbursements remain a manual journal entry on your side.

**Drift detection.** A reconciliation worker periodically reads the live invoice balance from QBO and compares it to our cached number. Any drift greater than one cent is surfaced as an audit event in your **QBO sync log** (Settings → Integrations → QBO → Sync log). No auto-correction — drift triggers a human review, not a silent rewrite.

## Other accounting platforms

Xero, NetSuite, Sage Intacct, and QuickBooks Desktop are not connected today. If you use one of these, follow the manual reconciliation flow below until the corresponding integration ships.

## Manual reconciliation

If your accounting platform isn't connected, you reconcile from CSV exports.

1. Pull a remittance CSV: `POST /v1/exports` with `{"kind": "remittances", "params": {...}}`, or use the **Export** button on the Overview page. The job renders to storage and you download a signed URL.
2. For each row, in your accounting platform:
   * Mark the corresponding invoice as paid by `recovered_amount`. Match on `placement_id` (canonical) or on the invoice number captured at placement time.
   * Record an expense for `fee_amount` to your "Collections fees" account.
3. Record the bank deposit when the Stripe Connect transfer lands, matching `net_remit_amount` and the `stripe_transfer_id` reference (or the manual ACH reference if Connect isn't configured).

We do not ship a QuickBooks-ready import template today.

## Reconciling partial payments

If a debtor pays $500 against a $1,000 invoice:

* The placement's `recovered_amount` increases by $500.
* The placement stays open until `recovered_amount >= invoice_amount`, at which point its status flips to `paid`.
* A separate Remittance row is created for each partial payment, each with its own snapshotted contingency rate.
* The placement-level `fee_amount` is the rolling sum of those Remittance fees (so a later contingency-rate change cannot retroactively rewrite the prior partial's fee).

## Reconciling plan installments

A payment plan generates one Remittance row per installment, all referencing the same placement. The original invoice in your books is paid down installment by installment. If a plan installment is missed and recovered later, both events appear in the remittance ledger (sometimes in different months on the monthly statement).

## Reconciling reversals (chargebacks)

A chargeback mints a **separate** Remittance row with negative amounts and `status='reversed'`. To reconcile in your books:

1. Re-open the previously-paid invoice for the reversed amount.
2. Reverse the fee expense.
3. Reverse the bank deposit.

The original `paid` Remittance row is left untouched as an immutable record of the forward transfer — the negative reversal row carries the claw-back. Look for the `parent_remittance_id` field to tie a reversal back to the original.

The placement does **not** automatically return to outreach on reversal — that's an operator decision.

## Closing a placement in your books

* When a placement reaches `paid`, the QBO writeback (if connected) will already have applied the final Payment. For manual reconciliation, mark the invoice fully paid.
* When a placement reaches `closed_uncollected`, work with your tax accountant on the write-off — see [Handling write-offs](/for-creditor-partners/creditor-finance/handling-write-offs.md).

## Reconciliation cadence

Most customers reconcile monthly using the statement PDF. If you place high volume and want tighter feedback, pull the remittances CSV weekly or hook the per-payment webhooks (see the developer portal).

## Issues we've seen and how to resolve

| Issue                                          | Resolution                                                                                                                                                    |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Invoice number in CSV doesn't match your books | Use the `placement_id` as the canonical key; the invoice number is whatever you supplied at upload                                                            |
| Fee on a payment doesn't match expected %      | Check `metadata.contingency_pct_snapshot` on the Remittance — it carries the exact rate applied. Rates change forward-only; historic rows are pinned.         |
| Bank deposit doesn't match disbursement        | Stripe Connect handles its own processing time. Verify against `stripe_transfer_id` in your Stripe dashboard.                                                 |
| QBO drift shows up in the sync log             | Read the audit event. Drift may indicate an out-of-band payment recorded directly in QBO, an edited invoice, or a missed writeback — review before adjusting. |

## TODO

* Screenshot: QBO sync log view with a drift event.
* Screenshot: Overview page Export button.
* Screenshot: QBO writeback Payment in the QuickBooks UI.

***

Last reviewed: 2026-05-12 by Finance Lead.


---

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

```
GET https://help.moderncollections.io/for-creditor-partners/creditor-finance/reconciling-with-your-accounting.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
