Billing, gateways, acquirers, ERP and tax invoice issuer
One status per invoice, matching by id and each number on its own date
Billings, cash and open amounts that tie out, plus exceptions
Month-end close, collections queue and finance AI agent
What it solves
- A single invoice table, with no invoice counted twice across accounts, gateways and retries.
- Billings, cash and delinquency reconcile with each other every month, to the cent.
- Sold but not received, received without an invoice and mismatched amounts become work lists, not end-of-quarter discoveries.
Business questions it answers
Ask your agent these questions once the case is live.
What you need
- Billing and gateways connected to Nekt, every account and company
- The ERP or tax invoice issuer, with the billing invoice id stored in some field
- The company's rule: what counts as recurring revenue and on which date each number is counted
What you get
- An invoice table with source, a single status and all three dates
- A monthly billings x cash x open reconciliation that ties out
- A receivables base by acquirer with settled and to-be-received amounts
- Exception tables for finance to review every week
Where to activate
The billings x cash x open reconciliation as the first report of the close, with the exceptions attached.
Exception tables sent to a spreadsheet or Slack every week, with an owner per type.
Answers about billings, cash and receivables with the date and status rule already applied.
Each gateway has its own structure, and matching with the ERP depends on a stored id. Start with one billing account and one closed month. The detailed view has the business rules, the pitfalls and the acceptance test. Or send everything straight to your agent with the Nekt MCP.
Revenue is spread across several billing accounts, two or three gateways and an ERP. The same charge appears on several rows: one per attempt, one per account, one in the payments table and another in the balance transactions table. Whoever sums everything inflates billings; whoever matches by amount and date reconciles the wrong customer. And what matters most, sales without money and money without a tax invoice, only shows up when accounting complains.
How it is usually done, and the rule
Each row is a mistake that already happened in practice.
Companies with more than one billing account (per group company, product line or subsidiary) stack the accounts into a single table with a source column. The invoice id is only unique within the account: the key is source + id. Every new account goes into the same table on the day it is connected.
Gateways generate more than one record for the same charge (duplicate copy, reissue, retry). Keep one per charge in this order: paid, chargeback, refunded, in protest, pending, expired; on a tie, the most recent. That way a paid duplicate copy doesn't coexist with the expired original.
Each card attempt becomes a charge row, and an invoice can have several declines before it is paid. Billings and cash count the document (billing invoice, e-commerce order), never the attempt. Declines go into their own table, one row per attempt, with a standardized decline code.
Month billings = gross cash from the month's invoices + what remains open on them. Each number has its own date: billings by accrual or issue date, cash by payment date, open by due date. If the identity doesn't hold in a month, there is a duplicate or a lost invoice, and the report doesn't go out.
Card money lands in the balance weeks after payment, and installment sales land per installment. Build receivables by transaction x installment with a status of settled or to be received. Net = amount minus fee, advance fee and anti-fraud fee. In the projection, remove sales with a chargeback or refund. Pix (instant payment) and boleto (bank payment slip) with no recorded payout land on the next bank business day, using a bank holiday calendar (movable holidays computed from Easter).
The ERP stores the billing invoice id in a custom field on the transaction and the billing customer id on the customer record. The product's invoice stores the gateway charge id (external_id). Match on those ids. To find sold but not received, bring only the paid side of the gateway into the join and list what is left unmatched.
Gateways have a charges table and a balance transactions table, which repeats every payment and adds fees and transfers. Revenue comes from the charges table. In Stripe, link charge to subscription through the invoice lines: the ready-made charges-by-subscription table only has the successful ones.
Stripe, Pagar.me and *_cents fields come in cents: divide by 100 once, in the first layer. Sales order lines in some ERPs come with an inverted sign and must be negated. Reversals and refunds go in as negative in cash and positive in the refunds table, never both in the same total.
When sales are issued by more than one group company, each report comes from one token per company and carries a company column. A global sale code that appears in both companies is a duplicate. If the issuing company changed on a date, the rule for which company applies is by a declared cutoff date.
The reconciliation doesn't delete or fix rows. It publishes one table per type of problem: approved outside the tax invoice issuer, approved with no tax invoice issued, product missing from the mapping, refunded with an active tax invoice, amount mismatch between billing and tax invoice, duplicate across companies. An empty table is the goal.
Gateway status to category
In the priority order used to keep one record per charge.
Definitions
Pitfalls that already happened
The first consolidated version summed one gateway's transactions table, which repeats every payment along with fees and transfers, and that gateway's revenue came out nearly double.
Revenue only from the charges table; balance transactions only for cash.
The failed renewals report started from the ready-made charges-by-subscription table, which only keeps successful charges. No decline ever showed up.
Link charge to subscription through the invoice lines.
The refunded flag only turns true when the full amount comes back. Partial refunds stayed as full revenue.
Use the refunded amount, not the flag.
A single receivable in finance covered more than one of the customer's contracts. Matching by customer repeated the receivable's amount on each contract.
Count how many contracts each receivable covers and allocate or deduplicate by receivable.
Dates came as Excel serial numbers (base 12/30/1899), quantities and unit prices arrived converted to dates, and some systems sent empty text instead of null.
Convert serials from 12/30/1899, reverse values read as dates and treat empty text as null in the first layer.
The same reason arrived as 051 in one gateway and 51 in another, and new reasons silently fell outside the mapping.
Strip the leading zero from three-character codes and keep a monitor for unmapped reasons.
Acceptance test
The case is done when every item passes.
- In each closed month, billings = gross cash + open, with zero difference.
- Each billing account's billings match the billing system's own dashboard for the same period (difference below 0.5%).
- The invoice table has no repeated source + id key, and no invoice has more than one status.
- An acquirer's settled net cash for the month matches the payouts received on the bank statement.
- Each exception table has an owner, and every row in it has a recorded reason or was resolved at the source.
Agent package
Paste into Claude, ChatGPT or any client with the Nekt MCP connected.
Billing reconciliation - The invoice table has one row per invoice, with a source column (billing account or gateway). The key is source + id. - Each charge has one status, chosen by priority: paid > chargeback > refunded > in_protest > pending > expired; on a tie, the most recent. - A payment attempt is not an invoice. Billings and cash count the document; declines are in the declines table, one row per attempt. - Month billings = gross cash + open on the month's invoices. Billings use accrual or issue date; cash uses the payment date; open uses the due date. - Net cash is per installment, on the acquirer's settlement date, minus fee, advance and anti-fraud fees. - Amounts from Stripe and *_cents fields are already converted to reais in the cleaned table. Don't divide again. - Partial refund: use the refunded amount, not the flag. - Matching with the ERP is by the billing invoice id stored in the ERP. Never match by amount and date. - For exception questions (sold but not received, no tax invoice, amount mismatch, duplicates), use the exception tables and don't recalculate. - If the question doesn't specify the date, answer by accrual and say so. Per-client exceptions: - <client>: recurring revenue only when the invoice line has a subscription; one-off and implementation charges stay out of recurring billings. - <client>: sales through <gateway> by external boleto (bank payment slip) stay out of the billing reconciliation. - <client>: until <date>, the issuing company was <headquarters>; after that, <branch>.
Build the "Billing reconciliation" case in my Nekt workspace following the rules at https://academy.nekt.com/en/industrias/saas/conciliacao-faturamento.md. 1) Find the source tables and confirm the columns the rules use. 2) Create a transformation at the stated grain applying every rule. 3) Run the acceptance test and show me the result of each item. 4) Create the case's context document in the workspace, leaving my clients' exceptions open for me to fill in.
Variations
A receivables hub by transaction x installment, with a daily report of settled and to-be-received amounts per acquirer.
Per-acquirer check using the gateway transaction's TID, NSU and authorization code against the statement.
A declines table with a standardized code, category and retryable flag, the foundation for dunning and card conversion.