ERP Finance Expense-Control Skill
Environment
All API calls use the shared remote base URL from environment_access.md:
http://34.46.77.124:8005. Never use localhost, 127.0.0.1, or local env scripts.
Available API Endpoints
Every endpoint is available both with and without the /api/ prefix:
| Short Path | Long Path | Returns |
|---|---|---|
/claims |
/api/claims |
Expense claim records (id, status, amount, vendor, submitter, etc.) |
/bills |
/api/ap/bills |
AP bill records (id, claim_id, status, amount, vendor_id, etc.) |
/payments |
/api/ap/payments |
Payment records (id, bill_id, amount, status, cleared_date, etc.) |
/vendors |
/api/vendors |
Vendor master data (id, name, bank info, tax_id, status, etc.) |
/compliance/objects |
/api/compliance/objects |
Compliance records per business/vendor (bank_account_status, pep_flag, sanctions_flag, screening_status, license_expiry, risk_score, ubo records, shell_company_flag, on_hold_flag, tax_id_status, required_docs) |
/prepaids/invoices |
/api/prepaids/invoices |
Prepaid invoice schedules (id, account, original_amount, start_date, term_months, monthly_amortization, cumulative_amortization, default_term_flag, etc.) |
/gl/balances |
/api/prepaids/gl-balances |
GL ending balances by account and period |
/close/logs |
/api/close/logs |
Close log entries (id, period, status, unresolved_items, etc.) |
/health |
— | Health check |
/endpoints |
— | Lists available endpoints |
General Conventions
Currency
- All amounts in USD.
- Two decimal places. Use cents representation where the template says "USD cents"; otherwise report dollar amounts with
.NNprecision. - When summing: sum raw values, then round to 2 decimals.
Sorting
- All ID lists (claim IDs, business IDs, invoice IDs, close-log IDs) must be sorted ascending (lexicographic for strings like
CLM-2025-*,BUS-2025-*,PPD-*). - Invoice result arrays and selected-invoice-ID arrays preserve the input scope order (the order given in the payload).
Source of Truth
- Live API data is authoritative. Provided CSV snapshots, local payloads, or batch manifests are context only. Always cross-reference against current API records.
- If a snapshot says a bill is scheduled but the live API shows it as void, the live status wins.
- If a snapshot says a claim is approved but the live API shows it as pending or rejected, the live status wins.
Enum Values
- Use only the exact allowed values listed in each answer template. Do not invent or abbreviate.
Domain 1: Claims & AP Reimbursement Close (Train 001, 004)
Data Sources
- Claims (
/claims) — claim status, claim amount, vendor, submitter. - AP Bills (
/bills) — bill status, bill amount, bill-to-claim linkage viaclaim_id, vendor_id. - Payments (
/payments) — payment status (cleared,scheduled,none), amount, linkedbill_id. - Close Logs (
/close/logs) — unresolved close entries that may block batch release.
Claim Classification Rules
Paid Claims (paid_claim_ids / similar)
A claim is paid when ALL of:
- The claim exists in
/claimswith statusapproved. - A matching AP bill exists (linked by claim_id) with status
paid. - A payment exists for that bill with status
clearedand amount matching the bill amount.
Payable / Eligible Claims (payable_claim_ids / eligible_claim_ids)
A claim is payable/eligible when ALL of:
- The claim exists in
/claimswith statusapproved. - A matching AP bill exists with status
scheduledorapproved(NOTvoid, NOTpaid). - No blocking issues (see below).
- The bill amount matches the claim amount (within reasonable tolerance).
- The vendor on the bill matches the vendor on the claim.
Blocked / Not-Ready Claims (blocked_claim_ids / not_ready_claim_ids)
A claim is blocked/not-ready when ANY of:
- Claim status is NOT
approved(e.g.,pending,rejected,draft). - The linked AP bill is
void. - The linked AP bill has a vendor mismatch with the claim.
- The linked AP bill has an amount mismatch with the claim.
- Unresolved partial-support or receipt-review flags exist.
- A close log entry for the period is unresolved and relates to the claim.
CRM vs AP Issue Distinction
When populating crm_required_claim_ids:
- CRM required: The issue is with the expense case itself — claim not approved, submitter documentation missing, receipt support under review, expense policy violation.
- AP-only issue: The claim is fine but the AP bill link is broken — void bill, vendor mismatch on bill, stale bill record.
- A claim can appear in both
blocked_claim_idsandcrm_required_claim_ids.
AP Open Balance
ap_open_balance_total: Sum of (bill amount − cleared payment amount) for all payable claims only.- Per-claim
ap_balance_by_claim: For each candidate claim, bill amount minus sum of cleared payments. If no bill exists or bill is void, balance is0.00. If bill is paid and payment cleared, balance is0.00.
Stale Snapshot Corrections (Train 004)
When a stale CSV snapshot is provided alongside live API data, assign one of:
current_snapshot_ok— snapshot matches live state.mark_in_flight_payment— bill is scheduled/approved, payment not yet cleared, snapshot shows none.replace_with_matched_paid_bill— snapshot shows old bill; live API shows a different bill that is paid.exclude_amount_or_vendor_mismatch— bill exists but amount or vendor doesn't match the claim.ignore_void_bill— snapshot bill is now void in live API.block_unapproved_claim— claim is not approved in live API.
Close Log Requirements
- Check
/close/logsfor unresolved entries related to the period under review. - If any unresolved close-log entry exists for the reviewed period, set
close_log_required.required = trueand list the relevant close-log IDs inclose_log_required.ids.
Batch Status (Claims Domain)
ready_to_close— all claims paid (no payable, no blocked).open_payables— at least one payable claim, zero blocked.blocked— at least one blocked claim.ready_to_send— all candidate claims eligible, zero not-ready.needs_ap_refresh— mix of eligible and not-ready, or close-log action needed.blocked— no eligible claims, or hard blocks present.
Domain 2: Vendor Onboarding & Compliance Release (Train 002, 005)
Data Sources
- Vendors (
/vendors) — vendor_id, business_id, bank info (last4), tax_id, license_expiry, status. - Compliance Objects (
/compliance/objects) — per business_id: bank_account_status, pep_flag, sanctions_flag, screening_status, license_expiry, risk_score, ubo records (name + ownership_pct), shell_company_flag, on_hold_flag, tax_id_status, required_documents_status.
Decision Logic
Per-Business Decision (approve / release)
A business can be approved/released when ALL of:
- Bank account status is
verified(noname_mismatch, noclosed). - No PEP flag confirmed.
- No sanctions match confirmed.
- Screening has been run and is clear.
- License is not expired relative to the review/as_of date.
- Tax ID is valid.
- All required documents are present.
- Not flagged as shell company.
- Not on hold.
- Risk score < 70 (or below the applicable override threshold).
- UBO information is complete.
awaiting_information / hold
Use when:
- Some compliance checks are incomplete (screening not run, missing documents) but no hard-stop flags are present.
- Minor issues that can be resolved with additional information.
- Bank mismatch exists but can potentially be corrected.
escalate
Use when ANY hard-stop flag is present:
confirmed_pepsanctions_confirmedshell_company_suspectedvendor_on_holdbank_closed- Multiple severe flags in combination.
- Expired license combined with other flags.
Hard-Stop Flags (Train 002)
Flag values (alphabetical order in output):
bank_closed— compliance bank_account_status isclosed.bank_name_mismatch— compliance bank_account_status isname_mismatch.confirmed_pep— compliance pep_flag is true/confirmed.expired_license— license_expiry date < as_of_date/review_date.missing_required_documents— required_documents_status is incomplete/missing.sanctions_confirmed— compliance sanctions_flag is true/confirmed.screening_not_run— compliance screening_status is not_run/pending.shell_company_suspected— compliance shell_company_flag is true.vendor_on_hold— compliance on_hold_flag is true.
Assign flags per business_id. Use an empty list [] when none apply.
UBO Reporting (Train 002)
- Count unique beneficial owner names (not records) where
ownership_pct>= the reporting threshold (typically 25%). - Report as an integer per business_id in
reportable_ubo_counts.
Account-Change Specific Fields (Train 005)
Bank Mismatch
bank_mismatch_ids: Business IDs where compliancebank_account_statusisname_mismatch.- Also cross-check: if the change ticket's
requested_bank_last4doesn't match the vendor's bank last4 in the compliance record, flag as mismatch.
Invalid Tax IDs
invalid_tax_ids: Business IDs where compliancetax_id_statusisinvalidor equivalent.
Expired Licenses
expired_license_ids: Business IDs wherelicense_expiry<as_of_date(review date). Use theas_of_datefield from the template as the comparison date.
Review Queue
review_queue_ids: Any business_id that has at least one flag, mismatch, invalid tax ID, expired license, or risk_score concern. In other words, every business that is NOT a cleanrelease.
Risk Score Override
risk_score_override_flags: Business IDs where compliancerisk_score >= 70.
Overall Release Ready
overall_release_ready = trueONLY if every listed business has decisionapprove/release.- If any business is
awaiting_information,hold, orescalate, setfalse.
Domain 3: Prepaid Expense Close (Train 003)
Data Sources
- Prepaid Invoices (
/prepaids/invoices) — prepaid_invoice_id, account (chart-of-account code), original_amount, start_date, term_months, monthly_amortization, cumulative_amortization (through current period), default_term_flag. - GL Balances (
/gl/balances) — ending_balance by account and period.
Amortization Model
- Straight-line monthly amortization as represented in the invoice records.
monthly_amortization = original_amount / term_months(already computed in source records).cumulative_amortization_through_march= sum of monthly amortizations fromstart_datethrough the close period (inclusive). The source records provide this pre-computed.
Invoice-Level Fields
For each invoice in the scope (output in scope order):
prepaid_invoice_id: as given.account: chart-of-account code (1250 or 1251).march_amortization: the monthly amortization amount for the close period (March).cumulative_amortization_through_march: total amortization from start through March.ending_balance:original_amount - cumulative_amortization_through_march. Rounded to 2 decimals.default_missing_term_flag:trueif the invoice hasdefault_term_flagset in source data.exception_flag:truewhen:- The invoice has a
default_missing_term_flag. - The ending balance is 0.00 (or very near zero, e.g., 0.01) while the invoice still has remaining term — indicates potential early write-off.
- Any data quality issue (negative balances, mismatched cumulative amortization, etc.).
- The invoice has a
Account-Level Rollup
For each account (1250, 1251):
account_name: from GL or prepaid source (e.g., "Prepaid Expenses" for 1250, "Prepaid Insurance" for 1251).selected_invoice_count: number of scoped invoices for that account.original_amount_total: sum oforiginal_amountacross scoped invoices.march_amortization_total: sum ofmarch_amortizationacross scoped invoices.cumulative_amortization_through_march: sum ofcumulative_amortization_through_marchacross scoped invoices.schedule_ending_balance:original_amount_total - cumulative_amortization_through_march.gl_ending_balance: from/gl/balancesfor that account and period.variance_amount:schedule_ending_balance - gl_ending_balance(can be negative).variance_flag:truewhen|variance_amount| > variance_threshold_abs(typically 100.00 USD).has_default_missing_term_flag:trueif ANY scoped invoice in that account hasdefault_missing_term_flag = true.account_status:reconciled— variance_flag is false AND has_default_missing_term_flag is false.variance_review— variance_flag is true but no default/missing term issues (small or explainable variance).requires_reconciliation— variance_flag is true with other flags, or has_default_missing_term_flag is true, or significant unexplained variance.
Default/Missing Term & Exception Invoice ID Lists
default_missing_term_invoice_ids: All scoped invoice IDs wheredefault_missing_term_flag = true, sorted ascending.exception_invoice_ids: All scoped invoice IDs whereexception_flag = true, sorted ascending.
Cross-Cutting Workflow
API Query Strategy
- Fetch all relevant data in parallel where possible — claims, bills, payments, vendors, compliance objects, prepaid invoices, and GL balances are independent.
- Filter by scope after fetching — the APIs may return more records than needed; filter to the candidate IDs from the task batch.
- Join records by linking keys:
claim_idbetween claims and bills,bill_idbetween bills and payments,business_idbetween vendors and compliance,vendor_idbetween vendors and change tickets.
Common Pitfalls
- Using stale/snapshot data as truth. Always verify against live API. The snapshot is context, not authority.
- Mixing up claim status and bill status. A claim can be
approvedwhile its bill isvoid— this means the claim is blocked, not payable. - Forgetting to deduct cleared payments when computing AP open balances.
- Not distinguishing CRM issues from AP issues. CRM required means the expense case owner must act; AP issues mean the AP team must correct the bill/payment link.
- Incorrect amortization math. Always use
original_amount - cumulative_amortizationfor ending balance, notmonthly * remaining_months(which can drift due to rounding). - Including void/paid bills in open AP balance. Only include scheduled/approved (unpaid) bills.
- Sorting errors. ID lists must be ascending; invoice arrays preserve input order.
- Missing close-log cross-reference. Always check
/close/logsfor unresolved entries that may affect batch release. - Rounding errors. Sum raw values, then round the total to 2 decimals. Don't round intermediate values.
- Enum value typos. Copy enum values exactly from the answer template — they are case-sensitive and must match precisely.
- Overlooking the
overall_release_ready/batch_statusderivation. These are derived fields that must be consistent with the per-item decisions. - Not handling edge cases: zero ending balances, fully amortized invoices with 0.00 or 0.01 remaining, claims with no matching bills, bills with no payments.
Output Validation Checklist
Before finalizing, verify:
- All ID lists are sorted ascending.
- All currency fields have exactly 2 decimal places.
- All required top-level keys are present per the answer template.
- Enum values match the template exactly (case, underscores).
- Derived fields (
batch_status,overall_release_ready,account_status) are consistent with per-item decisions. - Count fields (
reviewed_claim_count,selected_invoice_count,reportable_ubo_counts) are integers. - Invoice result arrays preserve the input scope order.
- No extra keys beyond what the template specifies.