Skip to contentLimited-time offer: code LAUNCH50 — 50% off your first month

API reference

Full schema for the public REST API. Available on Pro and Max plans. Issue a key at /account/api.

Prefer Postman? Download our v2.1 collection — paste your gimg_… key into the apiKey variable.

Auth

All endpoints take a Bearer token in the Authorization header. Tokens always begin with gimg_.

Authorization: Bearer gimg_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Rate limits

600 requests / hour / key, max 5 in flight. Every response includes:

  • X-RateLimit-Limitfixed at 600
  • X-RateLimit-Remainingcalls left in the current window
  • X-RateLimit-Resetepoch seconds when the window resets
  • Retry-Afterseconds until the next allowed call (only on 429)

Idempotency

Pass Idempotency-Key on POST requests. Sending the same key twice returns the existing generation row instead of double-charging credits.

POST/api/v1/generate

Submit a text-to-image OR image-edit generation. Returns immediately with a generationId; poll /api/v1/generations/:id for the result.

Body

  • promptstring ≤ 4000 charsrequired

    Natural-language description. Photographer terminology (camera, lens, lighting) helps.

  • type"text2img" | "edit"

    Defaults to 'text2img'. 'edit' requires inputImageKeys.

  • size"1024x1024" | "1024x1536" | "1536x1024"

    Aspect ratio. Defaults to 1024x1024.

  • quality"low" | "medium" | "high"

    Defaults to medium. high = HD 2K. low is Fast (1cr).

  • n1–4

    Number of variations. Defaults to 1.

  • inputImageKeysstring[] (max 4)

    R2 keys returned by /api/v1/upload. Required when type=edit.

Responses

  • 202 Acceptedjson

    { "generationId": "...", "status": "queued" }

  • 400 Bad Requestjson

    Invalid body. The error includes a Zod validation message.

  • 401 Unauthorizedjson

    Missing or invalid Bearer key.

  • 402 Payment Requiredjson

    Insufficient credits or monthly compute cap reached.

  • 403 Forbiddenjson

    Pro/Max plan required.

  • 422 Unprocessablejson

    Prompt blocked by content policy.

  • 429 Too Many Requestsjson

    Rate limit reached. See Retry-After.

POST/api/v1/upload

Get a presigned R2 PUT URL for uploading an input image. Two-step: this returns the URL, you PUT bytes to it directly.

Body

  • filenamestring ≤ 200required

    Display name; not used for storage.

  • contentType"image/png" | "image/jpeg" | "image/webp"required

    Must be exactly one of these three.

  • sizenumber (bytes ≤ 10 MB)required

    File size you intend to PUT. Used for validation.

Response (200)

  • urlstring

    Presigned PUT URL, expires in 5 minutes.

  • keystring

    R2 key — pass this in inputImageKeys when calling /api/v1/generate.

GET/api/v1/generations/:id

Poll the status of a generation. Returns immediately with current state.

Response (200)

  • idstring

    The generation id.

  • status"queued" | "running" | "succeeded" | "failed" | "blocked"

    'blocked' = content moderation rejected the input or output (credits refunded).

  • typestring

    text2img | edit | upscale | …

  • outputsArray<{ png, webp, width, height }>

    Populated when status=succeeded. URLs are public, immutable, CDN-cached.

  • errorstring | null

    Populated when status=failed or status=blocked.

  • costCreditsnumber

    Credits charged (refunded if blocked or failed).

  • createdAt / completedAtISO 8601

    Timestamps.

Outbound webhooks

Skip polling: register HTTPS endpoints to receive generation.succeeded and generation.failed events as they happen. Manage via /api/account/webhooks.

Register

curl -X POST https://gptimage2.plus/api/account/webhooks \
  -H "Cookie: <your session cookie>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/hooks/gptimg",
    "events": ["generation.succeeded", "generation.failed"],
    "label": "Production app"
  }'
# → { "id": "...", "secret": "whsec_..." }   ← copy this, shown ONCE

Event payload

POST https://your-app.com/hooks/gptimg
X-Gptimg-Event: generation.succeeded
X-Gptimg-Signature: <hex sha256 hmac of body>
X-Gptimg-Delivery: <uuid for dedup>
Content-Type: application/json

{
  "event": "generation.succeeded",
  "data": {
    "generationId": "...",
    "type": "text2img",
    "status": "succeeded",
    "outputs": [{ "png": "...", "webp": "...", "width": 1024, "height": 1024 }],
    "createdAt": "2026-04-26T01:23:45.000Z",
    "completedAt": "2026-04-26T01:23:50.000Z"
  }
}

Verify the signature

// Node example
import crypto from "crypto";
const expected = crypto
  .createHmac("sha256", process.env.WEBHOOK_SECRET)
  .update(rawBody)
  .digest("hex");
const ok = crypto.timingSafeEqual(
  Buffer.from(expected),
  Buffer.from(req.headers["x-gptimg-signature"])
);

Timeout: 5s per attempt. We retry non-2xx responses up to 3 times with exponential backoff (30s → 2m → 10m). After 8 consecutive failures across attempts, the webhook is auto-disabled — re-enable from /account/webhooks.