Skip to main content

Overview

The e-commerce API implements rate limiting to ensure fair usage, prevent abuse, and maintain service quality for all users. Rate limits are applied at different levels depending on the type of operation.

Rate Limit Configuration

The API uses multiple rate limiting strategies based on the operation type:

Kinesis Stream Rate Limiting

Data streaming to AWS Kinesis is rate-limited to prevent overwhelming the downstream processing pipeline:
settings.py
KINESIS_INSERT_RATE_LIMIT = ENV.get('KINESIS_INSERT_RATE_LIMIT')
This applies to:
  • Order event streaming (KINESIS_ORDERS_STREAM)
  • Product update streaming (KINESIS_PRODUCT_STREAM)
  • Product update events (KINESIS_PRODUCT_UPDATE_STREAM)
Kinesis rate limits are configured per environment and may vary between staging and production.

Background Queue Processing

Celery task queues have visibility timeouts to prevent duplicate processing:
settings.py
CELERY_VISIBILITY_TIMEOUT = 3600  # 1 hour in seconds
This ensures that:
  • Tasks are not picked up by multiple workers
  • Failed tasks can be retried after timeout
  • System resources are used efficiently

Authentication Rate Limits

To prevent brute force attacks and abuse, authentication endpoints have strict limits:

OTP Generation and Verification

settings.py
VERIFICATION_COUNT = 3      # Max OTP verification attempts
GENERATE_COUNT = 2          # Max OTP generation requests
RESEND_COUNT = 6            # Max OTP resend requests
USER_BLOCK_TIME_IN_SEC = 86400  # 24 hours
Verification Attempts:
  • Users can verify OTP up to 3 times
  • Exceeding limit triggers temporary account block
Generation Requests:
  • Users can request new OTP 2 times per session
  • Additional requests require waiting period
Resend Requests:
  • Users can resend OTP up to 6 times
  • After limit, must wait for cooldown period
Account Block:
  • Failed attempts result in 24-hour temporary block
  • Error message: “Your Account has been blocked due to multiple fail attempts”

User Account Creation

To prevent duplicate account creation and abuse:
settings.py
USER_LOCK_ENABLE = 1           # Enable user creation locking
USER_LOCK_EXPIRY = 300         # 5 minutes in seconds
USER_CREATION_UNDERPROCESS_MSG = 'User creation is under process, kindly wait for a moment.'
How It Works:
  • Lock is placed on email/phone during registration
  • Lock expires after 5 minutes
  • Prevents duplicate account creation race conditions
  • Returns friendly message if creation is in progress

Transaction Rate Limits

Order placement is rate-limited to prevent duplicate transactions:
settings.py
TXN_LOCK_ENABLE = 1            # Enable transaction locking
TXN_LOCK_EXPIRY = 900          # 15 minutes in seconds
RESTRICT_USER_TXN_ENABLE = 1   # Enable per-user transaction limits
PAYMENT_UNDERPROCESS_MSG = 'Your payment is currently being processed. Please try again later.'

Transaction Lock

Prevents duplicate order submission
  • Lock duration: 15 minutes
  • Applied per user + cart combination
  • Automatically released after completion

User Restrictions

Limits concurrent transactions per user
  • Prevents payment processing conflicts
  • Protects against accidental double-charges
  • Returns clear error message when active

Callback Request Limits

Customer support callback requests are rate-limited:
settings.py
CALLBACK_TIME_WINDOW_HOURS = 24
ENABLE_MULTIPLE_CALLBACK_CHECK = 1
MULTIPLE_CALLBACK_MESSAGE = "You have already raised a query. We will call you back between {} to {} on {}."
Policy:
  • One callback request per 24-hour period
  • Additional requests show existing callback time window
  • Ensures efficient support resource allocation

Ozonetel Callback Retries

settings.py
OZONETEL_CALLBACK_MAX_RETRIES = 1
FAILED_CALL_MAX_RETRIES = ENV.get('FAILED_CALL_MAX_RETRIES')
CALLBACK_RETRY_TIME_SECONDS = ENV.get('CALLBACK_RETRY_TIME_SECONDS')
Automated callback system retry limits:
  • Maximum automatic retries for failed calls
  • Configurable retry intervals
  • Prevents overwhelming support infrastructure

Email and Refund Limits

Automated Refund Emails

settings.py
REFUND_EMAIL_RETRY_COUNT = 3
REFUND_EMAIL_RETRY_SLEEP_TIME = 5  # seconds
BANK_REFUND_EMAIL_RETRY_COUNT = 3
BANK_REFUND_EMAIL_RETRY_SLEEP_TIME = 5
Refund notification emails are retried up to 3 times with 5-second intervals to ensure delivery.

Rate Limit Headers

The API currently does not expose rate limit information in response headers. Rate limits are enforced server-side and return error responses when exceeded.
When a rate limit is exceeded, you’ll receive an appropriate error response:

Transaction Lock Response

