🔌 Khanaa API Integration Guide (Frontend & Mobile)
Welcome to the Khanaa Frontend Integration Guide. This document explains how to connect your Next.js and React Native applications to the Khanaa Core API.
Our backend uses a Unified Authentication System. This means Customers, Riders, and Vendors all authenticate using the exact same endpoints. Your app's routing logic determines which screens to show based on their database role.
1. Environment & Base URL Setup
Do NOT hardcode the API URL in your components. We use environment variables so the apps can seamlessly switch between the live server and local testing environments.
Create or update your .env file:
# For Next.js (Web):
NEXT_PUBLIC_API_URL=https://api.khanaa.in
# For React Native (Expo):
EXPO_PUBLIC_API_URL=https://api.khanaa.in
# Note: If testing locally with the backend team, replace the above with the ngrok URL they provide.
2. Centralized API Client (Axios)
To avoid repeating code, configure an Axios instance globally. This ensures every request goes to the correct URL and automatically attaches the JWT token.
Create src/services/apiClient.ts (or .js):
import axios from 'axios';
import AsyncStorage from '@react-native-async-storage/async-storage'; // Use localStorage for Next.js
export const apiClient = axios.create({
baseURL: process.env.EXPO_PUBLIC_API_URL || process.env.NEXT_PUBLIC_API_URL,
timeout: 10000,
});
// Automatically inject the Khanaa JWT Token into every request
apiClient.interceptors.request.use(
async (config) => {
const token = await AsyncStorage.getItem('khanaa_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// Global error handler for Expired Tokens
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
// Token is invalid or expired. Clear storage and redirect to Login.
await AsyncStorage.removeItem('khanaa_token');
// trigger logout / navigation logic here
}
return Promise.reject(error);
}
);
3. Authentication Endpoints
We support three primary login methods. All successful logins return the exact same response structure.
A. Mobile OTP (Primary)
- Request OTP:
POST /auth/send-otp
Payload:
{ "phone": "+919876543210" }
- Verify OTP:
POST /auth/verify-otp
Payload:
{ "phone": "+919876543210", "otp": "123456" }
B. Email & Password
- Register:
POST /auth/email/register
{ "email": "x@x.com", "password": "pass" }
- Login:
POST /auth/email/login
{ "email": "x@x.com", "password": "pass", "rememberMe": true }
C. Google SSO
- Login/Register:
POST /auth/google
{ "idToken": "eyJhbGci..." }
Note: Obtain the
idTokenusing the React Native Google SDK. Do NOT implement web redirects on mobile.
Expected API Response (All Login Methods)
{
"message": "Authentication successful",
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"user": {
"id": "uuid-1234",
"phone": "+919876543210",
"email": "user@example.com",
"role": "CUSTOMER"
}
}
4. The "Gatekeeper" Routing Logic (Crucial)
After a successful login, you MUST save the accessToken to secure storage. Then, evaluate the user.role to determine the user's destination.
Example (Vendor App):
const handleLoginSuccess = async (response) => {
// 1. Save the token
await AsyncStorage.setItem('khanaa_token', response.accessToken);
// 2. Route based on role
if (response.user.role === 'VENDOR') {
navigation.replace('VendorDashboard');
}
else if (response.user.role === 'CUSTOMER') {
navigation.replace('KycUploadScreen');
}
else {
alert('Unauthorized app access.');
await AsyncStorage.removeItem('khanaa_token');
}
};
5. Password Management & Security Endpoints
Unauthenticated (No JWT required)
- Forgot Password:
POST /auth/password/forgot
{ "email": "x@x.com" }
- Reset Password:
POST /auth/password/reset
{ "token": "string", "newPassword": "pass" }
Authenticated (Requires JWT)
- Change Password:
POST /auth/password/change
{ "oldPassword": "pass", "newPassword": "pass" }
- Fetch Profile:
GET /auth/me
6. Calling Protected Routes Example
Because you configured the apiClient, calling protected routes becomes simple.
import { apiClient } from '../services/apiClient';
// Example: Fetch user profile
const fetchUserProfile = async () => {
try {
const response = await apiClient.get('/auth/me');
console.log("User Data:", response.data);
} catch (error) {
console.error("Failed to fetch profile:", error.response?.data?.message);
}
};
7. API Documentation
Interactive Swagger Docs:
👉 https://api.khanaa.in/api/docs