# How the Vercel Function Proxies Requests to the GPT Image 2 API: Complete Implementation Guide

> Learn how the Vercel Function proxies requests to the GPT Image 2 API. This guide explains authentication, credit reservation, and image generation.

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

---

**The Vercel Function at [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js) acts as a secure, authenticated proxy that validates users, reserves generation credits, forwards requests to the GPT Image 2 API at `ciyuan.today`, and returns base64-encoded images to the client.**

The **freestylefly/awesome-gpt-image-2** repository implements a serverless architecture where all GPT Image 2 API calls are mediated through a Vercel Function. This design pattern protects upstream credentials, enforces per-user rate limits, and provides consistent error handling. The proxy integrates with Supabase for authentication and usage accounting, making it suitable for production multi-tenant applications.

## Core Responsibilities of the Vercel Function Proxy

The proxy handles four critical concerns before any image generation occurs. Each responsibility maps to specific functions in the codebase, with clear separation between authentication, authorization, upstream communication, and response formatting.

### Configuration and Authentication Validation

The function first verifies that required secrets are present and that the requesting user is authenticated. In [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js), the `isServerConfigured()` helper checks for `CIYUAN_API_KEY` and `SUPABASE_SERVICE_ROLE_KEY` environment variables. The `getAuthContext` function from [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js) validates the Bearer token against Supabase and returns the authenticated user or an anonymous context for GET requests.

Anonymous access is restricted to fetching current authentication status. All POST requests—which trigger actual image generation—require a valid Supabase JWT in the `Authorization` header.

### Generation Slot Reservation

Before calling the upstream API, the proxy reserves a generation slot to prevent abuse and enforce credit limits. Two code paths exist based on user type:

- **`reserveGeneration`** — Standard users trigger the `reserve_generation_usage` RPC in Supabase, which atomically checks available credits and increments counters.
- **`reserveCreditGeneration`** — Super-admin users bypass credit checks via a separate path, though usage is still logged.

The reservation returns a `reservationId`, the amount of credits to be deducted, and updated free-generation counters. This reservation is held in a pending state until the upstream call completes or fails.

### Upstream API Communication

The `generateImage(prompt)` function constructs the request to the GPT Image 2 service. It uses `process.env.CIYUAN_BASE_URL` (defaulting to `https://ciyuan.today`) and sends a POST to `/v1/images/generations`.

```js
// Request structure sent to ciyuan.today
{
  model: 'gpt-image-2',
  prompt: 'user-provided prompt',
  size: '1024x1024',    // or other supported dimensions
  quality: 'standard',  // or 'hd'
  format: 'b64_json'    // returns base64-encoded JPEG
}

```

The upstream API key is never exposed to clients—it resides solely in Vercel environment variables and is injected server-side via `Authorization: Bearer ${process.env.CIYUAN_API_KEY}`.

### Response Handling and Cleanup

Successful responses from the GPT Image 2 API contain a base64-encoded JPEG in `payload.data[0].b64_json`. The proxy converts this to a data-URL format (`data:image/jpeg;base64,...`) suitable for immediate use in `<img>` tags, then marks the reservation complete via `completeReservation`.

On any failure—whether network error, upstream timeout, or HTTP 429 rate limit—the proxy catches the exception and releases the reservation with an appropriate error code:

```js
const errorCode = error?.status === 429 ? 'UPSTREAM_BUSY' : 'GENERATION_FAILED';
await releaseReservation(auth.client, reservation.reservationId, errorCode);

```

This ensures credits are not deducted for failed generations and clients receive actionable error messages in a uniform JSON format.

## Complete Proxy Implementation

The full request lifecycle in [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js) demonstrates how these stages compose into a robust handler:

