Overview
The Madad Platform REST API provides developers with secure access to product data and other platform resources. Built with modern standards and best practices, our API uses JWT-based authentication with role-based access control.
https://api.madad.app
Pagination
The API uses cursor-based pagination for efficient data retrieval:
- page_size: Number of items per page (default: 25, max: 100)
- page_token: Opaque token for getting the next page
- next_page_token: Token returned in response for next page
- has_next_page: Boolean indicating if more pages exist
1. Make initial request:
GET /products?page_size=102. Get
next_page_token from response3. Make next request with token
4. Repeat until
has_next_page is false
Rate Limiting
The API implements comprehensive rate limiting to prevent abuse and ensure fair usage:
| Endpoint Category | Rate Limit | Window | Notes |
|---|---|---|---|
| General API | 100 requests | 15 minutes | Applies to all endpoints |
| Authentication | 5 requests | 15 minutes | Successful requests don't count |
| Products | 60 requests | 1 minute | Product endpoints only |
When limits are exceeded, the API returns a
429 Too Many Requests status with retry information.
Authentication
The API uses JWT-based authentication with a dual-token system for maximum security:
- Access Token: Short-lived (15 minutes) for API requests
- Refresh Token: Long-lived (7 days) for obtaining new access tokens
- Role Required: developer role assigned by Madad team
Prerequisites
- Developer account provided by Madad team
- Valid email and password credentials
- Developer role assigned to your account
Authentication Flow
Login
Get initial tokens
Use Access Token
Make API requests
Refresh Tokens
When access token expires
Handle Expiry
Gracefully in your app
API Endpoints
Authenticate and get tokens
Authenticate with email and password to receive access and refresh tokens.
{
"email": "developer@example.com",
"password": "your-password"
}
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900,
"scope": "api_access",
"user": {
"id": "user123",
"email": "developer@example.com",
"role": "developer"
}
}
| Status | Error Code | Description |
|---|---|---|
| 400 | bad_request |
Email and password are required |
| 401 | unauthorized |
Invalid email or password |
| 403 | forbidden |
Access denied. Developer role required. |
Get paginated products
Retrieve a paginated list of active products with cursor-based pagination.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page_size |
integer | Optional | Number of products per page (default: 25, max: 100) |
page_token |
string | Optional | Token for pagination (from previous response) |
Health check
Check the API health status. This endpoint doesn't require authentication.
{
"status": "healthy",
"timestamp": "2024-01-09T12:00:00.000Z",
"version": "1.0.0"
}
Error Handling
The API uses standard HTTP status codes and returns errors in a consistent format:
{
"error": "error_code",
"message": "Human-readable error message"
}
HTTP Status Codes
| Status Code | Error Code | Description |
|---|---|---|
| 400 | bad_request |
Invalid request parameters |
| 401 | unauthorized |
Missing or invalid authentication |
| 401 | token_expired |
Access token has expired |
| 403 | forbidden |
Insufficient permissions |
| 404 | not_found |
Resource not found |
| 429 | too_many_requests |
Rate limit exceeded |
| 500 | internal_server_error |
Server error |
Rate Limit Error Response
{
"error": "too_many_requests",
"message": "Too many requests from this IP, please try again in 15 minutes.",
"retry_after": 900
}
The API includes standard rate limit headers in responses:
RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
Common Error Scenarios
retry_after period before making new requests. Implement exponential backoff for best results.
Code Examples
class MadadAPIClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.accessToken = null;
this.refreshToken = null;
this.retryCount = 0;
this.maxRetries = 3;
}
async login(email, password) {
const response = await fetch(`${this.baseUrl}/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message);
}
const data = await response.json();
this.accessToken = data.access_token;
this.refreshToken = data.refresh_token;
return data;
}
async getProducts(pageSize = 25, pageToken = null) {
const params = new URLSearchParams({ page_size: pageSize });
if (pageToken) params.append('page_token', pageToken);
return this.makeAuthenticatedRequest(`/products?${params}`);
}
async makeAuthenticatedRequest(endpoint, options = {}) {
const headers = {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
...options.headers,
};
try {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers,
});
// Handle rate limiting
if (response.status === 429) {
const errorData = await response.json();
const retryAfter = errorData.retry_after || 60;
if (this.retryCount < this.maxRetries) {
this.retryCount++;
console.log(`Rate limited. Retrying after ${retryAfter} seconds...`);
await this.delay(retryAfter * 1000);
return this.makeAuthenticatedRequest(endpoint, options);
}
throw new Error(`Rate limit exceeded. Retry after ${retryAfter} seconds.`);
}
// Handle token expiration
if (response.status === 401) {
const errorData = await response.json();
if (errorData.error === 'token_expired') {
await this.refreshTokens();
headers['Authorization'] = `Bearer ${this.accessToken}`;
return fetch(`${this.baseUrl}${endpoint}`, { ...options, headers });
}
}
if (!response.ok) {
const error = await response.json();
throw new Error(error.message);
}
this.retryCount = 0; // Reset on success
return response.json();
} catch (error) {
if (error.name === 'TypeError') {
throw new Error('Network error. Please check your connection.');
}
throw error;
}
}
async refreshTokens() {
const response = await fetch(`${this.baseUrl}/refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: this.refreshToken }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message);
}
const data = await response.json();
this.accessToken = data.access_token;
this.refreshToken = data.refresh_token;
return data;
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Usage with error handling
const client = new MadadAPIClient('https://api.madad.app');
async function example() {
try {
await client.login('developer@example.com', 'password');
const products = await client.getProducts(10);
console.log('Products:', products);
} catch (error) {
if (error.message.includes('Rate limit')) {
console.log('Rate limited - implement exponential backoff');
} else {
console.error('API Error:', error.message);
}
}
}
# 1. Health check (no auth required)
curl -X GET https://api.madad.app/health
# 2. Login (rate limited: 5 requests per 15 minutes)
curl -X POST https://api.madad.app/login \
-H "Content-Type: application/json" \
-d '{
"email": "developer@example.com",
"password": "your-password"
}'
# 3. Get products with rate limit headers (60 requests per minute)
curl -X GET "https://api.madad.app/products?page_size=10" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-I # Include headers to see rate limiting info
# 4. Handle rate limiting with retry
curl -X GET "https://api.madad.app/products" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
--retry 3 \
--retry-delay 60 \
--retry-connrefused
# 5. Refresh token (rate limited: 5 requests per 15 minutes)
curl -X POST https://api.madad.app/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "YOUR_REFRESH_TOKEN"
}'
# Example rate limit response (429):
# {
# "error": "too_many_requests",
# "message": "Too many requests from this IP, please try again in 15 minutes.",
# "retry_after": 900
# }
Postman Collection
For easy testing, we provide a comprehensive Postman collection with pre-configured requests, automatic token management, and built-in testing scripts.
• Pre-configured requests with examples
• Automatic token management
• Built-in testing scripts
• Comprehensive documentation
• Error handling examples
Quick Setup:
- Download the collection above
- Import into Postman (File → Import)
- Set your developer credentials in collection variables
- Run the Health Check to verify connectivity
- Login to get your tokens
- Start exploring the API!
Quick Start Workflow
- Health Check: Verify API is available
- Login: Get your access and refresh tokens
- Fetch Products: Use the paginated products endpoint
- Handle Pagination: Use
next_page_tokenfor subsequent pages - Refresh Tokens: When access token expires (every 15 minutes)