Skip to main content
When records in a reconciliation stay unmatched past their overdue_at, End Close opens an exception for the data stream and your reviewers see the open lines on the Exceptions page, one note per line. End Close writes those notes itself. If you already run your own matching engine, you can write them instead: your engine knows your billing rules, so its reasons are the ones your reviewers want to read. Lines your rules (or your engine, through POST /reconciliation_matches) have already matched are done and need no finding. Write findings for the lines that are left.

Prerequisites

  • An API key for the environment.
  • The reconciliation’s id and the id of the data stream whose lines you are reviewing (GET /reconciliations).

Write findings

Send one finding per open record. Identify the record by record_id, or by the external_id you gave it when you created it. A finding with suggestion.kind of match or adjust becomes the Approve action in the review; looks_right: true turns the line gray so it can be confirmed in bulk.
cURL
Response
This endpoint opens the exception for the data stream if the sweeper has not yet, and reuses the open one otherwise. When you already have the exception id, PUT /reconciliation_exceptions/{id}/findings takes the same body and returns { "upserted", "errors" }. Each finding is checked on its own. A bad record id, an empty note or an unknown record in suggestion.record_ids rejects that finding only; the rest are written and the response lists the rejected ones by position:
Partial success
Findings are keyed on the record, so re-sending a record replaces its finding. Send up to 1,000 per request. An evidence quote can carry a url to the document it came from — a contract uploaded to Files, say, using the file’s url. End it with #page=N and the review opens the PDF at that page: the row shows a document icon, and the drawer labels the quote’s link “Open p.N” and shows the document inline.
suggestion.record_ids lists every other record of the proposed match, on either side of the reconciliation — a roll-up names its sibling lines along with the invoice line. End Close recomputes the difference from the records’ amounts; a match that does not balance is refused when the reviewer approves it, so use adjust with a reason when a gap is expected.

Read the review back

cURL
Each row carries the record, its finding, a status derived on read — done once the record is matched, looks_right when the finding says so, to_look_at otherwise — and difference_cents, the gap between the line and what the finding found on the other side. Lines that carry a count (metadata.quantity, qty, count, event_qty or units on the record) also get quantity, other_quantity (the suggested records’ counts, summed into finding.other_side.count) and quantity_difference, so a billing review can see 27,468 vs 27,467 without reading the note. counts gives the totals per status, categories the finding categories with how many lines carry each, and pending_notes is the number of overdue lines that have no finding yet. status defaults to to_look_at; category (repeatable) and q narrow the page, and sort + dir order it by any column. GET /reconciliation_exceptions/{id} adds reasons, the adjustment reasons already used on the reconciliation. The full request and response shapes are under Reconciliation Exceptions in the API reference.