.dev
REST API

Finance

Procurement (suppliers, purchase orders, receipts), supplier bills and payments, COD receivables, cash accounts, expenses and cash-basis reports.

The finance module is a lightweight ERP attached to your stores: procurement, accounts payable, COD receivables, cash accounts and reports. Everything lives under /v1/finance and requires a bearer token.

  • Project-scoped. Every request carries a projectId (query param on reads, body field on writes). A project groups one or more stores (store.projectId) and is shared with inventory; list yours via GET /v1/inventory/projects.
  • Permissions. The store owner can do everything. Members need the finance.read permission for reads and finance.write for writes (enforced per store role). The finance module must also be enabled for the store (billing entitlement).
  • Lists accept page, limit, search and the filterator, and return the standard paginator envelope. Batch endpoints (:batchDelete, :batchPay, …) take { projectId, names, returnPartialSuccess? } and return the partial-success envelope.

Purchase-to-pay flow

Posting a receipt is one transaction with three effects: receipt lines become inventory objects (batch buckets carrying unit_cost in metadata), a reason: "receive" movement is recorded per line, and an open supplier bill is created for the total. Posting is idempotent. Rules that follow from this:

  • Batch-cost invariant — an existing batch only accepts stock-in at the same unitCost; receiving at a different cost fails with BATCH_COST_MISMATCH (use a different batch).
  • Voiding a posted receipt reverses the stock-in. It fails with RECEIPT_REVERSE_BLOCKED if quantity was already reserved or sold, and with BILL_NOT_OPEN if the bill has payments — pass { "voidPayments": true } to void those payments in the same transaction.
  • Purchase orders move through draft, sent, partial, received, cancelled; invalid transitions fail with INVALID_STATE_TRANSITION. Receipts don't require a PO (purchaseOrderId is optional).

At a glance

All endpoints require Bearer auth.

Suppliers

MethodPathDescriptionAuth
GET/v1/finance/suppliersList suppliersBearer
POST/v1/finance/suppliersCreate a supplierBearer
GET/v1/finance/suppliers/{id}Get oneBearer
PUT/v1/finance/suppliers/{id}UpdateBearer
DELETE/v1/finance/suppliers/{id}DeleteBearer
POST/v1/finance/suppliers:batchDeleteDelete manyBearer

Purchase orders

MethodPathDescriptionAuth
GET/v1/finance/purchase-ordersList POsBearer
POST/v1/finance/purchase-ordersCreate (status draft)Bearer
GET/v1/finance/purchase-orders/{id}Get oneBearer
PUT/v1/finance/purchase-orders/{id}Update reference/notes/currency/expectedAt/itemsBearer
POST/v1/finance/purchase-orders/{id}/sendTransition to sentBearer
POST/v1/finance/purchase-orders/{id}/cancelTransition to cancelledBearer
POST/v1/finance/purchase-orders/{id}/statusSet explicit status (state machine enforced)Bearer
POST/v1/finance/purchase-orders:batchSendSend many draftsBearer
POST/v1/finance/purchase-orders:batchCancelCancel manyBearer
GET/v1/finance/purchase-orders/{id}/pdfPDF (returns fileUrl)Bearer
POST/v1/finance/purchase-orders:batchPdfMerged PDF for manyBearer

Purchase receipts

MethodPathDescriptionAuth
GET/v1/finance/purchase-receiptsList receipts (with lines + supplier)Bearer
POST/v1/finance/purchase-receiptsCreate draft receipt with linesBearer
GET/v1/finance/purchase-receipts/{id}Get oneBearer
PUT/v1/finance/purchase-receipts/{id}Update notes/reference/attachments onlyBearer
POST/v1/finance/purchase-receipts/{id}/postPost: stock-in + create bill (idempotent)Bearer
POST/v1/finance/purchase-receipts/{id}/voidVoid a posted receipt (voidPayments optional)Bearer
POST/v1/finance/purchase-receipts:batchPostPost many draftsBearer
POST/v1/finance/purchase-receipts:batchVoidVoid many (always voids payments)Bearer
GET/v1/finance/purchase-receipts/{id}/pdfPDF (returns fileUrl)Bearer
POST/v1/finance/purchase-receipts:batchPdfMerged PDF for manyBearer

Supplier bills & payments (AP)

MethodPathDescriptionAuth
GET/v1/finance/supplier-billsList billsBearer
POST/v1/finance/supplier-billsCreate an ad-hoc bill (not from a receipt)Bearer
GET/v1/finance/supplier-bills/{id}Get one (with payments + receipt lines)Bearer
POST/v1/finance/supplier-bills/{id}/payRecord a (partial) payment — returns bill + paymentBearer
POST/v1/finance/supplier-bills:batchPayPay the full remaining balance on each billBearer
POST/v1/finance/supplier-bills:batchVoidPaymentsVoid all payments on each billBearer
GET/v1/finance/supplier-bills/{id}/pdfPDF (returns fileUrl)Bearer
POST/v1/finance/supplier-bills:batchPdfMerged PDF for manyBearer
GET/v1/finance/supplier-paymentsList payments (supplierBillId filter)Bearer
GET/v1/finance/supplier-payments/{id}Get oneBearer
POST/v1/finance/supplier-payments/{id}/voidVoid a payment, recompute the billBearer

Bills have no update or delete — totals are managed through payments and voids.

Receivables & customer payments (AR)

Receivables are derived from open COD orders — read-only rows keyed by order id.

