# How APIMart Integration Works for Server‑Side Image Generation in awesome‑gpt‑image‑2

> Learn how APIMart integration enables server-side image generation in awesome-gpt-image-2. Discover credential validation, credit reservation, prompt submission, and task polling.

- Repository: [苍何/awesome-gpt-image-2](https://github.com/freestylefly/awesome-gpt-image-2)
- Tags: how-to-guide
- Published: 2026-09-08

---

**The awesome‑gpt‑image‑2 repository delegates image generation to APIMart's specialized service by validating credentials through `getApimartConfig()`, reserving usage credits via Supabase, submitting prompts via `submitApimartGeneration()`, and polling task status with exponential back‑off until completion.**

The awesome‑gpt‑image‑2 project implements **APIMart integration** to offload computationally expensive image synthesis from the client to a dedicated server‑side service. This architecture uses a asynchronous task‑based workflow where the server manages credential validation, credit reservation, and status polling while the client handles transient state persistence and result retrieval. The integration spans four coordinated layers: environment‑based configuration, browser storage utilities, generation submission handlers, and status polling mechanisms.

## Configuration and Credential Management

Server‑side APIMart integration begins in **[`api/_lib/apimart.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/apimart.js)**, which centralizes all credential handling and HTTP client logic. The `getApimartConfig()` function reads the API key from `process.env.APIMART_API_KEY` and returns a configuration object containing `baseUrl`, `apiKey`, and a boolean `configured` flag:

```javascript
// api/_lib/apimart.js
export function getApimartConfig() {
  const apiKey = process.env.APIMART_API_KEY;
  const baseUrl = process.env.APIMART_API_URL || 'https://api.apimart.io';
  return {
    baseUrl,
    apiKey,
    configured: !!apiKey && apiKey.length > 0
  };
}

```

The `configured` flag acts as a guard throughout the codebase, ensuring APIMart API calls only execute when a valid key is present. This prevents runtime errors in environments where the service is not enabled.

## Client‑Side Storage and Helpers

For browser‑based interactions, **[`src/apimartClient.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/apimartClient.js)** provides utilities that persist user credentials and generation state across page reloads. The module defines storage keys `APIMART_KEY_STORAGE_KEY` and `APIMART_PENDING_STORAGE_KEY` to maintain the user’s personal API key and pending task IDs in `localStorage`:

- `saveStoredApimartKey(key)` encrypts and stores the user’s APIMart key.
- `getStoredApimartKey()` retrieves the decrypted key for authenticated requests.
- `pollApimartTask(fetchFn, options)` implements exponential back‑off polling with configurable `maxAttempts` and `intervalMs` parameters.

```javascript
// src/apimartClient.js
export async function pollApimartTask(fetchTaskFn, { maxAttempts = 100, intervalMs = 3000, onProgress }) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const result = await fetchTaskFn();
    if (onProgress) onProgress(result);
    
    if (result.status === 'succeeded' || result.status === 'failed') {
      return result;
    }
    
    await new Promise(resolve => setTimeout(resolve, intervalMs));
    intervalMs = Math.min(intervalMs * 1.5, 30000); // Exponential back‑off cap
  }
  throw new Error('Polling timeout');
}

```

The helper `isValidApimartTaskId(id)` validates task ID formats before initiating polling cycles, preventing unnecessary network requests.

## Server‑Side Generation Flow

The entry point for image generation resides in **[`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js)**. This handler validates incoming requests, manages credit reservations through Supabase, and orchestrates the APIMart submission:

1. **Credit Reservation**: The handler invokes the Supabase RPC `reserve_generation_usage` to atomically decrement the user’s available credits and create a reservation record.
2. **Task Submission**: If credits are available, the code calls `submitApimartGeneration()` from [`api/_lib/apimart.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/apimart.js), passing the prompt, language code, and an optional webhook URL pointing to `${process.env.APP_URL}/api/generation`.
3. **Persistence**: The returned `taskId` is stored in the `generation_reservations` table with the provider field set to `"apimart"`, linking the internal reservation to the external task.

```javascript
// api/generate-image.js (simplified)
import { getApimartConfig, submitApimartGeneration } from './_lib/apimart.js';

const config = getApimartConfig();
if (!config.configured) {
  throw new Error('SERVER_NOT_CONFIGURED');
}

const { taskId } = await submitApimartGeneration({
  apiKey: config.apiKey,
  prompt: 'A futuristic city at sunrise',
  language: 'en',
  webhook: `${process.env.APP_URL}/api/generation`
});

// Store taskId in generation_reservations table
await supabase.rpc('store_generation_task', { 
  reservation_id: reservationId, 
  external_task_id: taskId,
  provider: 'apimart'
});

```

If any step fails—whether due to upstream congestion, invalid configuration, or generation errors—the system releases the reservation with a specific `publicErrorCode` such as `UPSTREAM_BUSY`, `SERVER_NOT_CONFIGURED`, or `GENERATION_FAILED`.

## Task Polling and Status Retrieval

Clients retrieve generation status through the `/api/generation/status` endpoint implemented in **[`api/generation/status.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generation/status.js)**. This server handler invokes `getApimartTask()` from **[`api/_lib/apimart.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/apimart.js)** to query the current state of the external task:

```javascript
// api/_lib/apimart.js
export async function getApimartTask(taskId, apiKey) {
  const response = await fetch(`${getApimartConfig().baseUrl}/tasks/${taskId}`, {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });
  
  if (response.status === 429) {
    throw new Error('APIMART_RATE_LIMITED');
  }
  
  return normalizeApimartTask(await response.json());
}

```

The `normalizeApimartTask()` function (located in **[`api/_lib/generation.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/generation.js)**) standardizes APIMart’s response payload into a consistent format for the frontend, translating statuses like `processing`, `completed`, or `error` into unified terminal states.

On the client side, the `pollApimartTask()` utility repeatedly calls the status endpoint through a provided `fetchTask` function, handling `APIMART_RATE_LIMITED` responses with automatic retry logic and respecting `AbortSignal` for cancellation:

```javascript
// Client usage
import { pollApimartTask } from '../src/apimartClient.js';

const fetchTask = () => fetch(`/api/generation/status?taskId=${taskId}`)
  .then(r => r.json());

await pollApimartTask(fetchTask, {
  onProgress: (status) => console.log('Status:', status),
  maxAttempts: 100,
  intervalMs: 3000
});

```

## Error Handling and Reservation Management

The integration implements comprehensive error mapping to maintain clean separation between internal failures and user‑facing messages. When `submitApimartGeneration()` encounters upstream saturation, it throws errors mapped to `UPSTREAM_BUSY`. Configuration gaps trigger `SERVER_NOT_CONFIGURED`, while unexpected failures in the generation pipeline map to `GENERATION_FAILED`.

Each error path invokes `releaseReservation()` to refund credits and clean up the `generation_reservations` table, ensuring users are not charged for failed operations. The client‑side `pollApimartTask()` handles transient `APIMART_RATE_LIMITED` responses by deferring polling attempts without incrementing the retry counter, preventing premature timeout during high‑load periods.

## Summary

- **Credential Management**: [`api/_lib/apimart.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/apimart.js) centralizes API key reading via `getApimartConfig()`, exposing a `configured` flag to guard all downstream operations.
- **Client Persistence**: [`src/apimartClient.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/apimartClient.js) manages `localStorage` for user keys and pending tasks, providing `pollApimartTask()` with exponential back‑off.
- **Generation Flow**: [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js) reserves credits via Supabase RPC, submits tasks through `submitApimartGeneration()`, and stores the external `taskId` with provider `"apimart"`.
- **Status Polling**: [`api/generation/status.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generation/status.js) exposes normalized task states via `getApimartTask()`, while client utilities poll until terminal statuses (`succeeded`, `failed`) are reached.
- **Error Handling**: Specific error codes (`UPSTREAM_BUSY`, `SERVER_NOT_CONFIGURED`, `GENERATION_FAILED`) trigger reservation releases, protecting user credits against upstream failures.

## Frequently Asked Questions

### How does awesome‑gpt‑image‑2 store APIMart credentials securely?

The server stores the primary APIMart API key exclusively in environment variables accessed through `process.env.APIMART_API_KEY` within [`api/_lib/apimart.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/apimart.js). For client‑side personal keys, [`src/apimartClient.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/src/apimartClient.js) persists data in `localStorage` under `APIMART_KEY_STORAGE_KEY`, using encryption utilities to obfuscate the key before storage.

### What happens if the APIMart service is rate‑limited during generation?

When `getApimartTask()` receives a 429 response, it throws an `APIMART_RATE_LIMITED` error. The client‑side `pollApimartTask()` helper catches this condition and implements exponential back‑off, increasing the polling interval up to a 30‑second cap while maintaining the active connection until the rate limit clears.

### How does the system prevent charging users for failed generations?

Before submitting any request to APIMart, [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js) reserves a credit via the Supabase RPC `reserve_generation_usage`. If `submitApimartGeneration()` fails or the task subsequently errors, the code invokes `releaseReservation()` with a specific `publicErrorCode` (e.g., `GENERATION_FAILED` or `UPSTREAM_BUSY`), which atomically refunds the reserved credit and removes the pending reservation record.

### Which component normalizes APIMart task responses for the frontend?

The **[`api/_lib/generation.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/generation.js)** module contains `normalizeApimartTask()`, which transforms raw APIMart API responses into a standardized schema consumed by the client. This normalization ensures that status fields, error messages, and result URLs maintain consistent naming conventions regardless of upstream API changes.