Skip to content

Procure to pay (AP)

The complete payables stack: requisition → PO → receipt → bill → approval → payment → reconciliation.

AP is where fraud happens and where controls matter most. The design consequence:

Every AP screen is a control surface. Approval, segregation of duties, and duplicate detection are not features bolted onto a form — they are the reason the form exists.


1. The lifecycle

Requisition → PO → Goods receipt → Bill → Match → Approve → Schedule → Pay → Reconcile
      │        │         │           │       │        │                  │
      │        │         │           │       └────────┴─ the control gate │
      │        │         │           └─ Dr GR/IR or Expense / Cr AP       │
      │        │         └─ Dr Inventory/Expense / Cr GR/IR (if used)     │
      │        └─ commitment; no GL impact                    Dr AP / Cr Cash
      └─ no GL impact

No GL impact from requisitions or POs. The GL moves at goods receipt (if GR/IR is used) or at the bill. POs are commitments. Showing committed spend in an expense figure overstates it; showing only booked spend understates the obligation. Both matter — a spend view renders booked, accrued, and committed as three distinct series, never summed into one "spend" number.


2. Three-way match

The core AP control. Three documents must agree before payment.

  Purchase order        100 units @ $12.00   =  $1,200.00
  Goods receipt          98 units received
  Vendor invoice         100 units @ $12.00  =  $1,200.00
                        ─────────────────────────────────
  Quantity variance      2 units short           ($24.00)   ⚠ requires disposition
Match type Compares Used for
Two-way PO ↔ invoice Services, no physical receipt
Three-way PO ↔ receipt ↔ invoice Goods
Four-way + inspection/quality Regulated or high-value goods

UI rules:

  • Tolerances are configurable and displayed. "Matching within $50 or 2%" — a reviewer needs to know what is auto-passing.
  • A variance requires a disposition, never a silent pass: accept (with reason), request a vendor credit, partial-pay, or reject.
  • The three documents are shown side by side, line by line, with differences highlighted at the line level, not just the header. A header total that matches while lines don't is a common way overbilling hides.
  • MatchExceptionQueue is the AP clerk's worklist, sorted by age and amount.

3. The bill

type Bill = {
  vendorId: string;
  vendorInvoiceNumber: string;     // THEIR number — the duplicate-detection key
  billDate: Date;
  dueDate: Date;
  terms: PaymentTerms;
  currency: string;
  lines: BillLine[];               // each with account + full dimensions
  taxes: TaxLine[];
  total: Money;
  poReference?: string;
  approvals: Approval[];
  status: BillStatus;
  paymentSchedule?: Date;
  attachments: Document[];         // the source invoice — required
};

UI rules:

  • Duplicate detection runs before the form is saved, keyed on vendor + vendorInvoiceNumber, with a secondary fuzzy check on vendor + amount + date ± 5 days. Duplicate payment is one of the most common and most preventable AP losses, and the check must be a blocking warning showing the suspected duplicate side by side.
  • The source document is required. A bill with no attachment cannot be approved. This is the evidence an auditor asks for and it should never be optional.
  • The expense account and full dimensions are per line, not per bill. A single invoice legitimately hits four departments.
  • Default coding is suggested from history — this vendor's last bills — and the suggestion is visibly a suggestion, with the confidence and the basis shown.
  • Early-payment discounts are surfaced as a decision. "Pay by 12 Oct to save $240 (2%)" with the annualized return, because 2/10 net 30 is a ~37% annualized return and finance teams miss it constantly.

4. Approval

type ApprovalPolicy = {
  thresholds: { upTo: Money; approvers: Role[]; requireAll: boolean }[];
  requireSeparateApprover: true;   // preparer ≠ approver. Never configurable to false.
  dimensionApprovers?: Record<string, Role>;   // department owner must approve their spend
  delegations: { from: string; to: string; until: Date }[];
};

UI rules:

  • Segregation of duties is enforced, not advisory. The person who created a bill cannot approve it. This is not a setting.
  • The approval chain is visible before submission — who has to approve, in what order, and what's already done. An approval that disappears into a queue with no visibility is the reason AP teams chase people on Slack.
  • Threshold escalation is shown at entry. "Bills over $10,000 require CFO approval" appears while typing the amount, not after submitting.
  • Delegation has an expiry. Permanent delegation is a control failure and the UI requires an end date.
  • Rejection requires a reason and routes back to the preparer with it visible.
  • Approval is on a specific version. If a bill is edited after approval, approvals are voided and re-requested — with the change shown. Silent post-approval editing is a fraud vector.

5. Payment runs

type PaymentRun = {
  runDate: Date;
  paymentDate: Date;
  method: "ach" | "wire" | "check" | "card" | "rtp";
  bills: string[];
  totalAmount: Money;
  fundingAccount: string;
  status: "draft" | "approved" | "submitted" | "settled" | "partially-failed";
};

UI rules:

  • The run is previewed in full before submission: vendor, amount, method, bank details, and the resulting cash balance after the run. The most important number is the cash left afterwards — a payment run that overdraws is a very expensive UI failure.
  • Bank detail changes are the highest-risk event in AP. A vendor bank change within N days of a payment is flagged, requires re-verification through an out-of-band channel, and is displayed prominently in the run preview. This is how vendor-impersonation fraud works and the UI is the last line of defense.
  • Payment runs use HoldToConfirm. They are irreversible movements of money, often large.
  • Partial failures are a first-class state. A run where 40 of 42 payments settled is not "failed"; the UI shows exactly which two and what to do.
  • Positive pay files and check numbering are tracked; voided checks are recorded, never deleted.
  • Cash requirements forecast — what's due in the next 7/14/30 days versus available cash — is the view AP managers actually plan from.

