A backend-focused REST API for managing invoices with line items, automatic tax calculation, MongoDB persistence, Swagger documentation, Docker support and automated API tests.
Invoice API is a portfolio backend project that simulates a realistic invoice management service for small business or agency workflows.
The project is intentionally focused on backend architecture, business logic and API design. It is not a frontend project and not a simple tutorial CRUD example.
The API supports creating, reading, updating and deleting invoices. Each invoice contains structured customer data, invoice line items and calculated totals. The backend calculates item totals, subtotal, tax amount and final invoice total automatically.
A real invoice system should not rely on manually entered final amounts only. This API models invoices with:
- Unique invoice numbers
- Customer information
- Invoice line items
- Quantity and unit price per item
- Automatic subtotal calculation
- Tax calculation with a default tax rate of 19%
- Final total calculation
- Invoice status handling
- Draft invoices can be issued and receive an automatic due date
- Draft and open invoices can be cancelled when they are no longer valid
New invoices are created as drafts and receive an automatically generated invoice number in the following format:
INV-YYYY-000001
Example:
INV-2026-000001
The current version includes dedicated lifecycle actions for issuing, paying and cancelling invoices.
| Action | Rule | Result |
|---|---|---|
| Issue invoice | Only DRAFT invoices can be issued |
Status changes to OPEN |
| Issue date | Set automatically when the invoice is issued | issuedAt is stored |
| Due date | Calculated automatically | dueDate = issuedAt + 14 days |
| Pay invoice | Only OPEN invoices can be paid |
Status changes to PAID |
| Payment date | Set automatically when the invoice is paid | paidAt is stored |
| Cancel invoice | Only DRAFT and OPEN invoices can be cancelled |
Status changes to CANCELLED |
| Cancellation date | Set automatically when the invoice is cancelled | cancelledAt is stored |
Paid invoices cannot be cancelled directly. A refund or credit-note workflow would be a separate future improvement.
| Feature | Description |
|---|---|
| Invoice CRUD | Create, read, update and delete invoices |
| Invoice Numbers | Automatic invoice number generation |
| Line Items | Invoices contain one or more billable items |
| Tax Calculation | Automatic subtotal, tax amount and total calculation |
| MongoDB | Persistent invoice storage with Mongoose |
| Validation | Request validation with Joi |
| Swagger | Interactive OpenAPI documentation |
| Logging | HTTP request logging with Morgan and Winston |
| Rate Limiting | Global and write-operation rate limits |
| Monitoring | Health and metrics endpoints |
| Tests | Automated API tests with Jest and Supertest |
| Docker | Containerized application setup |
| Invoice Issuing | Draft invoices can be issued with automatic issue and due dates |
| Invoice Payment | Open invoices can be marked as paid with an automatic payment timestamp |
| Invoice Cancellation | Draft and open invoices can be cancelled through a dedicated lifecycle action |
- Node.js
- Express.js
- MongoDB
- Mongoose
- Joi
- Jest
- Supertest
- Swagger / OpenAPI
- Docker
- Winston
- Morgan
The API is deployed on Render and available at:
https://invoice-api-disf.onrender.com
| Endpoint | Description |
|---|---|
https://invoice-api-disf.onrender.com/ |
API root endpoint |
https://invoice-api-disf.onrender.com/monitor/health |
Production health check |
https://invoice-api-disf.onrender.com/api-docs |
Swagger API documentation |
Swagger UI is available after starting the application:
http://localhost:3000/api-docs
| Method | Endpoint | Description |
|---|---|---|
| GET | /invoices |
Get all invoices |
| GET | /invoices/:id |
Get invoice by ID |
| POST | /invoices |
Create a new draft invoice |
| PUT | /invoices/:id |
Update editable invoice data |
| PATCH | /invoices/:id/issue |
Issue a draft invoice |
| PATCH | /invoices/:id/pay |
Mark an open invoice as paid |
| PATCH | /invoices/:id/cancel |
Cancel a draft or open invoice |
| DELETE | /invoices/:id |
Delete invoice |
| Method | Endpoint | Description |
|---|---|---|
| GET | /monitor/health |
API and database health status |
| GET | /monitor/metrics |
Basic runtime metrics |
{
"customer": {
"name": "MT Intelligence",
"email": "billing@mtintelligence.ai",
"address": {
"street": "Example Street 12",
"city": "Stuttgart",
"postalCode": "70173",
"country": "Germany"
}
},
"items": [
{
"description": "Backend API development",
"quantity": 5,
"unitPrice": 80
}
],
"taxRate": 19
}{
"_id": "6656f3c0e2a1d9f8b4a12345",
"invoiceNumber": "INV-2026-000001",
"customer": {
"name": "MT Intelligence",
"email": "billing@mtintelligence.ai",
"address": {
"street": "Example Street 12",
"city": "Stuttgart",
"postalCode": "70173",
"country": "Germany"
}
},
"items": [
{
"description": "Backend API development",
"quantity": 5,
"unitPrice": 80,
"total": 400
}
],
"subtotal": 400,
"taxRate": 19,
"taxAmount": 76,
"total": 476,
"status": "DRAFT",
"issuedAt": null,
"dueDate": null,
"paidAt": null,
"cancelledAt": null
}invoice-api/
│
├── .github/
│ └── workflows/
│ └── ci.yml
│
├── controllers/
│ └── invoiceController.js
│
├── docs/
│ └── swagger-ui.png
│
├── middleware/
│ ├── rateLimiter.js
│ ├── requestLogger.js
│ └── validateRequest.js
│
├── models/
│ └── invoice.js
│
├── routes/
│ ├── invoiceRoutes.js
│ └── monitorRoutes.js
│
├── services/
│ └── invoiceService.js
│
├── swagger/
│ └── swagger.json
│
├── tests/
│ ├── invoice.api.test.js
│ └── invoice.test.js
│
├── utils/
│ └── logger.js
│
├── validation/
│ └── invoiceValidation.js
│
├── Dockerfile
├── docker-compose.yml
├── index.js
├── package.json
├── package-lock.json
└── README.md
Create a .env file in the project root:
PORT=3000
MONGODB_URI=mongodb://127.0.0.1:27017/invoice-apiThe project uses a separate test environment configuration:
PORT=3001
MONGODB_URI=mongodb://localhost:27017/invoice-api-testNo production credentials are stored in the repository.
Clone the repository:
git clone https://github.com/tabari86/invoice-api.git
cd invoice-apiInstall dependencies:
npm installStart the API:
npm startThe application runs on:
http://localhost:3000
Swagger UI:
http://localhost:3000/api-docs
npm testThe test suite covers the main invoice API endpoints and verifies invoice creation, automatic total calculation, invoice retrieval, updates, deletion and invoice lifecycle actions such as issuing, paying and cancelling invoices.
Build the Docker image:
docker build -t invoice-api .Run the container:
docker run -p 3000:3000 invoice-apiIf MongoDB is managed through Docker Compose, start the services with:
docker compose up --buildThe current version focuses on the core invoice backend:
- Clean REST API structure
- Invoice creation with calculated totals
- Invoice issuing with automatic due date calculation
- Invoice payment with automatic payment timestamp
- Invoice cancellation with automatic cancellation timestamp
- MongoDB persistence
- Request validation
- Swagger documentation
- Automated API tests
- Docker support
- Basic monitoring and logging
Refunds, credit notes, partial payments, user accounts and invoice PDF generation are intentionally not included in the current scope. These topics may be considered as future improvements if they add clear business value.
Moj Tabari
-
Website: mtintelligence.ai
-
LinkedIn: Mojtaba Tabari
