Limits

In this guide, we will look at how rate limiting works in the Moon Banking API. We will cover the rate limit structure, how to monitor your usage, and best practices for handling rate limits in your application.

The Moon Banking API uses rate limiting to ensure fair usage and maintain optimal performance for all users. Understanding how rate limits work will help you build robust applications that handle API requests efficiently.

Except for customers with a custom rate limit, the Moon Banking API limits API requests to 100 requests per minute per API key to ensure fair usage and prevent abuse. You may request higher limits by contacting support.


Rate limit structure

The Moon Banking API implements a simple and predictable rate limiting system based on fixed time windows. All rate limits are applied per API key.

    Name
    Requests per minute
    Description

    100 requests per minute per API key (may be increased upon request)

    Name
    Time window
    Description

    Fixed clock minutes (not rolling windows)

    Name
    Scope
    Description
    Rate limits apply per API key

Fixed minute windows

Rate limits are based on fixed clock minutes rather than rolling time windows. This means:

  • The rate limit counter resets at the start of each clock minute (e.g., 10:45:00, 10:46:00)
  • If you make 100 requests at 10:45:59, you can immediately make 100 more at 10:46:00

Monitoring your rate limits

API responses include headers that tell you your current rate limit status. You should monitor these headers to avoid hitting rate limits.

    Name
    X-Rate-Limit-Per-Minute
    Description

    The maximum number of requests allowed per minute (currently 100, but may be increased upon request)

    Name
    X-Rate-Limit-Remaining-Per-Minute
    Description

    The number of requests remaining in the current minute

    Name
    X-Rate-Limit-Reset-Per-Minute
    Description

    The ISO 8601 timestamp when the rate limit will reset

    Name
    X-Rate-Limit-Retry-After
    Description

    The number of seconds until the next reset time for the per-minute rate limit. You should wait to retry until this number of seconds has passed. This header will only be present if you have exceeded the rate limit.

Example response headers

Response headers

HTTP/1.1 200 OK
X-Rate-Limit-Per-Minute: 100
X-Rate-Limit-Remaining-Per-Minute: 87
X-Rate-Limit-Reset-Per-Minute: 2025-01-05T15:47:00.000Z
Content-Type: application/json

When you exceed the limit

When you exceed your rate limit, the API will return a 429 Too Many Requests error. The response headers will include information about your rate limit status and when you can make requests again.

Error response

{
  "success": false,
  "message": "Rate limit exceeded. Please try again later.",
  "code": "RATE_LIMIT_EXCEEDED",
  "timestamp": "2025-01-05T15:46:37.482Z",
  "version": "2025-07-11"
}

Best practices

Follow these best practices to avoid hitting rate limits and build a robust integration with the Moon Banking API.

Implement retry logic with exponential backoff

Always implement retry logic that respects the retryAfter value in rate limit errors. Use exponential backoff for repeated failures.

async function makeRequestWithRetry(requestFn, maxRetries = 3) {
  try {
    for (let attempt = 0; attempt <= maxRetries; attempt++) {
      try {
        return await requestFn();
      } catch (error) {
        if (error.code === 'RATE_LIMIT_EXCEEDED' && attempt < maxRetries) {
          const retryAfter = error.data?.retryAfter || 1;
          const backoff = Math.min(retryAfter * 1000 * 2 ** attempt, 60000);
          await new Promise((resolve) => setTimeout(resolve, backoff));
          continue;
        }
        throw error;
      }
    }
  } catch (error) {
    console.error('Request failed after retries:', error);
    throw error;
  }
}

Monitor rate limit headers

Always check the X-RateLimit-Remaining-PerMinute header and slow down your requests when you're getting close to the limit.

async function monitorRateLimit(response) {
  const remaining = parseInt(
    response.headers.get('X-RateLimit-Remaining-PerMinute'),
  );
  const resetTime = response.headers.get('X-RateLimit-Reset-PerMinute');

  if (remaining < 10) {
    console.warn(
      `Rate limit warning: Only ${remaining} requests remaining until ${resetTime}`,
    );
    // Consider slowing down or queuing requests
  }

  return remaining;
}

Implement request queuing

For applications that need to make many requests, implement a queue system that respects rate limits and spreads requests evenly across each minute.

class RateLimitedQueue {
  constructor(requestsPerMinute = 100) {
    this.limit = requestsPerMinute;
    this.queue = [];
    this.processing = false;
  }

  async add(requestFn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ requestFn, resolve, reject });
      if (!this.processing) {
        this.process();
      }
    });
  }

  async process() {
    this.processing = true;

    while (this.queue.length > 0) {
      const { requestFn, resolve, reject } = this.queue.shift();

      try {
        const result = await requestFn();
        resolve(result);
      } catch (error) {
        if (error.code === 'RATE_LIMIT_EXCEEDED') {
          // Re-queue the request
          this.queue.unshift({ requestFn, resolve, reject });
          const retryAfter = error.data?.retryAfter || 30;
          await new Promise((r) => setTimeout(r, retryAfter * 1000));
        } else {
          reject(error);
        }
      }

      // Add small delay between requests to avoid bursting
      await new Promise((r) => setTimeout(r, 600)); // ~100 requests per minute
    }

    this.processing = false;
  }
}

// Usage
const queue = new RateLimitedQueue(100);

for (const id of countryIds) {
  queue.add(() => client.countries.retrieve(id));
}

Cache responses when possible

Reduce the number of API requests by caching responses for data that doesn't change frequently.

const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function getCachedCountry(client, countryId) {
  const cacheKey = `country:${countryId}`;
  const cached = cache.get(cacheKey);

  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }

  const data = await client.countries.retrieve(countryId);
  cache.set(cacheKey, { data, timestamp: Date.now() });

  return data;
}

Rate limit increases

The current rate limit of 100 requests per minute is designed to accommodate most use cases. If your application requires higher rate limits, please contact support to discuss your needs.

When requesting a rate limit increase, please provide:

  • Your use case and expected request volume

Was this page helpful?