Appearance
Invoices API
Base route: /api/invoices
Auth required: ✅ JWT Bearer
Invoice Status Logic
Invoice status is computed — never stored in the database:
| Priority | Status | Condition |
|---|---|---|
| 1 | Canceled | isActive == false |
| 2 | FullyPaid | pendingAmount <= 0 |
| 3 | Overdue | dueDate.Date < today |
| 4 | PartiallyPaid | All other cases |
GET /api/invoices
Returns a paginated, filtered list of invoices with computed financial fields.
Permission: Invoice:Read
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | int | 1 | Page number (1-based) |
pageSize | int | 15 | Items per page (max 100) |
sortBy | string | invoiceDate | Sort field: invoiceDate | dueDate | amount | pendingAmount | paidAmount | invoiceNumber | vendorName |
sortDir | string | desc | asc | desc |
status | string | — | Filter by computed status: FullyPaid | PartiallyPaid | Overdue | Canceled |
search | string | — | Substring match on invoice number or vendor name |
vendorId | int | — | Return invoices for this vendor only |
invoiceNumber | string | — | Substring match on invoice number only |
fromDate | datetime | — | Inclusive lower bound on invoiceDate (ISO 8601) |
toDate | datetime | — | Inclusive upper bound on invoiceDate (ISO 8601) |
minAmount | decimal | — | Minimum invoice amount (inclusive) |
maxAmount | decimal | — | Maximum invoice amount (inclusive) |
isActive | bool | — | true = active, false = canceled. Omit to return all |
Response — List 200 OK
json
{
"items": [
{
"id": 101,
"vendorId": 1,
"vendorName": "ABC Pharmaceuticals",
"invoiceNumber": "INV-2026-001",
"amount": 50000.00,
"paidAmount": 20000.00,
"pendingAmount": 30000.00,
"status": "Overdue",
"invoiceDate": "2026-01-15T00:00:00Z",
"dueDate": "2026-02-15T00:00:00Z",
"description": "Monthly pharmaceutical supplies",
"isActive": true,
"createdAt": "2026-01-15T10:00:00Z"
}
],
"totalCount": 1,
"page": 1,
"pageSize": 15
}GET /api/invoices/:id
Returns a single invoice with nested vendor details and all computed fields.
Permission: Invoice:Read
Response — Single Invoice 200 OK — InvoiceDto (with nested vendor object)
Response — Not Found 404
POST /api/invoices
Creates a new invoice against a vendor.
Permission: Invoice:Create
Request Body
json
{
"vendorId": 1,
"invoiceNumber": "INV-2026-050",
"amount": 75000.00,
"invoiceDate": "2026-03-17T00:00:00Z",
"dueDate": "2026-04-17T00:00:00Z",
"description": "Q1 pharmaceutical supplies"
}| Field | Required | Description |
|---|---|---|
vendorId | ✅ | Must reference an existing active vendor |
invoiceNumber | ✅ | Unique invoice number |
amount | ✅ | Total invoice amount (positive decimal) |
invoiceDate | ✅ | Date of the invoice |
dueDate | ✅ | Payment due date |
description | — | Optional notes |
Response — Created 201 — InvoiceDto
Response — Invalid 400 Bad Request
PUT /api/invoices/:id
Updates an existing invoice.
Permission: Invoice:Update
Response — Updated 200 OK — Updated InvoiceDto
Response — Not Found 404
DELETE /api/invoices/:id
Soft-deletes an invoice (sets isActive = false). Status becomes Canceled.
Permission: Invoice:Delete
Request Body (optional)
json
{ "reason": "Duplicate invoice" }