You earned this revenue. Your billing stack never collected it.
This API compares your contract, your usage meter, your invoices and your payments for one period. It returns every discrepancy it can prove: in dollars, with the arithmetic and the fix attached.
Runs the same engine the paid endpoint uses. Nothing is stored and no key is needed.
Press “Run revenue check” to call the live API.
Four systems hold the truth. None of them compare notes.
The signed rate lives in the contract. The quantity lives in your usage meter. The charge lives in the invoice. The cash lives with the processor. Stripe reconciles Stripe to Stripe. Zuora reconciles Zuora to Zuora. Nobody reconciles the gap between all four: and that gap is exactly where revenue you already earned falls out.
Usage you metered but never invoiced
Your meter recorded 3,120 GB of egress. The invoice has no egress line at all. Neither system is wrong on its own, so nothing alerts, the period closes, and work you already delivered is never billed.
Rates that drifted from the signed contract
The order form says $0.0027 per call. The billing config says $0.0025. Each is internally consistent, so each passes its own reconciliation. Across 140 million calls the difference is real money: and it repeats every month until someone compares the two documents.
Invoices nobody chased
A partial payment nobody followed up. A minimum commitment nobody trued up. A duplicated line the customer was over-billed for and will eventually ask about. Billed is not collected, and both directions age quietly out of everyone's queue.
Caught at close it is an invoice correction. Caught two quarters later it is a negotiation.
Leakage is never one dramatic failure. It is a hundred small ones that each look like nothing in isolation. Industry estimates put SaaS revenue leakage at 3–5% of ARR: on $20M of ARR, that is $600K to $1M a year earned, delivered, and never collected.
The market already prices this problem. Recovery-audit firms are routinely paid 20–30% of whatever they claw back, which is a proven benchmark for what finance teams will pay to recover money after the fact. Every month you find it earlier, you keep more of it and argue about less of it.
Send all four record sets. Get back every discrepancy it can prove.
You post one period: contract terms, metered usage, invoice lines and payments. The engine compares them against each other rather than each system against itself, and returns typed findings. Every finding carries a signed dollar impact, the records it was derived from, and the one action that fixes it.
unbilled_usageUnits were metered against a contracted SKU and never invoiced at all.quantity_mismatchMetered quantity and invoiced quantity disagree, in either direction.rate_mismatchThe amount charged does not match the contracted rate for the quantity that was invoiced.duplicate_invoice_lineThe same SKU appears more than once on one invoice. The customer was over-billed.minimum_commitment_shortfallUsage earned less than the committed minimum and the difference was never trued up.underpaymentAn invoice was issued in full and only partly paid.uncontracted_skuUsage or invoice lines exist for a SKU with no contract term. Reported with zero impact: without a contracted rate no number can be proven, and the API will not guess one.Each finding also carries a repair drawn from a closed set: issue_invoice, issue_credit_note, correct_invoice_rate, collect_payment, true_up_commitment, review_contract. Over-billing comes back as a negative impactMinor with a credit note, so netImpactMinor is honest in both directions while recoverableMinor sums only what you can actually collect.
One period, one call, and what actually came back
Below is a request to the public demo endpoint and the exact response it returned. The period is synthetic; the engine and the arithmetic are the same ones the paid endpoint runs.
{
"periodLabel": "2026-07",
"contract": [
{ "sku": "api-calls", "ratePerUnitMicro": 2700, "includedUnits": 2000000, "minimumCommitmentMinor": 250000 },
{ "sku": "seats", "ratePerUnitMicro": 4500000 },
{ "sku": "egress-gb", "ratePerUnitMicro": 90000 }
],
"usage": [
{ "sku": "api-calls", "quantity": 141880000 },
{ "sku": "seats", "quantity": 120 },
{ "sku": "egress-gb", "quantity": 3120 }
],
"invoices": [
{ "invoiceId": "INV-2026-07-118", "sku": "api-calls", "quantity": 141880000, "amountMinor": 34970000 },
{ "invoiceId": "INV-2026-07-118", "sku": "seats", "quantity": 120, "amountMinor": 54000 }
],
"payments": [
{ "invoiceId": "INV-2026-07-118", "amountMinor": 35000000 }
]
}{
"periodLabel": "2026-07",
"netImpactMinor": 2849680,
"recoverableMinor": 2849680,
"findingCount": 3,
"findings": [
{
"code": "rate_mismatch",
"severity": "high",
"sku": "api-calls",
"impactMinor": 2797600,
"summary": "\"api-calls\" was invoiced 34970000 minor units for 141880000 units, but the contracted rate gives 37767600.",
"evidence": [
{
"kind": "contract",
"reference": "api-calls",
"detail": "contracted rate 2700 micro-cents/unit"
},
{
"kind": "invoice",
"reference": "INV-2026-07-118",
"detail": "141880000 units charged 34970000 minor units"
}
],
"repair": {
"action": "correct_invoice_rate",
"deltaMinor": 2797600,
"description": "Reprice the \"api-calls\" line(s) to the contracted rate. Net adjustment 2797600 minor units."
}
},
{
"code": "unbilled_usage",
"severity": "high",
"sku": "egress-gb",
"impactMinor": 28080,
"summary": "3120 units of \"egress-gb\" were metered but never invoiced.",
"evidence": [
{
"kind": "contract",
"reference": "egress-gb",
"detail": "rate 90000 micro-cents/unit"
},
{
"kind": "usage",
"reference": "egress-gb",
"detail": "3120 units metered"
}
],
"repair": {
"action": "issue_invoice",
"deltaMinor": 28080,
"description": "Invoice the 3120 unbilled unit(s) of \"egress-gb\" at the contracted rate: 28080 minor units."
}
},
{
"code": "underpayment",
"severity": "high",
"sku": "*",
"impactMinor": 24000,
"summary": "Invoice INV-2026-07-118 totals 35024000 minor units but only 35000000 was received.",
"evidence": [
{
"kind": "invoice",
"reference": "INV-2026-07-118",
"detail": "35024000 minor units invoiced"
},
{
"kind": "payment",
"reference": "INV-2026-07-118",
"detail": "35000000 minor units received"
}
],
"repair": {
"action": "collect_payment",
"deltaMinor": 24000,
"description": "Collect the outstanding 24000 minor units on invoice INV-2026-07-118."
}
}
],
"severityCounts": {
"high": 3,
"medium": 0,
"low": 0
},
"requestId": "9021984c-dfaa-4273-8caf-b38e1d6504ae"
}seats SKU matched its contract exactly and produced no finding at all: a clean SKU stays silent, so the output is a work list rather than a report to read.
Why money is integers and rates are micro-cents
Amounts are integer minor units (cents) never floating point. Rates are integer micro-cents, one ten-thousandth of a cent, because real usage pricing routinely goes below a cent per unit. $0.0027 per API call is 2,700 micro-cents. Store that rate as cents and it rounds to zero, and the rate comparison you were trying to run silently reports no difference on every line.
Rounding happens exactly once, at the end of a calculation, never per unit. In the response above: 139,880,000 billable calls × 2,700 micro-cents = 377,676,000,000 micro-cents, divided by 10,000 and rounded once = 37,767,600 cents, which is $377,676.00. Round per unit instead and the error compounds across every unit in the period, which is one of the failure modes this API exists to catch.
One call per period, run at close
Send the four record sets
Post the contract terms, metered usage, invoice lines and payments for one period. Read-only data you already have, in one JSON body. No OAuth scope and no standing access to your billing systems.
Get typed findings with the arithmetic
Each discrepancy comes back with a code, a severity, a signed dollar impact and an
evidencearray naming the exact records it was derived from. Nothing is asserted without the records behind it.Act on the repair plan
Every finding names the action (issue an invoice, credit a line, correct a rate, true up a commitment, collect a payment) and the exact amount. Hand it to billing, or drive it from your own code.
A small, versioned surface you can wire up in an afternoon
Authenticate with Authorization: Bearer <key>. Every error returns a stable code and a requestId you can quote. One reconciliation is one billed unit, and it is metered only after the call succeeds.
/v1/reconciliationsReconcile one period. Returns findings, evidence, repair plans, netImpactMinor and recoverableMinor. Key required; costs one reconciliation./v1/demo/reconcilePublic, keyless. Runs the real engine on up to 100 records total. Nothing stored, nothing metered: this is what the check at the top of this page calls./v1/sandbox/examplePublic. A runnable example payload you can post as-is.curl -X POST https://revenueintegrity-api.com/v1/reconciliations \ -H "Authorization: Bearer $REVENUE_INTEGRITY_KEY" \ -H "content-type: application/json" \ -d @period-2026-07.json
Full reference: API reference · Quickstart: two calls to a key · OpenAPI: /openapi.json · Health: /health
Deterministic, not probabilistic
Same input, same output, byte for byte. No model, no sampling, no clock. A finance team re-running last month's close gets last month's numbers.
Every finding shows its working
Each result names the contract term, the metered total and the invoice lines it was computed from, so a disputed number can be traced back to records on both sides.
Your data stays yours
The engine is stateless per request. The check at the top of this page stores nothing at all, and no connector holds standing access to your billing systems.
This service is newly launched. We publish no uptime percentage, customer count, logo, testimonial or certification claim until we have the operating history to support one.
Priced per reconciliation, capped so a runaway job cannot surprise you
Start free with 5 reconciliations a month, no card. Every paid plan includes an allowance, then a per-unit overage that is hard-capped per billing period: so your worst-case bill is the base price plus the cap, never more.
- 50 reconciliations included
- $12.00 per additional reconciliation
- Overage capped at $1,000 per period
- Full API access, Python and TypeScript SDKs
- 250 reconciliations included
- $8.00 per additional reconciliation
- Overage capped at $3,000 per period
- Full API access, Python and TypeScript SDKs
- 1,200 reconciliations included
- $5.00 per additional reconciliation
- Overage capped at $10,000 per period
- Full API access, Python and TypeScript SDKs
- 4,000 reconciliations included
- $3.00 per additional reconciliation
- Overage capped at $20,000 per period
- Full API access, Python and TypeScript SDKs
Prices in USD, billed monthly. Payment is processed by Square through our shared billing platform; card details never touch this site.
Run it on a month you have already closed
Paste one real period into the check above (contract, usage, invoices, payments) and see what comes back in dollars. Free for five reconciliations a month, no card.
One email address, no password, no card: the key is waiting on the other side.
Questions
What counts as one reconciliation?
Do you connect to Stripe, Zuora or NetSuite directly?
How is the dollar impact calculated?
What if a SKU has no contract term?
uncontracted_sku with a zero dollar impact. Without a contracted rate no impact can be proven, and the API will not guess one.