{
  "meta": {
    "code": 88,
    "message": "Invalid Parameter",
    "description": "Your payment is currently being processed. Please try again later."
  }
}

User Creation Lock Response

{
  "meta": {
    "code": 88,
    "message": "Invalid Parameter",
    "description": "User creation is under process, kindly wait for a moment."
  }
}

Multiple Callback Request Response

{
  "meta": {
    "code": 88,
    "message": "Invalid Parameter",
    "description": "You have already raised a query. We will call you back between 2:00 PM to 3:00 PM on 2026-03-09."
  }
}

Account Block Response

{
  "meta": {
    "code": 99,
    "message": "Authentication Required",
    "description": "Your Account has been blocked for 24 hours due to multiple fail attempts, please contact thesouledstore team"
  }
}

Handling 429 Responses

While the API uses HTTP 400/401 for most rate limit scenarios, future versions may implement HTTP 429 (Too Many Requests) responses.
Best practices for handling rate-limited requests:

1. Implement Exponential Backoff

async function retryWithBackoff(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.meta?.code === 88 && error.meta?.description?.includes('in process')) {
        const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

2. Display Clear User Messages

function handleRateLimitError(error) {
  const description = error.meta?.description || '';
  
  if (description.includes('payment is currently being processed')) {
    showNotification({
      type: 'warning',
      message: 'Your order is being processed. Please wait a moment.'
    });
  } else if (description.includes('multiple fail attempts')) {
    showNotification({
      type: 'error',
      message: 'Too many failed attempts. Your account has been temporarily locked.'
    });
  } else if (description.includes('already raised a query')) {
    showNotification({
      type: 'info',
      message: description
    });
  }
}

3. Prevent Duplicate Submissions

let isSubmitting = false;

async function submitOrder(orderData) {
  if (isSubmitting) {
    return { error: 'Please wait, your order is being processed.' };
  }
  
  try {
    isSubmitting = true;
    const response = await api.post('/api/v2/processorder', orderData);
    return response;
  } finally {
    // Keep lock for a few seconds to prevent double-click
    setTimeout(() => {
      isSubmitting = false;
    }, 3000);
  }
}

4. Monitor Rate Limit Errors

function logRateLimitError(error) {
  if (error.meta?.code === 88 || error.meta?.code === 99) {
    // Send to monitoring service
    analytics.track('rate_limit_hit', {
      endpoint: error.endpoint,
      errorCode: error.meta.code,
      description: error.meta.description,
      timestamp: new Date().toISOString()
    });
  }
}

Best Practices

For Client Applications

Cache Responses

Cache GET requests to reduce API calls
  • Use appropriate cache TTLs
  • Implement stale-while-revalidate
  • Respect cache-control headers

Debounce User Input

Delay API calls for search/filter operations
  • 300-500ms debounce for autocomplete
  • Prevent typing from triggering too many requests

Batch Operations

Combine multiple requests when possible
  • Use batch endpoints if available
  • Queue non-critical updates

Handle Errors Gracefully

Provide clear feedback to users
  • Show progress indicators
  • Display helpful error messages
  • Offer retry options

For Server Applications

  1. Implement Request Queuing
    • Use a queue system for bulk operations
    • Process items in batches
    • Respect rate limits in queue workers
  2. Use Service Accounts Wisely
    • Don’t share credentials across services
    • Implement proper authentication for each integration
    • Monitor API usage per service
  3. Implement Circuit Breakers
    class CircuitBreaker {
      constructor(threshold = 5, timeout = 60000) {
        this.failureCount = 0;
        this.threshold = threshold;
        this.timeout = timeout;
        this.state = 'CLOSED';
      }
      
      async execute(fn) {
        if (this.state === 'OPEN') {
          throw new Error('Circuit breaker is open');
        }
        
        try {
          const result = await fn();
          this.onSuccess();
          return result;
        } catch (error) {
          this.onFailure();
          throw error;
        }
      }
      
      onSuccess() {
        this.failureCount = 0;
        this.state = 'CLOSED';
      }
      
      onFailure() {
        this.failureCount++;
        if (this.failureCount >= this.threshold) {
          this.state = 'OPEN';
          setTimeout(() => {
            this.state = 'HALF_OPEN';
            this.failureCount = 0;
          }, this.timeout);
        }
      }
    }
    

Monitoring Your Usage

While the API doesn’t expose usage metrics in headers, you should:
  1. Log all API requests in your application
  2. Track error rates especially for rate limit errors
  3. Monitor response times to detect performance degradation
  4. Set up alerts for repeated rate limit errors

Contact Support

If you’re consistently hitting rate limits:
  • Review your implementation for inefficient API usage
  • Consider caching strategies to reduce request volume
  • Contact API support to discuss higher rate limits for your use case
  • Provide usage patterns and business justification for limit increases
Rate limits are designed to ensure fair usage and system stability. If you have legitimate high-volume use cases, reach out to discuss enterprise solutions.

Build docs developers (and LLMs) love