MethodPathDescriptionAuth
GET/v1/finance/receivablesOpen order receivables (q, codInTransit filters)Bearer
GET/v1/finance/receivables/{orderId}Receivable detail + linked orderBearer
POST/v1/finance/receivables:batchCollectCollect the full balance due on each orderBearer
GET/v1/finance/customer-paymentsList collected payments (orderId filter)Bearer
POST/v1/finance/orders/{orderId}/collectRecord a customer/COD paymentBearer
POST/v1/finance/customer-payments/{id}/voidVoid a customer paymentBearer

Financial accounts & transfers

MethodPathDescriptionAuth
GET/v1/finance/financial-accountsList accounts with computed balancesBearer
POST/v1/finance/financial-accountsCreate (name, type, openingBalance, isDefault)Bearer
GET/v1/finance/financial-accounts/{id}Get one with balanceBearer
PUT/v1/finance/financial-accounts/{id}UpdateBearer
DELETE/v1/finance/financial-accounts/{id}DeleteBearer
POST/v1/finance/financial-accounts:batchDeleteDelete manyBearer
GET/v1/finance/transfersMoney timeline (voided hidden by default)Bearer
POST/v1/finance/transfersRecord money in/out/between accountsBearer
GET/v1/finance/transfers/{id}Get oneBearer
POST/v1/finance/transfers/{id}/voidSoft-void (excluded from balances)Bearer

Expenses & other income

Both follow the same CRUD shape; categories are simple named trees (parentId).

MethodPathDescriptionAuth
GET / POST/v1/finance/expensesList / record expensesBearer
GET / PUT / DELETE/v1/finance/expenses/{id}Get / update (set status: "voided" to void) / deleteBearer
POST/v1/finance/expenses:batchDeleteDelete manyBearer
GET / POST/v1/finance/expense-categoriesList / create categoriesBearer
GET / PUT / DELETE/v1/finance/expense-categories/{id}Get / update / deleteBearer
POST/v1/finance/expense-categories:batchDeleteDelete manyBearer
GET / POST/v1/finance/other-incomesList / record other incomeBearer
GET / PUT / DELETE/v1/finance/other-incomes/{id}Get / update / deleteBearer
POST/v1/finance/other-incomes:batchDeleteDelete manyBearer
GET / POST/v1/finance/other-income-categoriesList / create categoriesBearer
GET / PUT / DELETE/v1/finance/other-income-categories/{id}Get / update / deleteBearer
POST/v1/finance/other-income-categories:batchDeleteDelete manyBearer

Reports & reset

MethodPathDescriptionAuth
GET/v1/finance/reports/overviewConsolidated bundle (from, to)Bearer
GET/v1/finance/reports/cash-positionBalances across financial accountsBearer
GET/v1/finance/reports/ap-agingPayables aging bucketsBearer
GET/v1/finance/reports/ar-agingReceivables aging bucketsBearer
GET/v1/finance/reports/pnlCash-basis P&L (from, to, groupBy=day)Bearer
POST/v1/finance/resetWipe project finance data — owner only, body confirm: "RESET"Bearer

Reports are cached server-side and invalidated on writes.

Examples

Create a supplier:

curl -X POST "https://api.feeef.org/v1/finance/suppliers" \
  -H "Authorization: Bearer $FEEEF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "projectId": "PROJECT_ID", "name": "Atlas Textiles", "paymentTerms": "NET30" }'

Create a purchase order and send it:

curl -X POST "https://api.feeef.org/v1/finance/purchase-orders" \
  -H "Authorization: Bearer $FEEEF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "PROJECT_ID",
    "supplierId": "SUPPLIER_ID",
    "items": [{ "sku": "tshirt/red/m", "qtyOrdered": 50, "unitCost": 950 }]
  }'

curl -X POST "https://api.feeef.org/v1/finance/purchase-orders/PO_ID/send?projectId=PROJECT_ID" \
  -H "Authorization: Bearer $FEEEF_TOKEN"

Receive the goods — create a receipt and post it (stock-in + bill):

curl -X POST "https://api.feeef.org/v1/finance/purchase-receipts" \
  -H "Authorization: Bearer $FEEEF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "PROJECT_ID",
    "supplierId": "SUPPLIER_ID",
    "purchaseOrderId": "PO_ID",
    "lines": [{ "sku": "tshirt/red/m", "qtyReceived": 50, "unitCost": 950, "batch": "B-2026-08" }]
  }'

curl -X POST "https://api.feeef.org/v1/finance/purchase-receipts/RECEIPT_ID/post?projectId=PROJECT_ID" \
  -H "Authorization: Bearer $FEEEF_TOKEN"

Pay the supplier bill from a financial account:

curl -X POST "https://api.feeef.org/v1/finance/supplier-bills/BILL_ID/pay" \
  -H "Authorization: Bearer $FEEEF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "projectId": "PROJECT_ID", "financialAccountId": "ACCOUNT_ID", "amount": 47500 }'

Collect a COD payment against an order:

curl -X POST "https://api.feeef.org/v1/finance/orders/ORDER_ID/collect" \
  -H "Authorization: Bearer $FEEEF_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "projectId": "PROJECT_ID", "financialAccountId": "ACCOUNT_ID", "amount": 3200 }'

Notes

  • PDF endpoints respond with { "fileUrl": "https://…" } — a hosted PDF, not a binary body.
  • POST /v1/finance/expenses is soft-deprecated: it records the expense as a native finance transfer (type: "expense") and returns that transfer row. Prefer /v1/finance/transfers for new integrations.
  • Payments (supplier and customer) are immutable — correct mistakes by voiding, never editing.
  • The general-ledger endpoints (gl-accounts, journal-entries, reports/trial-balance, reports/balance-sheet, accounting-periods) are retired; the routes are disabled even though older SDK builds still expose wrapper methods for them.

On this page