EasyPay is a closed-loop digital payment and financial management platform designed to enable fast, secure, and intelligent transactions within controlled ecosystems. The platform connects students, guardians or all customers, merchants which are businesses, and administrators through a unified system powered by M-Pesa integration and QR-based payments.
At its core, EasyPay replaces slow, manual mobile money interactions with a real-time, ledger-driven infrastructure that supports instant payments, transaction tracking, and programmable financial controls.
-Purpose
The primary goal of EasyPay is to:
Eliminate transaction delays caused by traditional mobile money workflows
Provide transparent and traceable financial records through a centralized ledger
Enable controlled spending using digital wallets
Improve operational efficiency for merchants and institutions
Reduce transaction expences
-How It Works (High-Level)
EasyPay operates on a two-layer financial architecture:
External Layer (M-Pesa Integration via Safaricom Daraja):
Handles deposits (STK Push), withdrawals (B2C)
Acts as the bridge between real-world money and the platform
Internal Layer (Ledger System):
Maintains users balances
Processes transactions instantly (sub-second)
Records all financial activities with full audit trails
- Key Concept: Closed-Loop Payments
Unlike traditional payment systems where every transaction goes through external providers, EasyPay uses a closed-loop model:
Funds are first deposited into the platform
All day-to-day transactions occur internally via the ledger
External APIs are only used for entry (top-up) and exit (withdrawal)
This approach ensures:
⚡ Faster transactions
💰 Lower operational costs
📊 Better financial control and visibility
🚀 Core Capabilities
QR-Based Payments: Users make payments by presenting a secure, time-sensitive QR code, enabling fast “scan-and-go” transactions.
Smart Wallets (Programmable Money): Funds can be categorized (e.g., meals, personal).
Real-Time Ledger: Every transaction is processed atomically, updating balances instantly while maintaining a complete transaction history.
Transaction Tracking & Transparency: Users can view detailed histories of all transactions, ensuring accountability and financial awareness.
Multi-User Ecosystem: Supports different roles:
Students (end users)
customers (end users)
businesses (service providers)
Admins (system managers)
- System Vision
EasyPay goes beyond being a simple wallet by acting as a:
Behavioral financial system that optimizes speed, enforces smart spending, and provides real-time financial visibility.
It is designed to scale while maintaining data isolation, transaction accuracy, and system reliability.
- Multi-role Authentication: Students, Guardians (Parents), Merchants, and Administrators
- Digital Wallets: Multiple wallet types (MEAL, POCKET, PERSONAL, SETTLEMENT)
- M-Pesa Integration: STK push deposits and B2C withdrawals
- QR Token System: Dynamic QR codes for contactless payments
- Payment Processing: Merchant-student transaction handling
- Financial Ledger: Complete audit trail and account statements
- Real-time Notifications: In-app notification system
- Role-based Dashboards: Tailored insights for each user type
- Backend: Django REST Framework
- Authentication: JWT (JSON Web Tokens)
- Database: PostgreSQL with UUID primary keys
- Payment Gateway: M-Pesa API Integration
- Architecture: RESTful API with role-based access control
EasyPay uses JWT (JSON Web Tokens) for authentication. The system issues two tokens upon login:
- Access Token: Short-lived token for API requests (expires in minutes)
- Refresh Token: Long-lived token for obtaining new access tokens
Method: POST
URL: /api/accounts/login/
Authenticates a user with email and password, returning JWT tokens for subsequent API requests.
{
"email": "user@example.com",
"password": "securepassword123"
}{
"user": {
"id": "uuid-string",
"email": "user@example.com",
"first_name": "John",
"last_name": "Doe",
"roles": [
{
"role": "STUDENT"
}
]
},
"tokens": {
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
}- 200 OK → Authentication successful
- 401 Unauthorized → Invalid credentials
No authentication required
Method: POST
URL: /api/accounts/token/refresh/
Exchanges a valid refresh token for a new access token without requiring full re-authentication.
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}- 200 OK → Token refreshed successfully
- 401 Unauthorized → Invalid or expired refresh token
No authentication required
Method: POST
URL: /api/accounts/register/
Registers a new user in the system with a specific role. The role determines the user's permissions and available features.
{
"email": "user@example.com",
"phone": "0712345678",
"first_name": "John",
"last_name": "Doe",
"password": "securepassword123",
"role": "STUDENT"
}{
"id": "uuid-string",
"email": "user@example.com",
"phone": "0712345678",
"first_name": "John",
"last_name": "Doe",
"roles": [
{
"role": "STUDENT"
}
]
}- 201 Created → User registered successfully
- 400 Bad Request → Validation error or duplicate data
No authentication required
Method: POST
URL: /api/accounts/logout/
Blacklists the provided refresh token, effectively logging the user out and invalidating the token.
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}{
"message": "Successfully logged out"
}- 205 Reset Content → Logout successful
- 400 Bad Request → Invalid token
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/accounts/me/
Returns the authenticated user's profile information including their assigned roles.
{
"id": "uuid-string",
"email": "user@example.com",
"phone": "0712345678",
"first_name": "John",
"last_name": "Doe",
"roles": [
{
"role": "STUDENT"
}
]
}- 200 OK → Profile retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: POST
URL: /api/students/setup/
Creates a student profile and links it to the authenticated user account using a registration number.
{
"reg_no": "STU/2024/001"
}{
"id": "uuid-string",
"user": "uuid-string",
"reg_no": "STU/2024/001",
"created_at": "2024-01-01T10:00:00Z"
}- 201 Created → Student profile created
- 400 Bad Request → Validation error
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/students/me/
Returns the student profile for the authenticated user.
{
"id": "uuid-string",
"user": "uuid-string",
"reg_no": "STU/2024/001",
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z"
}- 200 OK → Profile retrieved successfully
- 401 Unauthorized → Authentication required
- 404 Not Found → Student profile not found
Required (Bearer token)
Method: PATCH
URL: /api/students/me/
Partially updates the student profile. All fields are optional.
{
"reg_no": "STU/2024/002"
}{
"id": "uuid-string",
"user": "uuid-string",
"reg_no": "STU/2024/002",
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T11:00:00Z"
}- 200 OK → Profile updated successfully
- 400 Bad Request → Validation error
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/merchants/profile/
Returns the merchant's business profile including name, category, till number, and all registered terminals.
{
"id": "uuid-string",
"user": "uuid-string",
"name": "My Canteen",
"category_code": "FOOD",
"mpesa_till_number": "123456",
"is_active": true,
"terminals": [
{
"id": "uuid-string",
"device_id": "DEVICE-001",
"location": "Main Cafeteria - Counter 1",
"is_online": true
}
]
}- 200 OK → Profile retrieved successfully
- 401 Unauthorized → Authentication required
- 404 Not Found → Business profile not found
Required (Bearer token)
Method: PATCH
URL: /api/merchants/profile/
Partially updates the business profile. Category must be FOOD or OTHERS.
{
"name": "My Canteen",
"category_code": "FOOD"
}{
"id": "uuid-string",
"name": "My Canteen",
"category_code": "FOOD",
"mpesa_till_number": "123456",
"is_active": true
}- 200 OK → Profile updated successfully
- 400 Bad Request → Validation error
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/merchants/terminals/
Returns all POS terminals registered under the authenticated merchant's business.
[
{
"id": "uuid-string",
"business": "uuid-string",
"device_id": "DEVICE-001",
"location": "Main Cafeteria - Counter 1",
"is_online": true,
"created_at": "2024-01-01T10:00:00Z"
}
]- 200 OK → Terminals retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: POST
URL: /api/merchants/terminals/
Registers a new POS terminal for the authenticated merchant's business.
{
"device_id": "DEVICE-001",
"location": "Main Cafeteria - Counter 1"
}{
"id": "uuid-string",
"business": "uuid-string",
"device_id": "DEVICE-001",
"location": "Main Cafeteria - Counter 1",
"is_online": true,
"created_at": "2024-01-01T10:00:00Z"
}- 201 Created → Terminal registered successfully
- 400 Bad Request → Validation error
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/guardians/profile/
Returns the guardian's profile including their name and phone number.
{
"id": "uuid-string",
"user": "uuid-string",
"phone": "0712345678",
"created_at": "2024-01-01T10:00:00Z"
}- 200 OK → Profile retrieved successfully
- 401 Unauthorized → Authentication required
- 404 Not Found → Guardian profile not found
Required (Bearer token)
Method: GET
URL: /api/guardians/students/
Returns all students linked to the authenticated guardian's account.
[
{
"id": "uuid-string",
"reg_no": "STU/2024/001",
"first_name": "Student",
"last_name": "Name",
"can_view_transactions": true,
"can_topup": true
}
]- 200 OK → Students retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: POST
URL: /api/guardians/students/
Links a student to the guardian's account using the student's registration number. The student must already exist in the system.
{
"reg_no": "STU/2024/001"
}{
"id": "uuid-string",
"guardian": "uuid-string",
"student": "uuid-string",
"can_view_transactions": true,
"can_topup": true,
"created_at": "2024-01-01T10:00:00Z"
}- 201 Created → Student linked successfully
- 400 Bad Request → Validation error or student not found
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/wallets/
Returns all wallets belonging to the authenticated user with their current balances.
[
{
"id": "uuid-string",
"owner_type": "STUDENT",
"owner_id": "uuid-string",
"type": "MEAL",
"balance": 1500.00,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z"
},
{
"id": "uuid-string",
"owner_type": "STUDENT",
"owner_id": "uuid-string",
"type": "POCKET",
"balance": 500.00,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z"
}
]- 200 OK → Wallets retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/wallets/{wallet_type}/
Returns details for a specific wallet type. Replace MEAL with POCKET, PERSONAL, or SETTLEMENT as needed.
{
"id": "uuid-string",
"owner_type": "STUDENT",
"owner_id": "uuid-string",
"type": "MEAL",
"balance": 1500.00,
"created_at": "2024-01-01T10:00:00Z",
"updated_at": "2024-01-01T10:00:00Z"
}- 200 OK → Wallet retrieved successfully
- 401 Unauthorized → Authentication required
- 404 Not Found → Wallet type not found
Required (Bearer token)
Method: POST
URL: /api/payments/intent/create/
Creates a payment intent from a POS terminal. The intent expires in 1 minute. Terminal must be a UUID of registered terminal.
{
"terminal": "uuid-string",
"amount": 150.00
}{
"id": "uuid-string",
"terminal": "uuid-string",
"amount": 150.00,
"status": "PENDING",
"expires_at": "2024-01-01T10:01:00Z",
"created_at": "2024-01-01T10:00:00Z"
}- 201 Created → Payment intent created
- 400 Bad Request → Validation error
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/payments/intent/{uuid}/
Polls the status of a payment intent. Used by terminal to check if student has completed payment.
{
"id": "uuid-string",
"terminal": "uuid-string",
"amount": 150.00,
"status": "COMPLETED",
"student": "uuid-string",
"completed_at": "2024-01-01T10:00:30Z",
"created_at": "2024-01-01T10:00:00Z"
}- 200 OK → Status retrieved successfully
- 401 Unauthorized → Authentication required
- 404 Not Found → Payment intent not found
Required (Bearer token)
Method: POST
URL: /api/qr/generate/
Generates a new dynamic QR token for the authenticated student or guardian. Invalidates any existing active token. Token expires in 1 minute.
{
"amount": 150.00,
"wallet_type": "MEAL"
}{
"token": "ABC123XYZ789",
"amount": 150.00,
"wallet_type": "MEAL",
"owner": "uuid-string",
"expires_at": "2024-01-01T10:01:00Z",
"created_at": "2024-01-01T10:00:00Z"
}- 201 Created → QR token generated
- 400 Bad Request → Validation error
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/qr/validate/{token_value}/
Used by merchant app to verify a scanned QR code before processing a transaction. Returns validity status, amount, and owner.
{
"valid": true,
"token": "ABC123XYZ789",
"amount": 150.00,
"wallet_type": "MEAL",
"owner": {
"id": "uuid-string",
"name": "John Doe",
"type": "STUDENT"
},
"expires_at": "2024-01-01T10:01:00Z"
}- 200 OK → Token validated successfully
- 404 Not Found → Token not found or expired
No authentication required (public endpoint)
Method: POST
URL: /api/transactions/process-sale/
Executes a payment by matching a student's QR token with a merchant's payment intent. Validates amounts match, checks wallet balance, and processes the transfer.
{
"token_value": "ABC123XYZ789",
"intent_id": "uuid-string",
"wallet_type": "MEAL"
}{
"id": "uuid-string",
"from_wallet": "uuid-string",
"to_wallet": "uuid-string",
"amount": 150.00,
"status": "COMPLETED",
"reference": "TXN123456789",
"created_at": "2024-01-01T10:00:00Z"
}- 201 Created → Transaction processed successfully
- 400 Bad Request → Validation error or insufficient funds
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/transactions/history/
Returns all transactions for the authenticated merchant's business.
[
{
"id": "uuid-string",
"from_wallet": "uuid-string",
"to_wallet": "uuid-string",
"amount": 150.00,
"status": "COMPLETED",
"reference": "TXN123456789",
"created_at": "2024-01-01T10:00:00Z"
}
]- 200 OK → Transactions retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: POST
URL: /api/deposits/initiate/
Initiates an M-Pesa STK push to top up a wallet. Minimum amount is KES 10. Phone must be in format 0XXXXXXXXX.
{
"amount": 500,
"target_wallet": "MEAL",
"phone_number": "0712345678"
}{
"id": "uuid-string",
"user": "uuid-string",
"amount": 500,
"target_wallet": "MEAL",
"phone_number": "0712345678",
"status": "PENDING",
"mpesa_request_id": "ws_CO_191220191020363925",
"created_at": "2024-01-01T10:00:00Z"
}- 201 Created → Deposit initiated
- 400 Bad Request → Validation error
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/deposits/history/
Returns all deposits made by the authenticated user.
[
{
"id": "uuid-string",
"user": "uuid-string",
"amount": 500,
"target_wallet": "MEAL",
"status": "SUCCESS",
"mpesa_receipt": "NLJ7RT61SV",
"created_at": "2024-01-01T10:00:00Z"
}
]- 200 OK → Deposits retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: POST
URL: /api/withdrawals/request/
Initiates an M-Pesa B2C transfer. Wallet source is determined by role: merchants use SETTLEMENT, students use POCKET, guardians use PERSONAL.
{
"amount": 200,
"phone_number": "0712345678"
}{
"id": "uuid-string",
"user": "uuid-string",
"amount": 200,
"phone_number": "0712345678",
"status": "PENDING",
"created_at": "2024-01-01T10:00:00Z"
}- 201 Created → Withdrawal requested
- 400 Bad Request → Validation error or insufficient funds
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: POST
URL: /api/withdrawals/callback/
Public endpoint called by Safaricom to deliver B2C transaction results. Not for direct use — this is called automatically by M-Pesa.
{
"Result": {
"ResultCode": 0,
"ResultDesc": "The service request is processed successfully.",
"TransactionID": "NLJ7RT61SV",
"ResultParameters": {
"ResultParameter": [
{
"Key": "TransactionAmount",
"Value": 200
},
{
"Key": "TransactionReceipt",
"Value": "NLJ7RT61SV"
},
{
"Key": "ReceiverPartyPublicName",
"Value": "254712345678 - John Doe"
}
]
}
}
}{
"status": "success",
"message": "Callback processed"
}- 200 OK → Callback processed successfully
No authentication required (public webhook)
Method: POST
URL: /api/mpesa/callback/
Public endpoint called by Safaricom to deliver STK push transaction results. Not for direct use — this is called automatically by M-Pesa.
{
"Body": {
"stkCallback": {
"MerchantRequestID": "29115-34620561-1",
"CheckoutRequestID": "ws_CO_191220191020363925",
"ResultCode": 0,
"ResultDesc": "The service request is processed successfully.",
"CallbackMetadata": {
"Item": [
{
"Name": "Amount",
"Value": 500
},
{
"Name": "MpesaReceiptNumber",
"Value": "NLJ7RT61SV"
},
{
"Name": "PhoneNumber",
"Value": 254712345678
}
]
}
}
}
}{
"status": "success",
"message": "Callback processed"
}- 200 OK → Callback processed successfully
No authentication required (public webhook)
Method: GET
URL: /api/notifications/
Returns all notifications for the authenticated user, newest first.
[
{
"id": "uuid-string",
"user": "uuid-string",
"title": "Payment Received",
"message": "You received KES 150.00 from My Canteen",
"type": "PAYMENT",
"read": false,
"created_at": "2024-01-01T10:00:00Z"
}
]- 200 OK → Notifications retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: PATCH
URL: /api/notifications/{uuid}/read/
Marks a specific notification as read.
{
"id": "uuid-string",
"read": true,
"read_at": "2024-01-01T10:30:00Z"
}- 200 OK → Notification marked as read
- 401 Unauthorized → Authentication required
- 404 Not Found → Notification not found
Required (Bearer token)
Method: POST
URL: /api/notifications/read-all/
Marks all unread notifications as read for the authenticated user.
{
"message": "All notifications marked as read",
"count": 5
}- 200 OK → All notifications marked as read
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/dashboards/student/
Returns student dashboard data: meal & pocket balances, today's spend, unread notifications count, and active QR token if any.
{
"user": {
"name": "John Doe",
"reg_no": "STU/2024/001"
},
"wallets": {
"meal_balance": 1500.00,
"pocket_balance": 500.00
},
"today_spend": 250.00,
"unread_notifications": 3,
"active_qr_token": {
"token": "ABC123XYZ789",
"amount": 150.00,
"expires_at": "2024-01-01T10:01:00Z"
}
}- 200 OK → Dashboard data retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/dashboards/merchant/
Returns merchant dashboard data: business name, settlement balance, today's revenue, transaction count, pending withdrawals, and unread notifications.
{
"business": {
"name": "My Canteen",
"category": "FOOD"
},
"settlement_balance": 5000.00,
"today_revenue": 2500.00,
"today_transactions": 25,
"pending_withdrawals": 1,
"unread_notifications": 2
}- 200 OK → Dashboard data retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/dashboards/guardian/
Returns guardian dashboard data: personal balance, total family value, unread notifications, and a summary of each linked child's balance and today's spend.
{
"personal_balance": 2000.00,
"total_family_value": 4500.00,
"unread_notifications": 1,
"children": [
{
"name": "John Doe",
"reg_no": "STU/2024/001",
"meal_balance": 1500.00,
"pocket_balance": 500.00,
"today_spend": 250.00
}
]
}- 200 OK → Dashboard data retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/ledger/accounts/
Returns all ledger accounts owned by the authenticated user (e.g. Meal, Pocket) with their current balances.
[
{
"id": "uuid-string",
"owner_id": "uuid-string",
"account_type": "STUDENT_MEAL",
"balance": 1500.00,
"created_at": "2024-01-01T10:00:00Z"
},
{
"id": "uuid-string",
"owner_id": "uuid-string",
"account_type": "STUDENT_POCKET",
"balance": 500.00,
"created_at": "2024-01-01T10:00:00Z"
}
]- 200 OK → Accounts retrieved successfully
- 401 Unauthorized → Authentication required
Required (Bearer token)
Method: GET
URL: /api/ledger/statement/{account_type}/
Returns a full history of all money movements (debits and credits) for a specific ledger account type.
[
{
"id": "uuid-string",
"debit_account": "uuid-string",
"credit_account": "uuid-string",
"amount": 150.00,
"reference": "TXN123456789",
"description": "Payment at My Canteen",
"status": "POSTED",
"created_at": "2024-01-01T10:00:00Z"
}
]- 200 OK → Statement retrieved successfully
- 401 Unauthorized → Authentication required
- 404 Not Found → Account type not found
Required (Bearer token)
- User Initiates Deposit: User calls
/api/deposits/initiate/with amount, target wallet, and phone number - Backend Sends STK Push: System processes request and sends M-Pesa STK push to user's phone
- User Enters PIN: User receives prompt on phone and enters M-Pesa PIN
- Safaricom Sends Callback: M-Pesa calls
/api/mpesa/callback/with transaction result - Backend Updates Transaction: System processes callback, updates deposit status, and credits user's wallet
- User Requests Withdrawal: User calls
/api/withdrawals/request/with amount and phone number - Backend Validates Request: System checks wallet balance and validates withdrawal request
- Backend Sends B2C Request: System initiates M-Pesa B2C transfer to user's phone
- Safaricom Processes Request: M-Pesa processes the withdrawal and sends money to user
- Callback Updates Transaction: M-Pesa calls
/api/withdrawals/callback/with transaction result - Backend Finalizes Withdrawal: System processes callback, updates withdrawal status, and debits wallet
- Student Generates QR: Student calls
/api/qr/generate/to create dynamic QR token - Merchant Scans QR: Merchant scans QR code using POS terminal
- Merchant Validates Token: POS calls
/api/qr/validate/{token}/to verify token validity - Merchant Creates Payment Intent: POS calls
/api/payments/intent/create/to initiate payment - Student Confirms Payment: System matches QR token with payment intent
- Payment Processed: System transfers funds from student's wallet to merchant's settlement account
- Notifications Sent: Both parties receive transaction notifications
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| String | User email address (unique) | |
| phone | String | Phone number (unique, format: 07XXXXXXXXX) |
| first_name | String | User's first name |
| last_name | String | User's last name |
| is_active | Boolean | Account status |
| is_staff | Boolean | Admin access flag |
| roles | Array | User's assigned roles |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| user | UUID | Reference to User |
| role | String | Role type (STUDENT, CUSTOMER, BUSINESS, ADMIN) |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| user | UUID | Reference to User |
| reg_no | String | Registration number (unique) |
| created_at | DateTime | Profile creation timestamp |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| user | UUID | Reference to User |
| name | String | Business name |
| category_code | String | Business category (FOOD, OTHERS) |
| mpesa_till_number | String | M-Pesa till number |
| is_active | Boolean | Business status |
| terminals | Array | Registered POS terminals |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| business | UUID | Reference to Business |
| device_id | String | Terminal device ID (unique per business) |
| location | String | Physical location |
| is_online | Boolean | Online status |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| owner_type | String | Owner type (STUDENT, CUSTOMER, BUSINESS) |
| owner_id | UUID | Owner's user ID |
| type | String | Wallet type (MEAL, POCKET, PERSONAL, SETTLEMENT) |
| balance | Decimal | Current balance |
| created_at | DateTime | Wallet creation timestamp |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| terminal | UUID | POS terminal reference |
| amount | Decimal | Payment amount |
| status | String | Intent status (PENDING, COMPLETED, EXPIRED) |
| expires_at | DateTime | Expiration timestamp |
| Field | Type | Description |
|---|---|---|
| token | String | Token value |
| amount | Decimal | Payment amount |
| wallet_type | String | Source wallet type |
| owner | UUID | Token owner |
| expires_at | DateTime | Expiration timestamp |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| from_wallet | UUID | Source wallet |
| to_wallet | UUID | Destination wallet |
| amount | Decimal | Transaction amount |
| status | String | Transaction status |
| reference | String | Transaction reference |
| created_at | DateTime | Transaction timestamp |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| user | UUID | Depositing user |
| amount | Decimal | Deposit amount |
| target_wallet | String | Destination wallet type |
| phone_number | String | M-Pesa phone number |
| status | String | Deposit status (PENDING, SUCCESS, FAILED) |
| mpesa_request_id | String | M-Pesa request ID |
| mpesa_receipt | String | M-Pesa receipt number |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| user | UUID | Withdrawing user |
| amount | Decimal | Withdrawal amount |
| phone_number | String | Destination phone |
| status | String | Withdrawal status (PENDING, SUCCESS, FAILED) |
| transaction_id | String | M-Pesa transaction ID |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| user | UUID | Notification recipient |
| title | String | Notification title |
| message | String | Notification message |
| type | String | Notification type |
| read | Boolean | Read status |
| created_at | DateTime | Creation timestamp |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| owner_id | UUID | Account owner |
| account_type | String | Account type (STUDENT_MEAL, STUDENT_POCKET, etc.) |
| balance | Decimal | Current balance |
| Field | Type | Description |
|---|---|---|
| id | UUID | Unique identifier |
| debit_account | UUID | Account being debited |
| credit_account | UUID | Account being credited |
| amount | Decimal | Entry amount |
| reference | String | Entry reference |
| description | String | Entry description |
| status | String | Entry status |
| created_at | DateTime | Entry timestamp |
{
"email": ["This field is required."],
"phone": ["Phone number must be in format 07XXXXXXXXX"]
}{
"error": "Invalid Credentials"
}{
"error": "You do not have permission to perform this action"
}{
"error": "Resource not found"
}{
"error": "Internal server error occurred"
}{
"error": "M-Pesa service unavailable",
"details": "Unable to reach M-Pesa API"
}| Variable | Type | Description |
|---|---|---|
| base_url | String | API base URL (default: http://127.0.0.1:8000) |
| access_token | String | JWT access token for authenticated requests |
| refresh_token | String | JWT refresh token for token renewal |
- Set Base URL: Configure
base_urlto point to your EasyPay instance - Login: Use
/api/accounts/login/to obtain tokens - Set Tokens: Save
accesstoken toaccess_tokenvariable - Use Auth: Collection automatically uses Bearer token for protected endpoints
- Base URL:
http://127.0.0.1:8000 - Content-Type:
application/json - Authentication: Bearer token in Authorization header
- 200 OK → Request successful
- 201 Created → Resource created successfully
- 400 Bad Request → Validation error
- 401 Unauthorized → Authentication required or invalid
- 403 Forbidden → Permission denied
- 404 Not Found → Resource not found
- 500 Internal Server Error → Server error
POST /api/accounts/register/→ Create accountPOST /api/accounts/login/→ Get tokens- Set
access_tokenvariable - Make authenticated requests
POST /api/accounts/logout/→ Logout
- MEAL: Student meal allowance wallet
- POCKET: Student personal spending wallet
- PERSONAL: Guardian/personal wallet
- SETTLEMENT: Merchant settlement wallet
- STUDENT: Can make payments, generate QR codes
- CUSTOMER/Guardian: Can top up student wallets, view transactions
- BUSINESS/Merchant: Can receive payments, manage terminals
- ADMIN: Full system access