```js
export default async function handler(req, res) {
  // 1️⃣ Validate request method
  if (!['GET', 'POST'].includes(req.method)) {
    res.setHeader('Allow', 'GET, POST');
    return json(res, 405, { ok: false, error: 'METHOD_NOT_ALLOWED' });
  }

  // 2️⃣ Ensure server is configured
  if (!isServerConfigured()) {
    return json(res, 500, { ok: false, error: 'SERVER_NOT_CONFIGURED' });
  }

  // 3️⃣ Authenticate via Supabase
  const auth = await getAuthContext(req, {
    allowAnonymous: req.method === 'GET'
  });
  if (auth.error) {
    return json(res, 401, { ok: false, error: 'UNAUTHORIZED' });
  }

  // GET requests only fetch auth status
  if (req.method === 'GET') {
    return json(res, 200, { ok: true, user: auth.profile });
  }

  const { prompt, caseId } = req.body;

  // 4️⃣ Reserve a generation slot
  const reservation = auth.profile.isSuperAdmin
    ? await reserveCreditGeneration(auth.client, auth.user.id, caseId, prompt)
    : await reserveGeneration(auth.client, auth.user.id, caseId, prompt);

  if (!reservation.success) {
    return json(res, 429, { ok: false, error: 'INSUFFICIENT_CREDITS' });
  }

  try {
    // 5️⃣ Call the upstream GPT Image 2 API
    const image = await generateImage(prompt);

    // 6️⃣ Mark reservation complete and return result
    await completeReservation(auth.client, reservation.reservationId);

    return json(res, 200, {
      ok: true,
      image,
      user: profileFromReservation(auth.profile, reservation)
    });
  } catch (error) {
    const errorCode = error?.status === 429 ? 'UPSTREAM_BUSY' : 'GENERATION_FAILED';

    await releaseReservation(auth.client, reservation.reservationId, errorCode);

    return json(res, error?.status || 500, {
      ok: false,
      error: errorCode,
      message: error.message
    });
  }
}

```

## Client Integration Pattern

Front-end applications interact with the proxy through a simple fetch pattern. The client never handles raw API keys or manages credit accounting directly:

```js
fetch('/api/generate-image', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${accessToken}`   // Supabase JWT
  },
  body: JSON.stringify({
    prompt: 'A futuristic city at sunset',
    caseId: 12345
  })
})
  .then(r => r.json())
  .then(data => {
    if (data.ok) {
      // `data.image` is a data-URL ready for <img src=…>
      document.querySelector('img').src = data.image;
    } else {
      console.error('Generation error:', data.error);
    }
  });

```

## Key Files and Their Roles

| File | Purpose |
|------|---------|
| [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js) | Main Vercel Function implementing the proxy logic |
| [`api/_lib/supabase.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/supabase.js) | Authentication helpers, reservation management, and profile utilities |
| `scripts/vite-local-api.mjs` | Local development server that emulates Vercel Functions behavior |
| [`README.md`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/README.md) | Environment variable documentation and deployment instructions |

## Security and Architectural Guarantees

The Vercel Function proxy design provides specific protections:

- **Credential isolation**: The `CIYUAN_API_KEY` never leaves the serverless environment
- **Authenticated access**: All generation requests are tied to verified Supabase users
- **Usage enforcement**: The reservation system prevents credit overdraft and enables quota tracking
- **Graceful degradation**: 429 responses from the upstream API are caught and surfaced with `UPSTREAM_BUSY`, allowing client-side retry logic

## Summary

- The **Vercel Function proxy** at [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js) mediates all GPT Image 2 API traffic, protecting credentials and enforcing business logic
- **Four-stage processing**—configuration check, authentication, reservation, upstream call—ensures reliable quota management
- **Environment variables** `CIYUAN_API_KEY` and `SUPABASE_SERVICE_ROLE_KEY` are the only secrets required for deployment
- **Base64 image delivery** eliminates additional storage costs and enables immediate client-side rendering
- **Reservation cleanup** on failure guarantees users are not charged for unsuccessful generations

## Frequently Asked Questions

### What happens if the GPT Image 2 API returns a 429 rate limit?

The proxy catches HTTP 429 responses, releases the user's reservation with error code `UPSTREAM_BUSY`, and returns a 429 response to the client. This allows front-end code to implement exponential backoff retry logic without consuming user credits.

### Can anonymous users generate images through this proxy?

No. While anonymous GET requests are permitted to check authentication status, all POST requests that trigger actual image generation require a valid Supabase JWT. The `getAuthContext` function enforces this distinction based on request method.

### How does the proxy handle the API key without exposing it to clients?

The upstream `CIYUAN_API_KEY` is stored exclusively in Vercel environment variables and injected server-side by the `generateImage` function. Client-side code only sends its own Supabase JWT for authentication—the GPT Image 2 credentials never appear in browser network traffic or JavaScript bundles.

### What is the purpose of the reservation system in Supabase?

The reservation pattern provides atomic credit checking and usage accounting. By creating a pending reservation before calling the upstream API, the system guarantees that users cannot exceed their allocated credits even under race conditions. The reservation is either completed on success or released on failure, maintaining accurate billing state.