6. Vendor master

type Vendor = {
  id: string; name: string; legalName: string;
  taxId?: string;                    // W-9 / TIN
  form1099?: { required: boolean; box: string };
  bankDetails: BankDetail[];         // versioned, never overwritten
  defaultTerms: PaymentTerms;
  defaultAccount?: string;
  currency: string;
  status: "active" | "on-hold" | "inactive";
  approvedBy?: string;               // vendor onboarding is itself an approval
};

UI rules:

  • Bank details are versioned, never overwritten. The history — who changed them, when, and what verification was performed — is the audit trail that matters most in AP.
  • Vendor onboarding requires approval and is separate from bill entry. Whoever can create a vendor should not be able to pay one.
  • 1099 tracking flags missing W-9s before year-end, when it's still fixable. The Form 1099-NEC / 1099-MISC threshold is $600 for payments made through 2025 and $2,000 for payments made from 1 January 2026 (One Big Beautiful Bill Act, indexed for inflation from 2027) — the threshold is a dated table, not a constant. Payments by card or a third-party network are reported by the processor on Form 1099-K, not by the payer. A payee who will not provide a TIN triggers 24% backup withholding.
  • Duplicate vendor detection on name similarity and tax ID — duplicate vendors are how duplicate payments survive duplicate-invoice checks.
  • Sanctions/OFAC screening status is displayed where the integration exists. Paying a sanctioned entity is a legal event, not an accounting one.

7. Expense management

Employee-initiated spend. Same control model, different ergonomics — it's mobile-first, because receipts are photographed on phones.

UI rules:

  • Receipt capture is camera-first, with OCR pre-filling amount, date, and merchant — all shown as editable suggestions with the extracted value visible next to the image.
  • Policy violations are shown at entry, not at approval. "Meals over $75 require a business purpose" appears while typing, so the fix is cheap.
  • Corporate card transactions are matched to receipts, not re-entered. The unmatched-receipt and unmatched-transaction queues are both first-class.
  • Personal vs. reimbursable vs. corporate-card-paid are three different settlement paths and the UI never guesses.
  • Mileage and per diem use rate tables with effective dates — the rate that applied on the trip date, not today's.

8. Accruals from AP

At period end, goods and services received but not invoiced must be accrued. This is the bridge from AP to the close.

The GR/IR (goods received / invoice received) clearing account holds the gap:

  Receipt:  Dr Inventory/Expense  / Cr GR-IR clearing
  Invoice:  Dr GR-IR clearing     / Cr Accounts payable
  Balance in GR-IR = received not yet invoiced = the accrual

UI rules:

  • The GR/IR balance is a schedule that must be aged and cleared. Old balances mean either a missing invoice or a receipt that never happened, and both are findings.
  • UninvoicedReceiptsReport drives the period-end accrual entry — it is the evidence for it.
  • Open POs at period end are not accrued. Only significant unconditional or noncancelable purchase obligations are disclosed (ASC 440), and a loss on a firm commitment is accrued. Different treatment, and the UI must not conflate them.

9. AP metrics

Metric Formula Watch out
DPO (AP ÷ COGS) × days in period Higher isn't automatically better — it may mean you're late, not efficient
CCC DSO + DIO − DPO The working-capital cycle in days
On-time payment rate Bills paid by due date ÷ bills paid Vendor relationship health
Early-discount capture Discounts taken ÷ discounts available Usually shockingly low; high-ROI to fix
Invoice cycle time Receipt → approval → payment, in days Where the bottleneck is
Cost per invoice Processing cost ÷ invoice count The automation business case
Duplicate rate Duplicates caught ÷ invoices The control's effectiveness

DPO is the metric most likely to be misread. Rising DPO looks like improved cash management and may be deteriorating vendor relationships. Lopifi renders it with the on-time payment rate adjacent, always — one number without the other is misleading.


10. AP component set

Component Purpose
BillForm Entry with duplicate detection, line coding, and dimension capture
BillDetail Full bill with the source document, match, approvals, and audit trail
BillRegister All bills, filterable, with aging
ThreeWayMatch PO / receipt / invoice side by side, line-level variances
MatchExceptionQueue The clerk's worklist
ApprovalChain Who, in what order, what's done, what's blocking
ApprovalInbox The approver's queue, mobile-first, with the document inline
PaymentRunBuilder Select bills, preview, show the resulting cash balance
PaymentRunPreview Final confirmation with hold-to-confirm
CashRequirements Due in 7/14/30 days vs. available cash
VendorMaster With versioned bank details and change history
BankDetailChangeAlert The fraud-prevention surface
ExpenseCapture Camera-first, OCR-assisted, mobile
CardTransactionMatch Corporate card ↔ receipt matching
UninvoicedReceiptsReport GR/IR aging, drives the accrual
AgingTable AP aging, tied to the control account

Built against this document

The surfaces that implement what this argues — running, computing, or shaped by it.

Told when this spec changes

The docs are the contract the components are built against. When one changes, the component changes with it — and the copy in your repo does not. One email when that happens.

One address, no list rental, unsubscribe in one click.

Works in your QuickBooks Online or Xero file

Get your books closed every month

Lopifi is building AI bookkeeping that keeps your books closed on US GAAP as transactions happen, with a CPA review every quarter, for $200 a month. We’re not open yet.

$200/month when we open. No card now.