Disbursement API
A disbursement starts as PENDING and can be approved or rejected once. Anything already processed returns 409.
- Category
- Transactional backend API
- Stack
- Go
- REST API
- MySQL
- JWT
- GORM
- Docker
- Source
- shiinobu/disbursement-api
- POST/api/auth/login200 OKReturns a JWT and the user with role: admin.
- POST/api/disbursements201 Createdstatus: "PENDING", admin_fee: 2500 for an amount of 1500000.
- PATCH/api/disbursements/1/status200 OKBody { "status": "APPROVED" }. Response has status: "APPROVED" and processed_by.
- PATCH/api/disbursements/1/status409 ConflictBody { "status": "REJECTED" } on the same record. Error: "hanya disbursement pending yang dapat diproses" (only pending disbursements can be processed).
Overview
A backend API for managing fund disbursement requests, with JWT authentication, role-based authorization, status rules, pagination, search and CSV export.
At a glance
- JWT authentication
- Role-based access control
- PENDING → APPROVED / REJECTED workflow
- Status-based deletion rules
- Protected administrative operations
- Pagination metadata
- Search query support
- CSV reporting
- Layered repository/service/handler structure
- MySQL persistence with GORM
Problem and approach
Problem
Money movement needs more than CRUD. Each operation has to follow business rules, user permissions and controlled state transitions.
Approach
The API is built around the disbursement lifecycle: JWT authentication, role-based authorization, status-based rules, pagination, search and reporting endpoints.
Architecture
Requests pass through the API layer to business services, which reach the MySQL database through repositories. Authentication and authorization middleware protect operations by role and by record status.
API client
Sends authenticated requests to the disbursement REST API.
HTTP handler
Receives requests, validates input and maps them to application operations.
HTTP + JWT
Service layer
Applies business rules, authorization requirements and status transitions.
Repository
Handles persistence against the database.
MySQL
Stores users, disbursement records and transaction data.
GORM
How it works
A disbursement is not an open-ended CRUD record. Each state change is checked against its current status and the role of the user making the request.
- ApprovePENDINGAPPROVED
- RejectPENDINGREJECTED
Implementation
- JWT authentication
- Protected operations verify the identity of the requesting user before any business logic runs.
- Role-based authorization
- Sensitive operations are limited by user role, so only authorized users can perform administrative actions.
- Status management
- A disbursement moves through PENDING, APPROVED and REJECTED with controlled transitions instead of open-ended CRUD.
- Business rules
- Approval, rejection and deletion are checked against the current record status and the user's permissions before anything is written.
- Search and pagination
- List endpoints support search and pagination and return metadata about the current page and total records.
- CSV reporting
- Disbursement data can be exported as CSV for reporting.
Screens
Postman captures (6)
Notes
Challenges
- Implementing controlled disbursement state transitions
- Enforcing role-based permissions on sensitive operations
- Preventing invalid operations based on the current record status
- Designing consistent paginated API responses
- Supporting search and CSV reporting alongside transactional operations
Status
Every state change is checked against the current status and the user's role. Responses share one shape (data, message, success), and errors carry field-level messages.
Next project
Manufacture System API




