---
title: Customers and credit
description: 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.

```bash
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.

```bash
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.

```bash
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.

```bash
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.

### Next steps

**[Suppliers and finance](/operations/suppliers-and-finance)**

Mirror the flow on the supplier side with invoices and reorder suggestions.

**[Reports and dashboard](/operations/reports-and-dashboard)**

Watch revenue and per-pharmacist sales to spot collection problems early.
