Payments API
Manage incoming and outgoing payments, including links to clients and installment groups.
Base URL: /api/payments
Authentication & Authorization
All endpoints require a valid session cookie (token). Role-based authorization is enforced server-side.
| Role | GET / | POST / | PUT /:id | DELETE /:id |
|---|---|---|---|---|
| super-admin | ✅ | ✅ | ✅ | ✅ |
| admin | ✅ | ✅ | ✅ | ✅ |
| finance | ✅ | ✅ | ✅ | ✅ |
| agent | ✅ | ✅ | ❌ | ❌ |
| client | ❌* | ❌ | ❌ | ❌ |
*Although the router lists
clientforGET /, the implementation explicitly returns 401 for clients. Treat it as not allowed.
Data Model
Payment (list shape)
Fields returned by GET / (joined across related tables):
{
"id": 123,
"accountType": "Bank",
"serviceType": "installment_payment", // or other service types
"amount": 15000.0,
"paymentType": "income" /* or "expense" */,
"description": "Payment for installment XYZ",
"clientId": 45,
"clientName": "John Smith",
"paymentDate": "2024-07-01T00:00:00.000Z",
"createdBy": "Jane Admin",
"company": "Acme Properties",
"status": "pending" /* "approved" | "declined" */,
"installmentGroupId": 987,
"installmentGroupName": "Project ABC",
"attachments": [
{ "attachment": "/path/or/url/file.pdf", "title": "Receipt" }
],
"assignedAgents": [
{ "agentId": 12 }, { "agentId": 34 }
]
}
Notes
- The list endpoint includes attachments (from
installments_attachments) and assignedAgents (fromclients_agents).- Results are ordered by
paymentDatedescending.
Status semantics
pending: awaiting approval; when created for installment_payment, a notification is broadcast tosuper-adminusers.approved: accepted.declined: if set by PUT /:id, the record is deleted (see update behavior).
Endpoints
GET /
List payments with optional filters.
Auth: admin, finance, agent, super-admin (clients receive 401).
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
query | string | no | Substring match on accountType. |
company | number | no | Company ID to restrict results. If omitted and caller is not super-admin, results are implicitly scoped to the caller’s allowed companies. |
client | number | no | Filter by clientId. |
accountType | string | no | Exact match on accountType. |
status | enum(pending,declined,approved) | no | Filter by payment status. |
Response — 200
[
{
"id": 1,
"accountType": "Bank",
"serviceType": "installment_payment",
"amount": 25000,
"paymentType": "income",
"description": "Payment for installment Project A",
"clientId": 5,
"clientName": "Client Name",
"paymentDate": "2024-06-20T00:00:00.000Z",
"createdBy": "Admin User",
"company": "Company X",
"status": "approved",
"installmentGroupId": 101,
"installmentGroupName": "Project A",
"attachments": [ { "attachment": "https://.../receipt.pdf", "title": "Receipt" } ],
"assignedAgents": [ { "agentId": 12 } ]
}
]
Errors
- 401 when the caller is a client.
POST /
Create a payment. Special handling exists for serviceType = "installment_payment".
Auth: admin, finance, agent (clients receive 401).
Body
{
"accountType": "Bank", // required
"serviceType": "installment_payment", // required
"amount": 15000, // required (number)
"paymentType": "income", // required: "income" | "expense"
"description": "Optional text", // optional; if missing for installment payments, a default description is generated
"clientId": 45, // optional, recommended for client-linked payments
"paymentDate": "2024-07-01", // required; parsed into Date
"company": 3, // required (number)
"installmentGroupId": 987, // required when serviceType = "installment_payment"
"status": "pending", // optional; if "pending" for installment payments, triggers super-admin notification
"associatedEntity": "string-or-null" // optional; affects delete permissions
}
Behavior for serviceType = "installment_payment"
- Validates
installmentGroupIdand resolves its project; returns 404 if not found. - If
statusispending, sends a notification to super-admins containing amount, project, and creator name. - Returns
201with{ message, newPayment }(wherenewPaymentis the DB-returned identifier object).
Behavior for other service types
- Creates a standard payment record and returns
201 { message }.
Errors
- 401 when the caller is a client.
- 400 if
installmentGroupIdis missing for installment payments. - 404 if the referenced installment group does not exist.
- 500 on server/database errors.
Example
curl -X POST \
-H 'Content-Type: application/json' \
--cookie "token=..." \
-d '{
"accountType": "Bank",
"serviceType": "installment_payment",
"amount": 15000,
"paymentType": "income",
"clientId": 45,
"paymentDate": "2025-01-15",
"company": 3,
"installmentGroupId": 987,
"status": "pending"
}' \
https://your.api/api/payments
PUT /:id
Update a payment. Setting status to declined deletes the record instead of updating it.
Auth: admin, finance, super-admin
Body (any subset)
{
"accountType": "Bank",
"serviceType": "installment_payment",
"amount": 20000,
"paymentType": "income",
"description": "Reworded description",
"clientId": 45,
"paymentDate": "2025-02-01",
"status": "approved" // or "declined" (which deletes)
}
Responses
- 200
{ message: "Payments updated successfully" }when updated normally. - If
status = "declined": 200{ message: "Payments deleted successfully" }and the record is removed. - 404 if the payment does not exist.
Errors
- 500 on server/database errors.
DELETE /:id
Delete a payment.
Auth: admin, finance, super-admin
Delete rules
- If
associatedEntityis falsy on the payment and the caller is not super-admin, the server responds:- 400
{ message: "Cannot delete as it belongs to another entity" }
- 400
- Otherwise, the record is deleted.
Responses
- 200
{ message: "Payments deleted successfully" } - 404 if the payment does not exist.
Errors
- 500 on server/database errors.
Notes & Caveats
- Clients cannot list payments even though the router includes
clientforGET /. The controller blocks it with a 401. - The list endpoint joins related data to return
attachmentsandassignedAgentsarrays per payment. - There is an internal
getPaymentsByIdcontroller not currently wired in the router; if exposed, it would return a single raw payment row by ID.
Error Model
Standard JSON error payloads:
{ "message": "..." }
HTTP statuses used: 200, 201, 400, 401, 404, 500.
Changelog
- v1.0: Initial documentation for Payments API (GET list, POST create, PUT update/delete-on-decline, DELETE with associatedEntity rule).