REST API Documentation

v1.0.0

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.

Base URL: 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
Pagination Workflow:
1. Make initial request: GET /products?page_size=10
2. Get next_page_token from response
3. 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
Rate Limit Response (429):
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

  1. Developer account provided by Madad team
  2. Valid email and password credentials
  3. Developer role assigned to your account

Authentication Flow

1️⃣

Login

Get initial tokens

2️⃣

Use Access Token

Make API requests

3️⃣

Refresh Tokens

When access token expires

4️⃣

Handle Expiry

Gracefully in your app

API Endpoints

POST /login

Authenticate and get tokens

Authenticate with email and password to receive access and refresh tokens.

Request Body
{
  "email": "developer@example.com",
  "password": "your-password"
}
Success Response (200 OK)
{
  "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 /products Auth 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)
GET /health

Health check

Check the API health status. This endpoint doesn't require authentication.

Response (200 OK)
{
  "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 Response 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

429 Too Many Requests
{
  "error": "too_many_requests",
  "message": "Too many requests from this IP, please try again in 15 minutes.",
  "retry_after": 900
}
Rate Limit Headers:
The API includes standard rate limit headers in responses:
RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

Common Error Scenarios

Token Expired: Access tokens expire every 15 minutes. Use the refresh token endpoint to get a new access token.
Rate Limiting: When you exceed rate limits, wait for the retry_after period before making new requests. Implement exponential backoff for best results.
Authentication Protection: Failed authentication attempts count against rate limits, but successful logins don't. This protects against brute force attacks while allowing normal usage.
Best Practice: Always handle errors gracefully, implement retry logic for temporary failures, and respect rate limits to maintain API access.

Code Examples

JavaScript API Client with Rate Limiting
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);
    }
  }
}
cURL Examples with Rate Limiting
# 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.

Features included:
• Pre-configured requests with examples
• Automatic token management
• Built-in testing scripts
• Comprehensive documentation
• Error handling examples
Quick Setup:
  1. Download the collection above
  2. Import into Postman (File → Import)
  3. Set your developer credentials in collection variables
  4. Run the Health Check to verify connectivity
  5. Login to get your tokens
  6. Start exploring the API!

Quick Start Workflow

  1. Health Check: Verify API is available
  2. Login: Get your access and refresh tokens
  3. Fetch Products: Use the paginated products endpoint
  4. Handle Pagination: Use next_page_token for subsequent pages
  5. Refresh Tokens: When access token expires (every 15 minutes)