How to Handle Rate Limiting When Using APIMart: A Complete Guide

When APIMart returns HTTP 429, the SDK translates it into a APIMART_RATE_LIMITED error that includes a retryAfterMs property, allowing you to pause and retry automatically.

The freestylefly/awesome-gpt-image-2 repository provides a robust JavaScript SDK for image generation through APIMart. Learning to handle rate limiting when using APIMart ensures your application remains responsive and avoids service disruptions when you hit per-key request quotas.

Understanding APIMart Rate Limits

APIMart enforces strict per-key request quotas to ensure fair usage across all clients. When you exceed your allocated limit, the API responds with HTTP 429 (Too Many Requests). The SDK in this repository transforms these responses into structured errors that contain actionable retry information.

Detecting Rate Limit Errors

The SDK identifies rate-limit conditions through the apimartErrorCode utility found in shared/apimart.js. At line 73, this function maps HTTP 429 responses to the constant APIMART_RATE_LIMITED, creating a standardized error object you can catch reliably.

// Error detection happens automatically
if (error.code === 'APIMART_RATE_LIMITED') {
  console.log('Rate limit exceeded');
}

Reading the Retry-After Interval

Every rate-limit response includes a Retry-After header indicating how long to wait before retrying. The retryAfterMilliseconds helper (lines 81–90 in shared/apimart.js) parses this header—whether it contains seconds or a timestamp—and attaches the value to error.retryAfterMs as a millisecond integer.

// The error object includes the wait time
const waitTime = error.retryAfterMs || 2000; // fallback to 2 seconds

Automatic Retry Mechanisms in the SDK

The repository implements intelligent back-off logic directly in the polling utilities, reducing the boilerplate required in your application code.

The pollApimartTask Function

The pollApimartTask function in src/apimartClient.js (lines 44–46) automatically catches APIMART_RATE_LIMITED errors during status polling. When this occurs, the function pauses execution for the duration specified in error.retryAfterMs before attempting the next poll, ensuring you never exceed the API's suggested retry rate.

import { pollApimartTask, fetchPersonalTask } from './src/apimartClient.js';

async function waitForCompletion(taskId, apiKey) {
  const fetchTask = () => fetchPersonalTask(taskId, apiKey, 'en');
  
  // Automatically handles 429 errors with proper delays
  const result = await pollApimartTask(fetchTask, {
    intervalMs: 3000,
    maxAttempts: 120
  });
  
  return result;
}

Implementing Rate Limit Handling

While the SDK handles polling retries automatically, generation submissions and other direct API calls require explicit error handling in your application layer.

Basic Error Handling Pattern

Wrap your submission calls in try-catch blocks that specifically check for APIMART_RATE_LIMITED. Use the retryAfterMs property to delay your retry attempt.

import {
  submitPersonalGeneration,
  verifyPersonalApimartKey
} from './src/apimartClient.js';

async function generateImage(prompt, apiKey) {
  try {
    await verifyPersonalApimartKey(apiKey);
    const { taskId } = await submitPersonalGeneration(prompt, apiKey, 'en');
    return taskId;
  } catch (err) {
    if (err.code === 'APIMART_RATE_LIMITED') {
      console.warn(`Rate limited. Retry after ${err.retryAfterMs}ms`);
      await new Promise(res => setTimeout(res, err.retryAfterMs));
      return generateImage(prompt, apiKey); // Retry once
    }
    throw err;
  }
}

Exponential Backoff for Batch Processing

When submitting multiple generations in sequence, implement exponential backoff to prevent hammering the API. Start with a base delay and double the wait time after each consecutive rate-limit error, capping at 60 seconds.

import { submitPersonalGeneration } from './src/apimartClient.js';

async function submitWithBackoff(prompt, apiKey) {
  let backoff = 2000; // 2 seconds initial
  
  for (let attempt = 0; attempt < 5; attempt++) {
    try {
      return await submitPersonalGeneration(prompt, apiKey, 'en');
    } catch (e) {
      if (e.code !== 'APIMART_RATE_LIMITED') throw e;
      
      const waitMs = e.retryAfterMs || backoff;
      console.log(`Attempt ${attempt + 1} rate limited. Waiting ${waitMs}ms`);
      
      await new Promise(r => setTimeout(r, waitMs));
      backoff = Math.min(60000, backoff * 2); // Cap at 60 seconds
    }
  }
  throw new Error('Max retries exceeded due to rate limiting');
}

Best Practices for Production Use

Follow these guidelines to maintain optimal performance when interacting with APIMart:

  • Respect retryAfterMs: Never retry faster than the interval supplied by the API. The pollApimartTask implementation in src/apimartClient.js already adheres to this constraint.
  • Secure API Key Storage: The SDK stores keys under APIMART_KEY_STORAGE_KEY. Ensure this storage mechanism meets your application's security requirements.
  • Monitor Rate Limit Headers: Although the SDK abstracts the Retry-After header, you can extend fetchImpl to log X-RateLimit-Limit and X-RateLimit-Remaining for capacity planning.
  • Graceful UI Feedback: Surface user-friendly messages like "Please wait a moment before generating another image" when catching APIMART_RATE_LIMITED in frontend applications.
  • Abort Handling: When users navigate away during polling, catch APIMART_POLL_ABORTED errors (lines 99–105 in src/apimartClient.js) to clean up UI state properly.

Summary

  • APIMart returns HTTP 429 when exceeding per-key quotas, which the SDK converts to APIMART_RATE_LIMITED errors via apimartErrorCode in shared/apimart.js.
  • The retryAfterMilliseconds function parses the Retry-After header and attaches the value to error.retryAfterMs.
  • Automatic handling: pollApimartTask automatically pauses for the specified duration when encountering rate limits during polling loops.
  • Manual handling: Wrap submitPersonalGeneration calls in try-catch blocks and implement exponential backoff starting at 2 seconds, capped at 60 seconds.
  • Key files include shared/apimart.js for error utilities and src/apimartClient.js for high-level API methods with built-in retry logic.

Frequently Asked Questions

What error code does APIMart return when I hit the rate limit?

When you exceed your request quota, APIMart returns HTTP 429. The SDK's apimartErrorCode function in shared/apimart.js translates this into the string APIMART_RATE_LIMITED, allowing you to detect rate limiting programmatically without checking status codes directly.

How do I know how long to wait before retrying a failed request?

The SDK automatically parses the Retry-After response header using the retryAfterMilliseconds function (lines 81–90 in shared/apimart.js). This value is exposed as error.retryAfterMs on the thrown error object. If the header is missing, implement a fallback delay of 2000 milliseconds.

Does the SDK handle retries automatically?

The pollApimartTask function in src/apimartClient.js handles retries automatically for polling operations, pausing for error.retryAfterMs before continuing. However, submission functions like submitPersonalGeneration require you to implement your own retry logic using the error handling patterns shown in the examples above.

Where is the API key stored in this library?

According to the source code in shared/apimart.js, the SDK references APIMART_KEY_STORAGE_KEY for persistent storage of credentials. Ensure this storage location is secure and never expose the key in client-side logs or error messages.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →