.dev

How Feeef finance moves money

Wallets, courier cash-in, order collection, payouts, and the purchase that becomes both stock and a bill.

FeeefFeeef engineering

A COD business has two moments that look like "we got paid" and are not the same moment. The customer paid the courier. Later the courier paid you, in a lump, minus fees, for a pile of parcels. If you book both as one kind of income, the wallet lies.

Finance on Feeef is a ledger under /v1/finance, scoped to the same project as inventory. The finance guide lists every route. This is the shape of the money.

One tape

Every cash movement is a transfer. The type is one of:

capital, expense, other_in, other_out, sale_collect, courier_remittance, bill_payment, person_payment, withdraw, transfer.

A wallet is a financial account (/v1/finance/financial-accounts) — cash, bank, or an e-wallet — with a computed balance. fromAccountId or toAccountId empty means the money entered or left the project. Both set means it moved between wallets.

You do not edit a posted row. POST /v1/finance/transfers/{id}/void drops it from balances. Write a new row if the amount was wrong.

The merchant app's Activity tab is this tape. Overview (GET /v1/finance/reports/overview) and profit and loss (GET /v1/finance/reports/pnl, cash basis, optional groupBy=day) read it. Reports are cached and drop their cache on a write.

Receive is not Collect

Collect is one order. POST /v1/finance/orders/{orderId}/collect records a customer payment into a wallet and reduces that order's receivable. Receivables themselves are derived from open COD orders — GET /v1/finance/receivables — you do not insert them.

Receive is the courier's lump. POST /v1/finance/payments with projectId, financialAccountId, amount, and a partnerName (the company) writes a courier_remittance. It does not close a list of orders by itself. Delete it with DELETE /v1/finance/payments/{id} if you booked it on the wrong wallet.

Unstructured cash, the kind that is not a sale and not a bill, is POST /v1/finance/wallets/flow with kind: "in" or "out".

Who you pay

Payouts are people and providers: agent, salary, provider, misc_charges. Create with POST /v1/finance/payouts, see what is still owed on GET /v1/finance/payouts/dues, and pay from a wallet with POST /v1/finance/payouts/{id}/settle.

Charges are the operating costs that are not a supplier bill: normal, per_order, or recurring, under /v1/finance/charges. GET /v1/finance/charges/accrual is the windowed view. Expenses and other income still exist as their own resources; posting an expense also lands on the transfer tape (type: "expense"). Prefer the tape for new money-out that is just cash leaving a wallet.

Buying stock is the same ledger

A supplier, a purchase order (draft → sent → partial or received or cancelled), then a receipt. Posting the receipt is the join with inventory:

  • each line becomes a stock bucket, batch stamped with unit_cost
  • each line writes a receive movement
  • an open supplier bill is created for the total

Paying that bill is POST /v1/finance/supplier-bills/{id}/pay from a financial account. Partial payments are allowed. The payment is immutable; void it to undo. Voiding the receipt itself fails if the stock was already reserved or sold, or if the bill has payments you did not also void (voidPayments: true).

An existing batch refuses a different unit cost (BATCH_COST_MISMATCH). That is the costing rule, not a bug. New price, new batch.

A morning that adds up

Open overview for the month. Cash position should equal the wallets. A Yalidine transfer you received yesterday should be a courier payment, not fifty collected orders. A receipt you posted should show up as stock and as an open bill until you pay it. Profit and loss for the same dates should explain the gap between what customers owed and what landed in the wallet.

The general ledger, journals, trial balance, and accounting periods are retired. The routes are off. Cash-basis reports and the transfer tape are the books.

On this page