Skip to main content
Check a completed invoice against the agreements it is matched to. Each completed evaluation is an immutable ComplianceCheck, including evaluations that found nothing. Work that fails or is cancelled never produces a check.
Omit the body to check every eligible matched agreement. Supplied agreements are all-or-nothing. One check takes at most 20 agreements; an invoice with more returns 409 conflict until you supply agreement_ids. New work returns 202 with workflow_run_id and a Location header. Starting, retrying and cancelling require Write access. Reading checks, findings and workflow status requires Read.

What is eligible

The invoice must be completed, not a credit note, not covered by an active credit-note match, and have a primary document. The agreement must be matched to the invoice, active, and ready: it has a supplier, a title, usable content, and every terms document has finished processing. Matching is a separate command and is not run by a check. No claim may hold the pair: an invoice and agreement pair is not checked again while a claim that is not cancelled holds one of its alerts that is not dismissed. A check replaces all of a pair’s alerts, so this keeps claimed alerts, and the rest of that evaluation, as they were claimed. Idempotency-Key is optional. A replay returns 200 with the original run. Without a key, the in-progress guard still prevents two checks of the same pair from running at once.

Follow the work

One workflow run groups the request. One item evaluates one invoice and agreement pair. The selected agreements, the agreement version and the invoice fingerprint are captured at admission.
A completed item’s result contains compliance_check_id, finding_count and completeness. A failed item carries one of these codes: Cancel with POST /v1/workflow-runs/{id}/cancel. Cancelled work never replaces current findings.

Retry

Retry creates a new run linked to the named one and reruns its failed or cancelled items, or the subset in item_ids. Eligibility is verified again and current inputs are captured. Completed items are never rerun by retry. To reevaluate a completed pair, submit a new check.

Read results

GET /v1/compliance-checks lists completed checks, newest first. Filter with invoice_id, agreement_id, completed_from and completed_through. GET /v1/compliance-checks/{id}/findings returns the findings in their original order. Each finding has its own stable id. GET /v1/compliance-checks/{id}/transcript shows how the check reached its result: the display form of each tool call, in order, followed by its final summary when it fits the transcript size limit. Prompts and reasoning are not retained. completed_from and completed_through are calendar dates in your organization’s timezone. A check records what it read: the agreement version, the invoice fingerprint, and the identity and checksum of each source document. Each finding carries the invoice line values, the expected values, the cited excerpts and the referenced price item values as they were at publication. None of this changes when the invoice is edited, a price is deleted, a document is unlinked, or the resulting alert is edited or dismissed. freshness is derived when you read a check. outdated means the invoice evidence or the agreement version has changed since. The check itself is unchanged. The newest check for a pair is first in the list.

Check an agreement

An agreement check covers the agreement’s matched invoices that have no current result: never checked, or last check failed or was cancelled. Those are the invoices GET /v1/invoices?agreement_ids=$AGREEMENT_ID&alert_scope=selected_agreements&alert_checked=false&alert_checkable=true lists, apart from invoices already being checked, invoices without a primary document and pairs a claim holds. Send {"invoice_ids": [...]} (up to 20) to check a sample of them. Completed checks are kept, including outdated ones; check the invoice to re-evaluate one. The response is 202 with workflow_run_id, invoice_count and has_more: one request takes at most 5000 invoices, newest first, so repeat it after the run when has_more is true. The agreement must be active and ready (409 agreement_not_checkable); with nothing to check the response is 409 nothing_to_check and nothing starts. POST /v1/agreements/check does the same for every active, ready agreement and returns workflow_run_ids, one agreement check each, and has_more. The 5000-invoice limit applies to the request in total, filled agreement by agreement in ID order, newest invoices first. Every admitted run is returned: one whose dispatch failed fails, its items with dispatch_failed, and one whose acceptance was not confirmed either starts or, if it has not started five minutes after admission, fails with admission_expired items. Either way its invoices are unchecked again. With nothing to check it returns 200 with an empty list. An invoice check captures its inputs at admission; an agreement check’s item reads them when it starts, so stale_input means they changed after that. /check/retry applies to invoice checks only: to retry an agreement check, request it again, since failed and cancelled pairs count as unchecked. Items otherwise behave like invoice check items, with the same failure codes. A pair whose agreement is deactivated, or that a claim comes to hold, while the check waits fails not_eligible without replacing its alerts (a pair a claim holds keeps its last result), so agreements can be edited or deactivated during a check.

Recheck a topic

POST /v1/alert-topics/{id}/recheck checks the topic’s agreement again against every invoice behind the topic’s alerts, completed checks included, as one agreement check. Each invoice’s check replaces all of that invoice’s alerts for the agreement, including alerts in other topics; dismissed or credited alerts come back as new pending alerts if the check finds them again. Invoices a claim holds, invoices already being checked and invoices that cannot be checked are left as they are and counted in skipped_count. The response is 202 with workflow_run_id, invoice_count and skipped_count; with nothing to recheck it is 409 nothing_to_check. A pair whose check fails keeps its alerts and counts as unchecked, so the next agreement check retries it. A recheck is not idempotent: once its run finishes, the same request starts a new one.

Reset checks

POST /v1/invoices/{id}/check/reset and POST /v1/agreements/{id}/check/reset start an invoice’s or an agreement’s evaluation over: unfinished checks are cancelled, the pairs’ alerts are deleted, and every pair is marked unchecked so an agreement check picks it up again. A pair a claim holds keeps its alerts and its result. Completed checks are kept. The response reports deleted_alert_count, kept_alert_count and cancelled_check_count. When matching removes an invoice’s match to an agreement, that pair is reset the same way, so only a pair a claim holds keeps its alerts after losing its match.

How checks relate to alerts

Publishing a check replaces all of the pair’s previous alerts with its findings, including dismissed or credited ones, which come back as new pending alerts if the check finds them again. A pair a claim holds is never checked, so its alerts stay as they were claimed. A finding’s alert_id names the alert it became. A later check may replace that alert, and the finding keeps the original id. An alert’s provenance.retained_check links back to the check that produced it. The invoice alert_summary reports running, failed, cancelled and outdated checks from the same work.