This document lists ALL backend API endpoints required for the AX Rider mobile app to function properly.
Base URL: https://api.axpress.ng/api/v1/rider (or your configured base URL)
Start Super User
Field Value Phone 08031346316 Password Admin1234! Email inyang1@gmail.com Is Superuser ✅
- Endpoint:
POST /api/riders/auth/login/ - Purpose: Authenticate rider with phone and password
- Request Body:
{ "phone": "08012345678", "password": "password123", "device_id": "uuid-device-id", "device_name": "iPhone 15 Pro", "device_os": "ios", "fcm_token": "firebase-cloud-messaging-token" } - Response:
{ "tokens": { "access": "jwt-access-token", "refresh": "jwt-refresh-token" }, "rider": { "id": "rider_001", "name": "John Doe", "phone": "08012345678", ... } } - Status: ✅ CRITICAL - App cannot function without this
- Endpoint:
POST /auth/biometric/ - Purpose: Login using biometric authentication (fingerprint)
- Request Body:
{ "device_id": "uuid-device-id", "biometric_token": "encrypted-biometric-token", "fcm_token": "firebase-token" } - Response: Same as login
- Status:
⚠️ OPTIONAL - For biometric login feature
- Endpoint:
POST /auth/biometric/register/ - Purpose: Register device for biometric login
- Request Body:
{ "device_id": "uuid-device-id", "device_name": "iPhone 15 Pro", "biometric_type": "fingerprint" } - Status:
⚠️ OPTIONAL - For biometric login feature
- Endpoint:
POST /auth/refresh/ - Purpose: Refresh expired access token
- Request Body:
{ "refresh": "jwt-refresh-token" } - Response:
{ "access": "new-jwt-access-token" } - Status: ✅ CRITICAL - For maintaining user sessions
- Endpoint:
POST /auth/logout/ - Purpose: Invalidate tokens and logout rider
- Status: ✅ REQUIRED
- Endpoint:
POST /auth/change-password/ - Purpose: Change rider's password
- Request Body:
{ "old_password": "old123", "new_password": "new123" } - Status: ✅ REQUIRED
- Endpoint:
POST /api/fcm-token/(NEW - for Firebase) - Purpose: Update rider's Firebase Cloud Messaging token
- Request Body:
{ "fcm_token": "firebase-cloud-messaging-token" } - Status: ✅ CRITICAL - For Firebase push notifications
- Endpoint:
GET /me/ - Purpose: Get current rider's profile
- Response:
{ "id": "rider_001", "name": "John Doe", "phone": "08012345678", "email": "john@example.com", "status": "active", "duty_status": "on_duty", "vehicle_type": "bike", "rating": 4.8, "total_deliveries": 150, ... } - Status: ✅ CRITICAL - Displayed on home screen
- Endpoint:
PATCH /profile/ - Purpose: Update rider profile information
- Request Body:
{ "name": "John Doe", "email": "john@example.com", "address": "123 Main St" } - Status: ✅ REQUIRED
- Endpoint:
PATCH /bank/ - Purpose: Update bank account for withdrawals
- Request Body:
{ "bank_name": "GTBank", "account_number": "0123456789", "account_name": "John Doe" } - Status: ✅ REQUIRED - For wallet withdrawals
- Endpoint:
POST /avatar/ - Purpose: Upload profile picture
- Request: Multipart form data with image file
- Status:
⚠️ OPTIONAL
- Endpoint:
POST /duty/ - Purpose: Toggle rider between on-duty and off-duty
- Request Body:
{ "status": "on_duty", // or "off_duty" "latitude": 6.5244, "longitude": 3.3792 } - Response:
{ "status": "on_duty", "timestamp": "2024-01-15T10:30:00Z" } - Status: ✅ CRITICAL - Core functionality
- Endpoint:
GET /orders/assigned/ - Purpose: Get list of orders assigned to rider
- Response: Array of order objects
- Status: ✅ CRITICAL - Main screen content
- Endpoint:
GET /orders/{order_id}/ - Purpose: Get detailed information about specific order
- Status: ✅ CRITICAL
- Endpoint:
POST /orders/{order_id}/start/ - Purpose: Mark order as started (heading to pickup)
- Request Body:
{ "latitude": 6.5244, "longitude": 3.3792 } - Status: ✅ CRITICAL
- Endpoint:
POST /orders/{order_id}/arrived/ - Purpose: Mark arrival at pickup location
- Status: ✅ CRITICAL
- Endpoint:
POST /orders/{order_id}/pickup/ - Purpose: Mark order as picked up
- Request Body:
{ "latitude": 6.5244, "longitude": 3.3792, "pickup_time": "2024-01-15T10:30:00Z" } - Status: ✅ CRITICAL
- Endpoint:
POST /orders/{order_id}/at-dropoff/ - Purpose: Mark arrival at dropoff location
- Status: ✅ CRITICAL
- Endpoint:
POST /orders/{order_id}/deliver/ - Purpose: Mark order as delivered
- Status: ✅ CRITICAL
- Endpoint:
POST /orders/{order_id}/complete/ - Purpose: Complete order and finalize
- Request Body:
{ "latitude": 6.5244, "longitude": 3.3792, "completion_time": "2024-01-15T11:00:00Z", "notes": "Delivered successfully" } - Status: ✅ CRITICAL
- Endpoint:
POST /orders/{order_id}/cancel/ - Purpose: Cancel order with reason
- Request Body:
{ "reason": "Customer not available", "notes": "Called multiple times" } - Status: ✅ REQUIRED
- Endpoint:
POST /orders/{order_id}/cod/ - Purpose: Record cash-on-delivery payment
- Request Body:
{ "amount": 5000, "payment_method": "cash" } - Status: ✅ CRITICAL - For COD orders
- Endpoint:
POST /orders/{order_id}/proof/ - Purpose: Upload delivery proof (photo, barcode, signature)
- Request: Multipart form data
phase: "pickup" or "delivery" proof_type: "photo", "barcode", "signature" file: image file barcode_value: "scanned-barcode-value" notes: "Additional notes" latitude: 6.5244 longitude: 3.3792 - Status: ✅ CRITICAL - Required for order completion
- Endpoint:
GET /orders/history/ - Purpose: Get rider's completed orders
- Query Parameters:
?page=1&limit=20&status=completed - Status: ✅ REQUIRED
- Endpoint:
GET /offers/ - Purpose: Get list of available order offers
- Response: Array of offer objects
- Status: ✅ CRITICAL - "For You" tab content
- Endpoint:
POST /offers/{offer_id}/accept/ - Purpose: Accept an order offer
- Response: Full order object
- Status: ✅ CRITICAL
- Endpoint:
POST /offers/{offer_id}/decline/ - Purpose: Decline an order offer
- Request Body:
{ "reason": "Too far", "Too busy", etc. } - Status: ✅ CRITICAL
- Endpoint:
GET /routes/ - Purpose: Get delivery routes assigned to rider
- Query Parameters:
?status=activeor?status=completed - Response: Array of route objects with multiple stops
- Status: ✅ CRITICAL - Routes screen content
- Endpoint:
GET /routes/{route_id}/ - Purpose: Get detailed route information with all stops
- Status: ✅ CRITICAL
- Endpoint:
POST /routes/{route_id}/stops/{stop_id}/start/ - Purpose: Mark a route stop as started
- Status: ✅ CRITICAL
- Endpoint:
POST /routes/{route_id}/stops/{stop_id}/complete/ - Purpose: Mark a route stop as completed
- Status: ✅ CRITICAL
- Endpoint:
GET /earnings/ - Purpose: Get earnings summary for different periods
- Query Parameters:
?period=todayor?period=weekor?period=month - Response:
{ "period": "today", "total_earnings": 15000, "total_deliveries": 12, "total_distance": 45.5, "total_hours": 6.5, "breakdown": { "base_fare": 10000, "distance_bonus": 3000, "tips": 2000 } } - Status: ✅ CRITICAL - Earnings screen content
- Endpoint:
GET /wallet/ - Purpose: Get current wallet balance
- Response:
{ "balance": 45000, "pending": 5000, "available": 40000, "currency": "NGN" } - Status: ✅ CRITICAL - Wallet screen content
- Endpoint:
GET /wallet/transactions/ - Purpose: Get wallet transaction history
- Query Parameters:
?page=1&limit=20 - Response: Array of transaction objects
- Status: ✅ CRITICAL
- Endpoint:
POST /wallet/withdraw/ - Purpose: Request withdrawal to bank account
- Request Body:
{ "amount": 10000 } - Status: ✅ CRITICAL - Withdrawal feature
- Endpoint:
POST /location/ - Purpose: Update rider's current location (real-time tracking)
- Request Body:
{ "latitude": 6.5244, "longitude": 3.3792, "speed_kmh": 25.5, "battery_pct": 85 } - Status: ✅ CRITICAL - Real-time tracking
- Note: Called every 30 seconds when on duty
- Endpoint:
POST /location/batch/ - Purpose: Upload multiple location points at once
- Request Body:
{ "locations": [ { "latitude": 6.5244, "longitude": 3.3792, "timestamp": "2024-01-15T10:30:00Z", "speed_kmh": 25.5 } ] } - Status:
⚠️ OPTIONAL - For offline location buffering
- Endpoint:
GET /notifications/ - Purpose: Get rider's notifications
- Response: Array of notification objects
- Status: ✅ REQUIRED - Notifications screen
- Endpoint:
PATCH /notifications/{notification_id}/read/ - Purpose: Mark single notification as read
- Status: ✅ REQUIRED
- Endpoint:
POST /notifications/read-all/ - Purpose: Mark all notifications as read
- Status: ✅ REQUIRED
- Endpoint:
GET /documents/ - Purpose: Get rider's uploaded documents (license, insurance, etc.)
- Response: Array of document objects
- Status:
⚠️ OPTIONAL - Document management
- Endpoint:
POST /documents/upload/ - Purpose: Upload rider documents
- Request: Multipart form data
doc_type: "license", "insurance", "vehicle_registration" file: document file expires_at: "2025-12-31" - Status:
⚠️ OPTIONAL
- Endpoint:
POST /support/ - Purpose: Create support ticket
- Request Body:
{ "category": "technical", "subject": "Payment not received", "message": "I completed order AX-12345 but haven't received payment", "order_id": "order_123" } - Status: ✅ REQUIRED - Support/help feature
- Endpoint:
GET /support/tickets/ - Purpose: Get rider's support tickets
- Status:
⚠️ OPTIONAL
- Endpoint:
GET /demand/ - Purpose: Get high-demand areas (heat map)
- Response:
[ { "area": "Ikeja", "latitude": 6.5244, "longitude": 3.3792, "demand_level": "high", "active_orders": 15, "surge_multiplier": 1.5 } ] - Status:
⚠️ OPTIONAL - Heat map feature
- Method: Firebase Admin SDK
- Purpose: Send real-time notifications to riders
- Status: ✅ CRITICAL - Real-time notifications
- Note: Replaces WebSocket/Ably for push notifications
Message Types:
from firebase_admin import messaging
import json
message = messaging.Message(
data={
'type': 'incoming_order',
'offer': json.dumps({
'id': 'offer_123',
'orderId': 'order_456',
'estimatedEarnings': '2500',
'distanceKm': '5.2',
'etaMins': '15',
'pickupAddress': '123 Main St',
'dropoffAddress': '456 Oak Ave',
'merchantName': 'Shoprite',
'vehicleType': 'bike',
'paymentMethod': 'cash',
'codAmount': '0',
'secondsRemaining': '300',
'expiresAt': '2024-01-15T10:30:00Z',
})
},
token=rider.fcm_token,
notification=messaging.Notification(
title='🚴 New Order Incoming!',
body='₦2500 · 5.2km',
),
android=messaging.AndroidConfig(
priority='high',
),
apns=messaging.APNSConfig(
payload=messaging.APNSPayload(
aps=messaging.Aps(
sound='default',
),
),
),
)
messaging.send(message)message = messaging.Message(
data={
'type': 'order_update',
'order_id': 'order_456',
'status': 'picked_up',
'timestamp': '2024-01-15T10:35:00Z',
},
token=rider.fcm_token,
notification=messaging.Notification(
title='Order Update',
body='Order picked up successfully',
),
)
messaging.send(message)message = messaging.Message(
data={
'type': 'notification',
'title': 'New Bonus Available',
'body': 'Complete 5 more deliveries today!',
'priority': 'high',
},
token=rider.fcm_token,
notification=messaging.Notification(
title='New Bonus Available',
body='Complete 5 more deliveries today!',
),
)
messaging.send(message)- Login -
POST /api/riders/auth/login/ - Refresh Token -
POST /auth/refresh/ - Update FCM Token -
POST /api/fcm-token/(NEW) - Get Profile -
GET /me/ - Toggle Duty Status -
POST /duty/ - Get Assigned Orders -
GET /orders/assigned/ - Get Order Detail -
GET /orders/{order_id}/ - Order Lifecycle - Start/Pickup/Deliver/Complete
- Upload Proof of Delivery -
POST /orders/{order_id}/proof/ - Get Available Offers -
GET /offers/ - Accept/Decline Offer -
POST /offers/{offer_id}/accept|decline/ - Get Routes -
GET /routes/ - Route Stop Start/Complete -
POST /routes/{route_id}/stops/{stop_id}/start|complete/ - Get Earnings Summary -
GET /earnings/ - Get Wallet Balance -
GET /wallet/ - Get Wallet Transactions -
GET /wallet/transactions/ - Update Location -
POST /location/ - Firebase Push Notifications - Backend sends via Firebase Admin SDK
- Logout -
POST /auth/logout/ - Change Password -
POST /auth/change-password/ - Update Profile -
PATCH /profile/ - Update Bank Details -
PATCH /bank/ - Record COD Payment -
POST /orders/{order_id}/cod/ - Cancel Order -
POST /orders/{order_id}/cancel/ - Get Order History -
GET /orders/history/ - Withdraw Funds -
POST /wallet/withdraw/ - Get Notifications -
GET /notifications/ - Mark Notifications as Read -
PATCH /notifications/{id}/read/ - Create Support Ticket -
POST /support/
- Biometric Login -
POST /auth/biometric/ - Register Biometric -
POST /auth/biometric/register/ - Upload Avatar -
POST /avatar/ - Batch Location Update -
POST /location/batch/ - Get/Upload Documents -
GET|POST /documents/ - Get Support Tickets -
GET /support/tickets/ - Get Area Demand -
GET /demand/
pip install firebase-admin# settings.py or firebase_config.py
import firebase_admin
from firebase_admin import credentials
cred = credentials.Certificate('path/to/serviceAccountKey.json')
firebase_admin.initialize_app(cred)Add to Rider model:
class Rider(models.Model):
# ... existing fields
fcm_token = models.CharField(max_length=255, blank=True, null=True)
fcm_token_updated_at = models.DateTimeField(auto_now=True)
device_id = models.CharField(max_length=255, blank=True, null=True)
device_name = models.CharField(max_length=100, blank=True, null=True)
device_os = models.CharField(max_length=20, blank=True, null=True)- All endpoints (except login) require JWT authentication
- Include in headers:
Authorization: Bearer <access_token> - Token expires after 24 hours (configurable)
- Use refresh token to get new access token
All successful responses should follow this format:
{
"success": true,
"data": { ... },
"message": "Success message"
}Error responses:
{
"success": false,
"error": "Error message",
"code": "ERROR_CODE",
"details": {}
}200 OK- Successful GET/PATCH201 Created- Successful POST (resource created)204 No Content- Successful DELETE400 Bad Request- Invalid request data401 Unauthorized- Missing or invalid token403 Forbidden- Valid token but insufficient permissions404 Not Found- Resource not found500 Internal Server Error- Server error
Use tools like:
- Postman - API testing
- cURL - Command line testing
- Django REST Framework Browsable API - Built-in testing
# Login
curl -X POST https://api.axpress.ng/api/riders/auth/login/ \
-H "Content-Type: application/json" \
-d '{
"phone": "08012345678",
"password": "password123",
"device_id": "test-device",
"fcm_token": "test-fcm-token"
}'
# Get Profile (with auth)
curl -X GET https://api.axpress.ng/api/v1/rider/me/ \
-H "Authorization: Bearer <access_token>"Use Firebase Console to send test messages:
- Go to Firebase Console → Cloud Messaging
- Send test message to specific FCM token
- Verify app receives the message
For more details, refer to:
FIREBASE_SETUP.md- Complete Firebase integration guideFIREBASE_QUICK_REFERENCE.md- Quick reference for Firebaselib/services/api_service.dart- API service implementationlib/config/api.dart- Endpoint definitionslib/models/models.dart- Data models
- Authentication (Login, Refresh Token, Logout)
- Profile (Get Profile, Update Profile)
- Duty Status (Toggle Duty)
- Orders (Get Assigned, Order Detail, Order Lifecycle)
- Location (Update Location)
- Firebase FCM Token endpoint
- Offers (Get, Accept, Decline)
- Proof of Delivery (Upload)
- COD Payment Recording
- Order History
- Earnings (Get Summary)
- Wallet (Balance, Transactions, Withdraw)
- Bank Details (Update)
- Routes (Get, Detail, Stop Management)
- Notifications (Get, Mark Read)
- Support (Create Ticket)
- Firebase Push Notifications (Backend implementation)
- Biometric Authentication
- Documents Management
- Area Demand/Heat Map
- Batch Location Updates
Document Version: 1.0 Last Updated: 2024-01-15 Contact: Backend Team