Customers and credit
Search customers, manage credit limits, read the ledger, and record payments that reduce the balance.
You manage customer credit from apps/server/src/features/customers/route.ts. Every read needs authentication, and recording a payment additionally requires one of the admin, branch_manager, pharmacist, or cashier roles.
Find a customer
List customers with GET /customers, paginated with page and page_size (defaults 1 and 20). Pass search to match by name, phone (partial LIKE), or exact national ID. Results sort by name ascending.
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8000/api/v1/customers?search=0772&page=1&page_size=20"
Fetch one record with GET /customers/:customerId. Both money fields (credit_limit, current_balance) return as strings, and is_credit_allowed returns as a boolean.
Create a customer with a credit limit
Create records with POST /customers. You set name (required), plus phone, national_id, notes, credit_limit (number, minimum 0, default 0), and is_credit_allowed (boolean, default false). Leave is_credit_allowed false and the customer pays cash only.
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name":"Sarah Nakimuli","phone":"0772000111","national_id":"CM123456","credit_limit":50000,"is_credit_allowed":true}' \
http://localhost:8000/api/v1/customers
Update later with PUT /customers/:customerId, sending only the fields you want to change. Sending an empty body returns 400 No fields to update.
Read the credit ledger
Each customer carries current_balance, the outstanding amount they owe you. Open the audit trail with GET /customers/:customerId/ledger, newest entries first, paginated at 20 per page. Each row shows transaction_type, amount, balance_after, and created_by_name from the joined users table.
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8000/api/v1/customers/CUSTOMER_ID/ledger
Record a payment against the balance
Take money against what the customer owes with POST /customers/:customerId/payments. The amount must be greater than zero and must not exceed current_balance, or you get a 400 naming both figures. The handler runs in a transaction: it decrements the balance, inserts a PAYMENT row into customer_ledger with the new balance_after, and emits sync changes for both rows.
curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"amount":15000,"notes":"Cash received at counter"}' \
http://localhost:8000/api/v1/customers/CUSTOMER_ID/payments
The response returns ledger_id, amount_paid, previous_balance, and new_balance so you can print a receipt for the exact payment.