
Accounts Payable Management
- 188 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Manage vendor invoices, payment schedules, and accounts payable workflows for ecommerce merchants so cash outflows stay accurate, auditable, and tied to purchase and fulfillment operations.
About
Ecommerce-focused accounts payable skill from awesome-ecommerce-skills for operating merchant finance. Covers vendor bill handling, payment timing, audit trails, and payable controls integrated with storefront, marketplace, and supplier workflows after go-live.
- Structures vendor invoice intake and approval
- Aligns AP with purchase orders and inventory costs
- Supports reconciliation for multi-channel sellers
- Reduces payment errors and duplicate vendor payouts
Accounts Payable Management by the numbers
- 188 all-time installs (skills.sh)
- Ranked #490 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill accounts-payable-managementAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 188 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Manage vendor invoices, payment schedules, and accounts payable workflows for ecommerce merchants so cash outflows stay accurate, auditable, and tied to purchase and fulfillment operations.
Files
Accounts Payable Management
Overview
Accounts payable (AP) management covers ingesting supplier invoices, matching them against purchase orders and goods receipts, scheduling payments, capturing early-payment discounts, and reconciling against the vendor ledger. For most e-commerce merchants, a dedicated AP tool or accounting software integration handles this far better than custom code.
When to Use This Skill
- When your AP team is manually keying invoices from PDFs into spreadsheets and payment delays are causing vendor friction
- When you need automated three-way matching between purchase orders, goods receipts, and invoices
- When early-payment discounts (e.g., 2/10 net 30) are being missed because payment scheduling is reactive
- When preparing for an ERP integration (NetSuite, SAP, QuickBooks) and need a clean AP data model
- When audit requirements demand an immutable record of every invoice approval, payment authorization, and GL posting
Core Instructions
Step 1: Determine your current setup and choose the right AP tool
| Store Stage | Recommended Tool | Why |
|---|---|---|
| Small (< $1M revenue) | QuickBooks Online or Xero | Both handle AP with supplier invoices, payment scheduling, and bank reconciliation; integrate with Shopify/WooCommerce via native connectors |
| Mid-market ($1M–$20M) | BILL (formerly Bill.com) or Tipalti | BILL handles invoice capture via email, approval workflows, ACH/check payments, and vendor portals; Tipalti adds mass global payments |
| Enterprise ($20M+) | NetSuite ERP or SAP Business One | Full ERP with three-way matching, GL coding, and multi-entity consolidation |
| Custom / Headless | Build an AP data model + integrate with Stripe Treasury or Plaid for payments | For platforms with non-standard procurement workflows |
Step 2: Connect your e-commerce platform to your AP system
Shopify
Connect Shopify to QuickBooks Online: 1. Install QuickBooks Online connector from the Shopify App Store (free, by Intuit) or use A2X (paid, more reliable for high-volume) 2. The connector syncs Shopify sales, refunds, and payouts to QuickBooks automatically 3. In QuickBooks → Expenses → Vendors, manage your supplier invoices and payment schedules 4. Enter vendor invoices manually in QuickBooks or forward supplier invoices to your QuickBooks inbox email (QuickBooks extracts invoice data via OCR)
Connect Shopify to BILL: 1. Install BILL from the Shopify App Store or connect via Zapier 2. BILL receives supplier invoices via email (forward to your BILL inbox address) 3. BILL extracts invoice data, routes for approval based on your rules, and schedules ACH or check payments 4. For Shopify inventory vendors: create purchase orders in BILL and match incoming invoices against them
WooCommerce
Connect WooCommerce to QuickBooks: 1. Install the QuickBooks Online plugin from WooCommerce.com (official extension) 2. Configure sync settings: sales orders, refunds, and fees sync automatically 3. Manage supplier invoices in QuickBooks → Expenses
Connect WooCommerce to Xero: 1. Install Xero from WooCommerce.com or use a third-party connector like WooSync or Xero for WooCommerce by Codisto 2. Xero handles AP with a built-in bills module, payment approvals, and bank reconciliation
BigCommerce
Connect BigCommerce to QuickBooks: 1. Use QuickBooks Online connector from the BigCommerce App Marketplace or A2X Accounting 2. A2X is specifically designed for e-commerce accounting and handles Shopify/WooCommerce/BigCommerce → QuickBooks sync accurately
Connect BigCommerce to NetSuite: 1. Use the NetSuite Connector from the BigCommerce App Marketplace or a middleware like Celigo or Boomi 2. NetSuite provides enterprise AP with full three-way matching, multi-entity support, and audit trails
Step 3: Set up invoice capture and approval workflows
Using BILL (best-in-class dedicated AP tool)
1. Invoice capture: Forward supplier invoices to your BILL inbox email or have suppliers submit directly via a BILL supplier portal link 2. AP inbox in BILL: Review captured invoices at BILL → Payables → Inbox; BILL's OCR extracts vendor name, invoice number, date, amount, and due date 3. Approval routing: Go to BILL → Settings → Approval Policies to configure amount-based routing:
- Under $500: auto-approve
- $500–$5,000: AP Manager approval
- $5,000–$50,000: Controller approval
- Over $50,000: CFO approval
4. Approvers receive an email with a one-click approve/reject link 5. Payment scheduling: BILL schedules payments based on vendor due dates; you can also set to pay X days before due date to capture 2/10 early discounts
Using QuickBooks Online for smaller operations
1. Go to Expenses → Vendors → [Vendor] → New Transaction → Bill 2. Enter invoice details manually or forward the invoice PDF to your QuickBooks inbox email 3. Set the due date based on vendor terms (e.g., net 30) 4. To pay: go to Expenses → Pay Bills, select invoices due, choose payment method (bank transfer, check) 5. QuickBooks tracks outstanding AP and generates an aging report (Reports → Accounts Payable Aging)
Step 4: Implement three-way matching
Three-way matching compares: the purchase order (what you ordered), the goods receipt (what you received), and the vendor invoice (what the vendor is charging).
In NetSuite:
- NetSuite handles three-way matching natively — create a PO, receive the goods (Inventory → Receive Inventory), then match the vendor bill against both; discrepancies auto-flag as exceptions
In QuickBooks:
- QuickBooks does not do three-way matching automatically
- Workflow: create a PO in QuickBooks (Expenses → Purchase Orders), receive the items in inventory, then match the bill to the PO manually
- Third-party add-on: Zahara or Lightyear add PO matching and approval automation on top of QuickBooks
In BILL:
- BILL supports PO matching — create POs in BILL, then when an invoice arrives, BILL prompts you to match it against an open PO
Step 5: Capture early-payment discounts
Common vendor terms are "2/10 net 30" — 2% discount if paid within 10 days, full amount due in 30.
In BILL: 1. In your vendor record, set payment terms to "2/10 Net 30" 2. BILL automatically flags invoices where early payment would save money 3. Go to BILL → Payables → Early Pay to see all discount opportunities sorted by savings amount
In QuickBooks: 1. When entering a vendor bill, set the payment terms to "2/10 Net 30" 2. QuickBooks calculates the discount amount automatically 3. When paying: select the bill and QuickBooks shows the discount available if paid today
Key rule: Set a weekly payment run on a fixed day (e.g., every Tuesday). Pay all invoices due in the next 10 days. This captures early discounts systematically without manual review.
Step 6: Reconcile and report
AP aging report
Run monthly to see all outstanding payables by age:
- QuickBooks: Reports → Accounts Payable Aging Summary
- BILL: Reports → AP Aging
- Xero: Reports → Aged Payables Summary
This shows you what's current, 30–60 days, 60–90 days, and 90+ days overdue.
Cash flow forecast
- QuickBooks: Reports → Cash Flow Forecast (shows projected outflows based on bill due dates)
- Float (add-on for QuickBooks/Xero): provides a more accurate 90-day cash flow forecast including AP obligations
Custom / Headless — core AP data model
// Minimal AP invoice schema for custom implementations
interface ApInvoice {
id: string;
vendorId: string;
invoiceNumber: string; // unique per vendor
invoiceDate: Date;
dueDate: Date;
currency: string; // 'USD'
totalCents: number;
paidCents: number; // increments as payments are applied
status: 'received' | 'pending_approval' | 'approved' | 'scheduled' | 'paid' | 'disputed';
poId?: string; // linked purchase order for matching
earlyDiscountRate?: number; // e.g., 0.02 for 2%
earlyDiscountDeadline?: Date;
}
// Identify invoices where early payment saves money
function findEarlyPaymentOpportunities(
invoices: ApInvoice[],
todayDate: Date
): { invoiceId: string; discountCents: number; deadline: Date }[] {
return invoices
.filter(inv => inv.status === 'approved')
.filter(inv => inv.earlyDiscountRate && inv.earlyDiscountDeadline! > todayDate)
.map(inv => ({
invoiceId: inv.id,
discountCents: Math.round(inv.totalCents * inv.earlyDiscountRate!),
deadline: inv.earlyDiscountDeadline!,
}))
.sort((a, b) => b.discountCents - a.discountCents);
}Best Practices
- Separate invoice approval from payment authorization — the person who approves an invoice should not be the person who initiates the payment; this is a basic internal control
- Run payment runs on a fixed weekly cadence — predictable payment dates reduce bank fees, simplify cash forecasting, and vendors learn to expect payment on those days
- Store original invoice PDFs for 7 years — attach the PDF to every bill in QuickBooks/BILL; required for tax audits and vendor disputes
- Send remittance advice — when paying multiple invoices in one ACH batch, email the vendor a list of which invoices were paid and for what amounts so they can reconcile their AR
- Lock invoice amounts after approval — never edit a bill's total after it's been approved; create a credit memo or debit memo for adjustments instead
Common Pitfalls
| Problem | Solution |
|---|---|
| Duplicate invoice payments | QuickBooks and BILL both alert on duplicate invoice numbers per vendor — enable these warnings and require staff to acknowledge them before saving |
| Early discount window missed because invoice sat in approval queue | Add a "discount deadline" badge in your approval tool; BILL shows this prominently; set escalation reminders 2 days before the discount expires |
| AP aging report shows negative balances | Vendor credits and credit memos can create negative balances; ensure credits are applied against open invoices as part of your payment run |
| Vendor disputes payment amount | Always store the PO, goods receipt, and invoice together with your matching result; this is your paper trail for disputes |
Related Skills
- @vendor-management
- @order-management-system
- @returns-refund-policy
{
"context": "Tests whether the agent designs the AP database schema using the correct conventions: monetary amounts in cents as BIGINT, UUID primary keys with gen_random_uuid(), correct status enumerations via CHECK constraints, proper unique constraints and partial indexes, credit memo type support, and the correct set of tables with their relationships.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Cents storage",
"max_score": 12,
"description": "All monetary amount columns use BIGINT (not DECIMAL/NUMERIC/FLOAT) and are named with a _cents suffix (e.g., total_cents, subtotal_cents, paid_cents, amount_cents)"
},
{
"name": "UUID primary keys",
"max_score": 8,
"description": "Primary key columns use UUID type with gen_random_uuid() as the default value"
},
{
"name": "Invoice status enum",
"max_score": 10,
"description": "The invoice status column uses a CHECK constraint containing all of: 'received', 'processing', 'pending_approval', 'approved', 'scheduled', 'paid', 'disputed', 'void'"
},
{
"name": "Match status enum",
"max_score": 8,
"description": "A match_status column exists with a CHECK constraint containing all of: 'unmatched', 'partial', 'matched', 'exception'"
},
{
"name": "Payment method enum",
"max_score": 6,
"description": "A payment_method column uses a CHECK constraint containing at least: 'ach', 'wire', 'check', 'card'"
},
{
"name": "Payment status enum",
"max_score": 6,
"description": "A payments table status column uses a CHECK constraint containing at least: 'pending', 'submitted', 'cleared', 'returned', 'cancelled'"
},
{
"name": "Payment run status enum",
"max_score": 6,
"description": "A payment_runs table status column uses a CHECK constraint containing at least: 'draft', 'approved', 'submitted', 'completed'"
},
{
"name": "Duplicate invoice constraint",
"max_score": 10,
"description": "A UNIQUE constraint exists on (vendor_id, invoice_number) to prevent duplicate invoice entries"
},
{
"name": "Due-date partial index",
"max_score": 8,
"description": "A partial index exists on (due_date, status) with a WHERE clause filtering to status values 'approved' and/or 'scheduled'"
},
{
"name": "Vendor balance partial index",
"max_score": 8,
"description": "A partial index exists on (vendor_id, status) with a WHERE clause excluding 'paid' and 'void' statuses"
},
{
"name": "Credit memo support",
"max_score": 10,
"description": "A 'type' column exists on the invoices table with values including 'invoice' and 'credit_memo' (credit memos use negative amounts to offset open balances)"
},
{
"name": "Discount cents column",
"max_score": 8,
"description": "The payments table includes a discount_cents column (BIGINT) separate from the payment amount"
}
]
}
AP Database Schema for Multi-Entity Finance Platform
Problem/Feature Description
A mid-size manufacturing company is retiring their legacy spreadsheet-based accounts payable process and migrating to a new in-house finance platform. The AP team processes hundreds of supplier invoices each month across three legal entities, each with its own bank account and chart of accounts. They need a solid PostgreSQL database schema that can support the full invoice lifecycle — from receipt through three-way matching, approval, payment scheduling, and eventual archival.
The finance controller has flagged several recurring pain points with the old system: duplicate payments from the same invoice being entered twice by different AP clerks, inability to track whether invoices were matched against purchase orders and goods receipts, no way to distinguish regular supplier invoices from credit memos (which were causing mysteriously negative balances in aging reports), and slow queries when generating monthly AP aging reports for vendors with hundreds of open invoices. The new schema must be designed to prevent these issues structurally, not just through application logic.
Output Specification
Write a single SQL file named ap_schema.sql containing the complete DDL for the accounts payable tables. The file should include all tables, constraints, and indexes needed for a production-ready AP system. Add brief comments to explain non-obvious design decisions.
Do not include application code — only SQL DDL statements.
{
"context": "Tests whether the agent implements the payment run module following skill conventions: 10-day discount look-ahead horizon, sorting by discount value descending, inclusion of discount-eligible invoices alongside due invoices, separate discount_cents on payment records, atomic transaction for payment run creation, approved-only invoice selection, weekly cadence recommendation, remittance advice to vendors, segregation of duties, and bank account change verification.",
"type": "weighted_checklist",
"checklist": [
{
"name": "10-day discount horizon",
"max_score": 8,
"description": "Early payment opportunity lookup uses a 10-day look-ahead window (not 7, not 14) when filtering invoices with expiring discounts"
},
{
"name": "Discount sort order",
"max_score": 7,
"description": "Discount opportunities are sorted by discount value descending (highest savings first, not by deadline or invoice date)"
},
{
"name": "Discount invoices included",
"max_score": 9,
"description": "Payment run includes both (a) invoices due by run date AND (b) invoices with expiring discounts not yet at due date, merged without duplicates"
},
{
"name": "Approved-only filter",
"max_score": 9,
"description": "Payment run query filters for invoices with status='approved' only — does NOT include invoices in 'processing', 'pending_approval', 'disputed', or other non-approved states"
},
{
"name": "Discount cents separated",
"max_score": 8,
"description": "Each payment record stores discount_cents separately from the net amount_cents (discount is not simply subtracted without being recorded)"
},
{
"name": "Atomic transaction",
"max_score": 10,
"description": "Payment run creation (run record + payment records + invoice status updates to 'scheduled') executes inside a single database transaction"
},
{
"name": "Vendor discount fields",
"max_score": 8,
"description": "Discount rate and discount window days are read from vendor record fields (e.g., early_discount_rate, early_discount_days) rather than parsed from invoice notes or terms text"
},
{
"name": "Segregation of duties",
"max_score": 9,
"description": "Design notes or code comments explicitly state that the invoice approver and payment run initiator must be different roles/users; OR the code enforces this check programmatically"
},
{
"name": "Bank change verification",
"max_score": 8,
"description": "Invoices from vendors whose bank account was changed recently (within ~7 days) are flagged for manual verification and excluded from the automated payment batch"
},
{
"name": "Remittance advice sent",
"max_score": 8,
"description": "The vendor notification function sends a remittance listing each invoice number and the amount paid, not just a generic payment confirmation"
},
{
"name": "Weekly cadence mentioned",
"max_score": 8,
"description": "Design notes or code comments recommend or implement a fixed weekly payment cadence (not ad-hoc or daily runs)"
},
{
"name": "Discount window expiry check",
"max_score": 8,
"description": "Discount opportunities skip invoices where the discount deadline has already passed (discountDeadline < today is excluded)"
}
]
}
Weekly Payment Run Automation with Discount Capture
Problem/Feature Description
A regional retail chain runs weekly payments to its 150+ active suppliers. The treasury team currently picks invoices manually each Friday, misses early-payment discounts worth tens of thousands of dollars annually, and occasionally sends payments to vendors whose bank accounts have recently changed — leading to returned ACH transactions. The CFO wants a TypeScript module that automates the weekly payment run: gather approved invoices that are due, layer in any invoices with expiring early-payment discounts, apply the discounts to the payment amounts, execute everything atomically, and notify vendors of what was paid.
The approval workflow is already in place and enforces a strict rule: whoever approves an invoice must not be the same person who kicks off the payment run. The system needs to support this separation. Additionally, to reduce fraud risk, any invoice from a vendor whose bank account details have changed recently must be held for manual verification rather than included automatically in the payment batch.
Output Specification
Write a TypeScript file named payment_run.ts that implements the following:
getEarlyPaymentOpportunities(): Promise<DiscountOpportunity[]>— returns approved invoices eligible for early-payment discount, within the correct look-ahead window, sorted appropriatelybuildPaymentRun(options: PaymentRunOptions): Promise<string>— selects which invoices to pay (due invoices + discount-eligible invoices), applies discounts, creates the run and payment records atomically, and transitions invoice statusesnotifyVendorsOfPayment(runId: string): Promise<void>— sends remittance communication to vendors being paid in this run
Include TypeScript interfaces for all data shapes. Add a brief DESIGN_NOTES.md file (max 1 page) explaining the key design decisions made, including how segregation of duties is enforced and how the bank account change risk is handled.
{
"context": "Tests whether the agent implements invoice ingestion and three-way matching following the skill's specific conventions: filtering attachment types, vendor resolution with fallback to manual review, due date calculation from net-day terms, 1% matching tolerance, correct exception logic, match status derivation rules, currency preservation, and invoice locking after approval.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Attachment type filter",
"max_score": 7,
"description": "Email ingestion only processes attachments with content types in: application/pdf, image/png, image/jpeg (skips all others)"
},
{
"name": "Vendor resolution with fallback",
"max_score": 8,
"description": "Vendor lookup uses BOTH email sender domain AND extracted vendor name; unknown vendors are flagged for manual review and the email is skipped (not thrown as an error)"
},
{
"name": "Due date from net terms",
"max_score": 8,
"description": "Due date is calculated by parsing vendor payment terms as 'net{N}' (e.g., 'net30' → 30 days), with a default of 30 days when terms don't match"
},
{
"name": "Original currency preserved",
"max_score": 9,
"description": "Invoice is saved with the extracted original currency (e.g., EUR, GBP) rather than converting to USD on ingest"
},
{
"name": "No-PO exception",
"max_score": 7,
"description": "Three-way match returns exception status immediately when no PO is linked to the invoice"
},
{
"name": "1% tolerance applied",
"max_score": 10,
"description": "Invoice-to-PO total comparison uses a tolerance of 1% of the PO cost (not hard equality) — variances within 1% do NOT generate an exception"
},
{
"name": "Line-level quantity check",
"max_score": 8,
"description": "Match logic checks that quantity_received (from goods receipt) is not less than invoice line quantity for each matched line"
},
{
"name": "Line-level price check",
"max_score": 8,
"description": "Match logic checks for unit price mismatches between invoice lines and corresponding PO lines"
},
{
"name": "No-receipt exception",
"max_score": 7,
"description": "When no goods receipt is linked to the invoice, an exception is added (e.g., 'No goods receipt on file') rather than silently passing"
},
{
"name": "Match status derivation",
"max_score": 9,
"description": "Final match_status is derived as: 'matched' when no exceptions, 'partial' when exceptions exist but variance is 0, 'exception' otherwise"
},
{
"name": "Invoice lock enforcement",
"max_score": 9,
"description": "The lock function prevents modifications to total_cents, due_date, and vendor_id after an invoice reaches 'approved' status (throws or rejects edit attempts on these fields)"
},
{
"name": "AP event logging",
"max_score": 10,
"description": "The three-way match result is logged using logApEvent (or equivalent audit trail call) with the match status, variance, and exceptions"
}
]
}
Invoice Ingestion and Three-Way Matching Engine
Problem/Feature Description
A wholesale distributor has just gone live with a new procurement system that generates structured purchase orders and goods receipt records. Their AP team is drowning in PDF invoices arriving via email from over 200 active vendors. They need a TypeScript module that can automatically ingest invoices from an email inbox, match them against the corresponding purchase orders and goods receipts, and flag discrepancies for human review — all without requiring the AP clerks to manually key in data or hunt down receipts.
The operations manager has identified a few tricky edge cases from their old system: vendors occasionally send invoices in EUR or GBP rather than USD, and in the past the team would convert to USD before saving — leading to reconciliation headaches when the conversion rate changed. Some vendors also send invoices with slightly different unit prices than the PO (e.g., a $10,001 invoice on a $10,000 PO due to rounding) that shouldn't block payment. The matching logic needs to be robust: it should compare quantities received against invoice quantities line-by-line, check for unit price consistency against the PO, and produce clear exception messages when something doesn't match. Once an invoice is approved, the record should be considered immutable — any correction must go through a formal void-and-reissue process rather than allowing quiet edits.
Output Specification
Write a TypeScript file named ap_matching.ts that implements the following functions. You do not need a working runtime — write the logic clearly enough that a reviewer can assess correctness.
ingestInvoiceFromEmail(email: EmailMessage): Promise<void>— extracts invoice data from PDF/image attachments, resolves the vendor by email domain or extracted vendor name, flags unknown vendors for manual review, and persists the invoice with the correct due date computed from the vendor's payment termsperformThreeWayMatch(invoiceId: string): Promise<MatchResult>— matches an invoice against its PO and goods receipt, applying appropriate tolerance logic, and returns a structured result with status and exception listlockInvoiceAfterApproval(invoiceId: string): Promise<void>— enforces immutability of key invoice fields post-approval
Include TypeScript interfaces for all relevant data shapes. Add inline comments explaining any non-obvious decisions in the matching logic.
{
"name": "finsi/accounts-payable-management",
"version": "0.1.0",
"summary": "Manage supplier invoices and vendor payments with automated receipt matching, payment scheduling, early discount optimization, and reconciliation workflows",
"skills": {
"accounts-payable-management": {
"path": "SKILL.md"
}
}
}