http://localhost:8000/api/v1/
All endpoints require authentication using Django session authentication.
{
"error": "ERROR_CODE",
"message": "Human-readable error message"
}PERMISSION_DENIED- User lacks required permissionINVALID_STATE_TRANSITION- Request cannot transition to requested stateNOT_FOUND- Resource not foundVALIDATION_ERROR- Input validation failedAUTHENTICATION_FAILED- Authentication credentials invalid
GET /api/v1/users/me/Response:
{
"id": "uuid",
"username": "john",
"email": "john@example.com",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"is_active": true,
"created_at": "2026-01-20T10:00:00Z"
}GET /api/v1/users/Permission: Admin only
POST /api/v1/users/Permission: Admin only
Request:
{
"username": "newuser",
"email": "newuser@example.com",
"password": "securepassword123",
"first_name": "New",
"last_name": "User",
"role": "user"
}GET /api/v1/requests/Returns: Requests visible to the authenticated user based on their role
- Admin: All requests
- Manager: Own requests + assigned requests
- User: Only own requests
Response:
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": "uuid",
"title": "Budget Approval",
"description": "Q1 budget approval request",
"status": "submitted",
"status_display": "Submitted",
"creator": {
"id": "uuid",
"username": "john",
"email": "john@example.com",
"role": "user"
},
"assigned_to": {
"id": "uuid",
"username": "manager",
"role": "manager"
},
"reviewed_by": null,
"reviewed_at": null,
"rejection_reason": "",
"created_at": "2026-01-20T10:00:00Z",
"updated_at": "2026-01-20T10:05:00Z"
}
]
}POST /api/v1/requests/Request:
{
"title": "New Request",
"description": "Detailed description of the request"
}Response: 201 Created with request object
GET /api/v1/requests/{id}/PUT /api/v1/requests/{id}/Note: Only works for requests in draft status
Permission: Request creator only
Request:
{
"title": "Updated Title",
"description": "Updated description"
}DELETE /api/v1/requests/{id}/Note: Soft delete - only works for draft requests (or admin for any) Response: 204 No Content
POST /api/v1/requests/{id}/submit/Permission: Request creator only
Allowed from: draft status only
Response:
{
"id": "uuid",
"status": "submitted",
"status_display": "Submitted",
...
}POST /api/v1/requests/{id}/approve/Permission: Manager (assigned) or Admin
Allowed from: submitted status only
Response:
{
"id": "uuid",
"status": "approved",
"status_display": "Approved",
"reviewed_by": {...},
"reviewed_at": "2026-01-20T11:00:00Z",
...
}POST /api/v1/requests/{id}/reject/Permission: Manager (assigned) or Admin
Allowed from: submitted status only
Request:
{
"reason": "Insufficient documentation provided"
}Response:
{
"id": "uuid",
"status": "rejected",
"status_display": "Rejected",
"reviewed_by": {...},
"reviewed_at": "2026-01-20T11:00:00Z",
"rejection_reason": "Insufficient documentation provided",
...
}GET /api/v1/audit-logs/Permission: Manager (limited) or Admin (full)
Response:
{
"count": 5,
"results": [
{
"id": "uuid",
"actor": {
"id": "uuid",
"username": "manager",
"role": "manager"
},
"action": "approve",
"action_display": "Approve",
"content_type": 12,
"object_id": "request-uuid",
"metadata": {
"old_status": "submitted",
"new_status": "approved",
"request_title": "Budget Approval"
},
"ip_address": "192.168.1.100",
"timestamp": "2026-01-20T11:00:00Z"
}
]
}draft→submitted(via/submit/)submitted→approved(via/approve/)submitted→rejected(via/reject/)
approved(no further transitions)rejected(no further transitions)
| Action | User | Manager | Admin |
|---|---|---|---|
| Create Request | Yes | Yes | Yes |
| View Own Requests | Yes | Yes | Yes |
| View Assigned Requests | No | Yes | Yes |
| View All Requests | No | No | Yes |
| Edit Own Draft | Yes | Yes | Yes |
| Submit Request | Yes | Yes | Yes |
| Approve Request | No | Yes* | Yes |
| Reject Request | No | Yes* | Yes |
| View Audit Logs | No | Yes** | Yes |
| Manage Users | No | No | Yes |
* Manager can only approve/reject assigned requests
** Manager can only see logs for requests they're involved in
# Login (get session cookie)
curl -X POST http://localhost:8000/admin/login/ \
-d "username=user&password=user123" \
-c cookies.txt
# Create request
curl -X POST http://localhost:8000/api/v1/requests/ \
-b cookies.txt \
-H "Content-Type: application/json" \
-d '{"title":"Test Request","description":"Test description"}'
# Submit request
curl -X POST http://localhost:8000/api/v1/requests/{id}/submit/ \
-b cookies.txt
# Approve request (as manager)
curl -X POST http://localhost:8000/api/v1/requests/{id}/approve/ \
-b manager-cookies.txtimport requests
session = requests.Session()
# Login
session.post(
'http://localhost:8000/admin/login/',
data={'username': 'user', 'password': 'user123'}
)
# Create request
response = session.post(
'http://localhost:8000/api/v1/requests/',
json={
'title': 'New Request',
'description': 'Request description'
}
)
request_id = response.json()['id']
# Submit request
session.post(f'http://localhost:8000/api/v1/requests/{request_id}/submit/')Currently not implemented but can be added using:
django-ratelimitfor view-level limiting- Nginx rate limiting for request-level control
Default: 20 items per page
Query parameters:
?page=2- Get page 2?page_size=50- Change page size (max 100)