API Reference

All endpoints are relative to https://api.pixelengine.ai/functions/v1. Every request requires an API key or OAuth access token.

Idempotent retries

A submit request can time out before its response arrives, leaving you unsure whether the job was created. To make retries safe, send an Idempotency-Key header with any request that creates jobs: /animate, /animate-batch, /generate-image, /keyframes, /pixelate and /remove-background. Choose a new key for each logical request (a UUID, or an ID from your own system) and send the same key with every retry of it.

Request
POST /animate
Authorization: Bearer pe_sk_...
Idempotency-Key: 8f14e45f-ceea-4672-a7a3-6f0e1b2c3d4e
Content-Type: application/json

{ "image": "...", "prompt": "walk cycle, facing right" }

The first request with a key creates the job as usual. A later request with the same key creates nothing and charges nothing: it returns the original job with "replayed": true and that job's current status, even if the first request is still being processed. error is null unless that job has failed.

Replayed response
{
  "api_job_id": "3f6c2b1e-...",
  "status": "pending",
  "error": null,
  "replayed": true
}
RuleDetail
Format1 to 255 printable ASCII characters. Anything else is a 400 invalid_idempotency_key.
ScopeKeys belong to the credential that sent them: one API key, or one app's access token for one user. The same key from a different API key is a different key.
Rejected submitsIf the original request was rejected with an error response (for example 400, 402 insufficient_credits or a 500 from us), the key is freed and a retry with it creates a new job. Rejected submits are never charged.
Failed jobsIf a replay comes back with status failure, the job was accepted and failed later, so it was charged only as any failed job is (nothing, except a batch's anchor fee; see /animate-batch Billing). Submit again with a new key. The same applies if your first request never got a response and the job never started: it fails within minutes and keeps its key.
EndpointsA key belongs to the endpoint it was first sent to. Sending it to a different endpoint is a 409 idempotency_key_reused.
BatchesA replayed /animate-batch returns the original batch_id and every api_job_id.
LifetimeA key stays tied to its job permanently. Don't reuse a key for a different request to the same endpoint: you will get the old job back, marked replayed.
Without the headerEvery request creates a new job, as before.

In the rare case that a retry arrives just as the original fails, the retry gets a 409 idempotency_key_in_use; send it again and it will run.

GET/balance

Returns the authenticated user's current credit balance.

Response

Response 200
{
  "monthly_balance": 1200,
  "purchased_balance": 500,
  "total_balance": 1700,
  "reserved": 20,
  "available": 1680
}
FieldTypeDescription
monthly_balanceintegerCurrent monthly credit pool.
purchased_balanceintegerCurrent purchased credit pool.
total_balanceintegermonthly_balance + purchased_balance.
reservedintegerCredits held by in-flight jobs (not yet deducted).
availableintegerCredits available for new jobs (total_balance − reserved, floor 0).

Errors

HTTPCodeCause
401unauthorizedInvalid or inactive API key, or expired access token.
GET/billing

Returns a billing summary for the authenticated user over a given date range, plus a current balance snapshot. Useful for tracking credit spend and understanding usage over time. For the individual charges behind these totals, use GET /billing/entries.

Query parameters

ParameterRequiredDefaultDescription
start_dateNo30 days before end_dateInclusive start date in YYYY-MM-DD format (UTC).
end_dateNoTodayInclusive end date in YYYY-MM-DD format (UTC).

The maximum period is 365 days.

Response

Response 200
{
  "period": {
    "start_date": "2026-03-01T00:00:00.000Z",
    "end_date": "2026-03-31T23:59:59.999Z"
  },
  "totals": {
    "credits_used": 1240,
    "credits_added": 1200,
    "refunds": 40,
    "adjustments": 0,
    "net_change": -80,
    "jobs_charged": 62
  },
  "balance": {
    "monthly_balance": 920,
    "purchased_balance": 500,
    "total_balance": 1420,
    "reserved": 20,
    "available": 1400
  }
}
FieldTypeDescription
period.start_datestringISO timestamp of the period start.
period.end_datestringISO timestamp of the period end.
totals.credits_usedintegerTotal credits charged (sum of debit entries).
totals.credits_addedintegerTotal credits added (purchases, monthly refresh, etc.).
totals.refundsintegerTotal credits taken back out of the wallet (for example a refunded purchase). These reduce your balance.
totals.adjustmentsintegerCredits added by hand by Pixel Engine support.
totals.net_changeintegercredits_added + adjustments − refunds − credits_used. Positive means credits gained, negative means net spend.
totals.jobs_chargedintegerNumber of jobs that consumed credits in the period.
balanceobjectCurrent balance snapshot — same shape as GET /balance.

Errors

HTTPCodeCause
400invalid_requestInvalid date format, start_date after end_date, or period exceeds 365 days.
401unauthorizedInvalid or inactive API key, or expired access token.
404invalid_requestNo wallet found for the authenticated user.
500internal_errorServer-side failure.
GET/billing/entries

Returns the authenticated user's credit history line by line, newest first: every charge, credit purchase, monthly refresh, refund and adjustment. Each charge carries the api_job_id it paid for, so you can match spend to your own records. Results are paged with a cursor; there is no limit on how far back you can go.

Query parameters

ParameterRequiredDefaultDescription
limitNo50Entries per page, 1–200.
start_dateNoNoneOnly entries on or after this day, YYYY-MM-DD (UTC).
end_dateNoNoneOnly entries on or before this day, YYYY-MM-DD (UTC).
typeNoAll typesComma-separated: debit, credit, refund, adjustment.
cursorNoNonenext_cursor from the previous page, unchanged. Keep the other parameters the same between pages.

Response

Response 200
{
  "entries": [
    {
      "id": 220470,
      "created_at": "2026-10-19T20:37:15.60985+00:00",
      "type": "debit",
      "amount": 20,
      "change": -20,
      "description": "api animation generation",
      "api_job_id": "b005abb6-32a9-428e-b124-775c8dcd5d82",
      "job_id": null,
      "balance_after": { "monthly": 2085, "purchased": 10978, "total": 13063 }
    }
  ],
  "has_more": true,
  "next_cursor": "eyJ0IjoiMjAyNi0xMC0xOVQyMDozNzoxNS42MDk4NSswMDowMCIsImkiOjIyMDQ3MH0"
}
FieldTypeDescription
idintegerLedger entry ID.
created_atstringISO timestamp of the entry.
typestringdebit (a job was charged), credit (purchase, plan refresh, auto-refill), refund (credits taken back out, for example a refunded purchase), adjustment (added by support).
amountintegerCredits moved, always positive.
changeintegerSigned effect on your balance: negative for debit and refund, positive otherwise.
descriptionstring | nullHuman-readable description.
api_job_idstring | nullThe API job this entry charged, as used by GET /jobs.
job_idstring | nullThe web-app job this entry charged.
balance_afterobject | nullBalance right after this entry (monthly, purchased, total). Null on older entries.
has_morebooleanWhether older entries remain.
next_cursorstring | nullPass as cursor to fetch the next (older) page. Null on the last page.

Errors

HTTPCodeCause
400invalid_requestInvalid limit, date, type or cursor, or start_date after end_date.
404not_foundUnknown path under /billing.
401unauthorizedInvalid or inactive API key, or expired access token.
404invalid_requestNo wallet found for the authenticated user.
500internal_errorServer-side failure.
POST/animate

Submits an image-to-video generation job. The endpoint supports both pixel art animation and general-purpose frame animation. Returns immediately with a job ID; generation runs asynchronously. Poll GET /jobs to track progress.

Cost: 20 credits on pixel-engine-v1.1 and frame-engine-v1.1; 26 credits on pixel-engine-v1.5, which is slower to start.

Request body

JSON
{
  "image": "<base64-encoded image or data URL>",
  "prompt": "a character walking through a forest",
  "model": "pixel-engine-v1.1",
  "negative_prompt": "blurry, distorted",
  "pixel_config": { "colors": 16 },
  "output_frames": 8,
  "seed": 12345,
  "output_format": "webp",
  "matte_color": "#808080",
  "transform": {
    "canvas_size": 128,
    "fill_method": "edge-extend",
    "offset_x": 0,
    "offset_y": 0
  }
}
FieldTypeRequiredDescription
imagestringYesBase64-encoded image, or a data URL (data:image/png;base64,…). Accepted formats depend on model. See image constraints below.
promptstringYesNon-empty text describing the desired animation.
modelstringNoWhich animation model to use. Defaults to "pixel-engine-v1.1". See Models below.
render_modestringModel-dependent"pixel" or "detailed". Required for pixel-engine-v1.5. The -engine- models imply their own: sending the matching value is accepted, a contradicting one is rejected. See Models below.
negative_promptstringNoWhat to avoid in the generation. Not supported by pixel-engine-v1.5 — see Models below.
pixel_configobjectNoPixel art color config. Defaults to { "colors": 24 }. Only allowed in pixel mode. See PixelConfig below.
output_framesintegerNoNumber of animation frames. Default: 8. Range and whether odd counts are allowed depend on the model — see Models below.
seedintegerNoSeed for reproducibility. Integer between 1 and 9,999,999,999. If omitted, a random seed is used.
output_formatstringNo"webp" (default), "gif", or "spritesheet".
matte_colorstringNo6-character hex color (e.g. "#ff0000") used to flatten any alpha channel before processing. Default: "#808080".
transformobjectNoPlace the image on a larger square canvas before animating — resize, offset, flip, and fill the background. See Transform below. Omit it to use the image as-is.
To remove the background from the output animation, run it through POST /remove-background after generation completes.

Models

If model is omitted, the API defaults to "pixel-engine-v1.1".

Modelrender_modeBest forInput formatsImage sizeoutput_frames
pixel-engine-v1.5"pixel"Pixel art sprites and charactersPNGUp to 320×320 px3–16
pixel-engine-v1.5"detailed"Illustrations and non-pixel imagesPNG or JPEG256×256 px to 2048×2048 px3–16
pixel-engine-v1.1—Pixel art. Often better for loops, walk cycles and idlesPNGUp to 256×256 px2–16 (even)
frame-engine-v1.1—Illustrations and non-pixel imagesPNG or JPEG256×256 px to 2048×2048 px2–24 (even)
pixel-engine-v1.5 requires render_mode. The two -engine- models are the same weights down two different pipelines, which is why there are two names for one model; from v1.5 onward a model takes an explicit render_mode instead. The older names stay supported and imply their own mode — sending a render_mode that contradicts one is rejected with 400 invalid_request.
pixel_config is rejected with 400 invalid_request outside pixel mode — that is "frame-engine-v1.1", or pixel-engine-v1.5 with render_mode: "detailed".
negative_prompt is rejected for pixel-engine-v1.5 when non-empty. The model runs CFG-distilled at a guidance scale of 1.0, so there is no unconditional branch for a negative prompt to steer — accepting one and ignoring it would be worse than saying so. Omit the field or send an empty string.
On pixel-engine-v1.5, prompts under 15 words are automatically rewritten into the descriptive style the model was trained on before generation. The model was trained on 30–50 word captions and short prompts produce semantically wrong results — the wrong action, not a rougher version of the right one. The prompt actually used is returned on the job. Send a longer prompt to keep your own wording, or call /enhance-prompt yourself to see the rewrite first.

PixelConfig

pixel_config is only valid in pixel mode — that is "pixel-engine-v1.1", model omitted (which defaults to it), or "pixel-engine-v1.5" with render_mode: "pixel". Provide one of two modes — never both. If pixel_config is omitted entirely, it defaults to count mode with 24 colors.

Count mode — cluster output to N colors
{ "colors": 24 }
Palette mode — force specific colors
{ "palette": ["#ffaa00", "#223344", "#ffffff"] }
FieldTypeConstraints
colorsinteger2–256.
palettestring[]Array of hex color strings (e.g. "#ff0000")
Palette mode is an experimental feature. Forcing a specific palette can produce worse results than letting the model choose its own colors. If quality matters more than exact color matching, prefer count mode (colors).

Image constraints

Data URL prefixes are stripped automatically.

  • Max decoded size: 5 MB for both models.
  • Aspect ratio: Between 1:2 and 2:1 for both models.
  • Alpha: flattened onto matte_color before processing.
ModelFormatDimensionsNotes
pixel-engine-v1.1PNG onlyEach axis must be 256 px or smallerDesigned for pixel art input.
frame-engine-v1.1PNG or JPEGEach axis must be between 256 px and 2048 pxBoth width and height must be at least 256 px.

output_frames rules differ by model. On "pixel-engine-v1.5" it is any integer from 3 to 16 — odd counts included. On the -engine- models it must be an even integer starting at 2, with a maximum of 16 for "pixel-engine-v1.1" and 24 for "frame-engine-v1.1".

Response

Response 200
{
  "api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "queued",
  "error": null
}

Errors

HTTPCodeCause
400invalid_requestMissing or invalid field (prompt, image format, output_frames, etc.).
400image_too_largeImage exceeds 5 MB decoded.
401unauthorizedInvalid or inactive API key, or expired access token.
402insufficient_creditsNot enough available credits.
405method_not_allowedRequest method is not POST.
500internal_errorServer-side failure.

Common validation failures include unsupported image formats for the chosen model, pixel_config being sent outside pixel mode, images smaller than 256×256 px in detailed mode, and out-of-range output_frames values — or odd ones on the -engine- models, which take even counts only.

POST/animate-batch

Submits multiple image-to-video jobs in a single request (2–10 sub-jobs). The whole batch runs sequentially inside one warm GPU container, which amortizes the cold-start cost across every sub-job — so a batch is cheaper per animation than submitting the same jobs one at a time through POST /animate. Returns immediately with a batch ID and one job ID per sub-job; generation runs asynchronously. Poll GET /batch-jobs to track the whole batch at once.

Cost: The first sub-job (the anchor) costs 20 credits; each additional sub-job costs 12 credits. A batch of N sub-jobs costs 20 + 12 × (N − 1) credits — e.g. 5 jobs = 68 credits vs. 100 if submitted individually.

Request body

JSON
{
  "jobs": [
    {
      "image": "<base64-encoded image or data URL>",
      "prompt": "a character walking through a forest",
      "model": "pixel-engine-v1.1",
      "pixel_config": { "colors": 16 },
      "output_frames": 8
    },
    {
      "image": "<base64-encoded image or data URL>",
      "prompt": "a character drawing its sword",
      "model": "pixel-engine-v1.1"
    }
  ]
}
FieldTypeRequiredDescription
jobsarrayYesBetween 2 and 10 sub-job objects. Each object accepts the same fields as the POST /animate request body (image, prompt, model, pixel_config, output_frames, seed, output_format, matte_color).
All sub-jobs must use the same pipeline. Every sub-job's model must map to the same engine — either all "pixel-engine-v1.1" or all "frame-engine-v1.1". Mixing pixel and frame models in one batch returns 400 invalid_request.
"pixel-engine-v1.5" is not available on this endpoint and returns 400 invalid_request, even when every sub-job uses it. It has no batch service of its own — use POST /animate per job.

Image constraints

Each sub-job image follows the same per-model rules as POST /animate (format, dimensions, aspect ratio, alpha handling). In addition:

  • Max per image: 5 MB decoded.
  • Max total: 30 MB decoded across all sub-jobs combined.

Billing

A separate hold is placed for each sub-job at submission. The anchor (the first sub-job) pays a non-refundable cold-start fee: it is charged on both success and failure, and is only released if the batch is cancelled before the anchor runs. Every other sub-job follows the normal hold rules — released on failure or cancellation, charged only on success.

Response

Response 200
{
  "batch_id": "b1f2c3d4-5678-90ab-cdef-1234567890ab",
  "api_job_ids": [
    "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "9c858901-8a57-4791-81fe-4c455b099bc9"
  ],
  "status": "queued"
}
FieldTypeDescription
batch_idstringIdentifier for the whole batch. Pass to GET /batch-jobs or POST /cancel.
api_job_idsstring[]One job ID per sub-job, in submission order (index 0 is the anchor). Each is an ordinary job ID — poll a single sub-job with GET /jobs?id=<api_job_id> or cancel one with POST /cancel.
statusstringAlways "queued" on a successful submission.
If submission fails partway (e.g. a credit hold or upload error after some rows were created), the entire batch is marked failed and any holds are released — you are never charged for a batch that never started.

Errors

HTTPCodeCause
400invalid_requestjobs missing or not an array, fewer than 2 or more than 10 sub-jobs, mixed pixel/frame pipelines, or a single sub-job is invalid (the message is prefixed with jobs[i]:).
400image_too_largeA sub-job image exceeds 5 MB decoded.
400payload_too_largeTotal decoded image bytes across all sub-jobs exceed 30 MB.
401unauthorizedInvalid or inactive API key, or expired access token.
402insufficient_creditsNot enough available credits to cover the full batch.
405method_not_allowedRequest method is not POST.
500internal_errorServer-side failure.
POST/keyframes

Submits a keyframe-conditioned generation job. Provide one or more reference images at specific frame positions, and the model interpolates between them to produce a full animation. Supports both pixel art and general-purpose output. Returns immediately with a job ID; generation runs asynchronously. Poll GET /jobs to track progress.

Cost: 24 credits.

Request body

JSON
{
  "prompt": "a character walking cycle",
  "render_mode": "pixel",
  "total_frames": 8,
  "frames": [
    { "index": 0, "image": "<base64>", "strength": 1.0 },
    { "index": 4, "image": "<base64>", "strength": 0.8,
      "placement": { "offset_x": 4, "offset_y": -2, "flip_h": true } },
    { "index": 7, "image": "<base64>", "strength": 1.0 }
  ],
  "transform": { "canvas_size": 128, "fill_method": "edge-extend" },
  "negative_prompt": "blurry, distorted",
  "pixel_config": { "colors": 24 },
  "seed": 12345,
  "output_format": "webp",
  "matte_color": "#808080"
}
FieldTypeRequiredDescription
promptstringYesNon-empty text describing the desired animation.
render_modestringYes"pixel" or "detailed". Determines image format constraints and post-processing. See Render modes below.
total_framesintegerYesTotal number of output frames. Integer between 3 and 20.
framesarrayYesBetween 1 and total_frames keyframe objects. Each provides a reference image at a specific position in the output sequence.
frames[].indexintegerYesFrame position in the output sequence. Must be in range [0, total_frames − 1]. Each index may only appear once.
frames[].imagestringOne ofBase64-encoded image, or a data URL. Mutually exclusive with frames[].image_url.
frames[].image_urlstringOne ofHTTPS URL to download the keyframe image. Mutually exclusive with frames[].image.
frames[].strengthnumberNoConditioning strength for this keyframe. Float between 0.0 and 1.0. Default: 1.0.
frames[].placementobjectNoWhere this keyframe's image sits on the shared canvas: offset_x, offset_y, flip_h, flip_v. Requires transform. It has no size or fill field — every keyframe shares one canvas.
transformobjectNoThe shared canvas every keyframe is placed on. See Transform below. Supplying it also lifts the same-dimensions requirement on your input images.
negative_promptstringNoWhat to avoid in the generation.
pixel_configobjectNoPixel art color config. Defaults to { "colors": 24 }. Only allowed for render_mode: "pixel". See PixelConfig above.
seedintegerNoSeed for reproducibility. Integer between 1 and 9,999,999,999.
output_formatstringNo"webp" (default), "gif", or "spritesheet".
matte_colorstringNo6-character hex color (e.g. "#ff0000") used to flatten any alpha channel before processing. Default: "#808080".
To remove the background from the output animation, run it through POST /remove-background after generation completes.

Render modes

ModeInput formatsImage size
pixelPNG onlyUp to 256×256 px per axis
detailedPNG or JPEG256–2048 px per axis
pixel_config is rejected for render_mode: "detailed" with 400 invalid_request.

Image constraints

Data URL prefixes are stripped automatically.

  • Max per image: 10 MB decoded.
  • Max total: 20 MB across all keyframes combined.
  • Aspect ratio: Between 1:2 and 2:1.
  • Consistency: All keyframe images must have the same dimensions — unless you supply a transform, which places them all on one shared canvas and lets their input sizes differ.
  • Alpha: flattened onto matte_color before processing.

Response

Response 200
{
  "api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "queued",
  "error": null
}

Errors

HTTPCodeCause
400invalid_requestMissing or invalid field (prompt, render_mode, frames, dimensions, etc.).
400image_too_largeSingle image exceeds 10 MB or total exceeds 20 MB.
400image_fetch_failedAn image_url could not be downloaded or timed out.
401unauthorizedInvalid or inactive API key, or expired access token.
402insufficient_creditsNot enough available credits.
405method_not_allowedRequest method is not POST.
500internal_errorServer-side failure.

Transform

An optional transform places your image on a larger square canvas before generation — useful when your subject is cropped tight and you want room around it for the animation to move into, or when you want a consistent output size regardless of what you sent. Accepted by POST /animate and POST /keyframes. Omit it and the image is used as-is.

JSON
{
  "transform": {
    "canvas_size": 128,
    "fill_method": "edge-extend",
    "fill_color": "#808080",
    "offset_x": 0,
    "offset_y": 0,
    "flip_h": false,
    "flip_v": false
  }
}
FieldTypeRequiredDescription
canvas_sizeintegerYesEdge length of the square output, in pixels. Capped by the model: 320 for "pixel-engine-v1.5" with render_mode: "pixel", 256 for "pixel-engine-v1.1" and for POST /keyframes with render_mode: "pixel", and 2048 in detailed mode. Asking for more returns 400 rather than silently shrinking your output.
fill_methodstringNoHow to fill the space around your image. "edge-extend" (default) stretches the outermost pixels outward, "solid" paints fill_color, and "transparent" leaves it clear.
fill_colorstringNo6-character hex color, used only when fill_method is "solid". Default: "#808080".
offset_xintegerNoHorizontal shift from center, in pixels. Positive moves right. Default: 0.
offset_yintegerNoVertical shift from center, in pixels. Positive moves down. Default: 0.
flip_hbooleanNoMirror the image horizontally. Default: false.
flip_vbooleanNoMirror the image vertically. Default: false.
canvas_size is an absolute pixel size, not a multiplier. Your output is exactly that many pixels square, whatever you sent in.

On /keyframes, the object splits in two

Every keyframe has to land on the same canvas — the interpolation model requires it. So transform carries only the shared parts (canvas_size, fill_method, fill_color), and each keyframe positions itself with its own placement:

JSON
{
  "transform": { "canvas_size": 128, "fill_method": "solid", "fill_color": "#1a1a2e" },
  "frames": [
    { "index": 0, "image": "<base64>",
      "placement": { "offset_x": 4, "offset_y": -2, "flip_h": true } },
    { "index": 7, "image": "<base64>",
      "placement": { "offset_x": 0, "offset_y": 6 } }
  ]
}

A placement accepts only offset_x, offset_y, flip_h and flip_v — there is no per-frame size or fill, so one keyframe can never end up on a different canvas than the rest. Any placement you omit defaults to centered and unflipped.

Supplying a transform on /keyframes also lifts the usual requirement that every keyframe image share the same dimensions — they all end up on the shared canvas, so their input sizes no longer have to match.
POST/generate-image

Generates a still pixel-art image from a text prompt. Optionally accepts a reference image (base64 or URL) — when provided, the model edits/transforms the reference instead of generating from scratch (image-to-image). Returns immediately with a job ID; generation runs asynchronously. Poll GET /jobs to track progress and retrieve the output PNG.

Cost: Varies by model (6–36 credits). See Models below.

Request body

JSON — text-to-image
{
  "prompt": "a knight standing in a torchlit dungeon",
  "model": "nb_flash_2_1",
  "pixel_config": { "colors": 24 },
  "seed": 12345
}
JSON — image-to-image (with reference)
{
  "prompt": "the same character, now wearing a red cape",
  "model": "oai_gpt25_high",
  "image": "<base64-encoded image or data URL>",
  "pixel_config": { "palette": ["#1a1a1a", "#c83232", "#f0c878", "#ffffff"] }
}
JSON — with reference images
{
  "prompt": "the knight from the first reference holding the sword from the second",
  "model": "nb_flash_2_1",
  "reference_images": [
    { "image_url": "https://example.com/knight.png" },
    { "image": "<base64-encoded image or data URL>" }
  ],
  "pixel_config": { "colors": 24 }
}
FieldTypeRequiredDescription
promptstringYesNon-empty text describing the desired image (or, in image-to-image mode, the desired edit).
modelstringNoWhich generation model to use. Defaults to "nb_flash". See Models below.
pixel_configobjectYesPixel art color config — required on this endpoint (all outputs are pixel art). Provide either colors or palette, never both. See PixelConfig below.
imagestringNoOptional image to edit. Base64-encoded image or a data URL (data:image/png;base64,…). PNG or JPEG. Mutually exclusive with image_url. When omitted, the request runs as text-to-image.
image_urlstringNoHTTPS URL to download the image to edit. Mutually exclusive with image.
reference_imagesarrayNoImages the model draws from without editing them: a character to keep consistent, an object to include, a style to match. Separate from the image to edit. Each entry is { "image": "<base64>" } or { "image_url": "https://…" }, PNG or JPEG, up to 5 MB each. Nano Banana models (nb_*) take up to 14 images in total and GPT Image models (oai_*) 16, counting image when you send one. All images together up to 20 MB. Not accepted by pe_image_v1. Say in your prompt how each should be used. No extra charge.
seedintegerNoSeed for reproducibility. Integer between 1 and 9,999,999,999. Only honored by OpenAI models (oai_*) where supported; Google models (nb_*) accept the field but ignore it. pe_image_v1 uses it, but the same seed on a different GPU or after a deploy can give a different draw — treat it as a hint, not a guarantee.
widthintegerpe_image_v1 onlySprite width in pixels, 16–128. Required with pe_image_v1, rejected for other models. Above 64 px on the longest side, sizes must be even; an odd value is rounded up and the response carries a notice and the delivered size. The longest side can be at most 4× the shortest, measured on the drawn size (so at 65–128 px the shortest side is at least 18).
heightintegerpe_image_v1 onlySprite height in pixels, same rules as width.
remove_backgroundbooleanNope_image_v1 only; default true. false delivers the sprite with its flat grey ground still in (opaque PNG). Not accepted for other models.
enhance_prompt"auto" | booleanNope_image_v1 only; default "auto": a prompt of 15 words or fewer is rewritten into a fuller description before drawing. false uses your words exactly — choose it to get the same sprite again from the same prompt and seed. true rewrites any prompt. Not accepted for other models.
Providing both image and image_url returns 400 invalid_request. Omitting both is valid — the request runs as text-to-image.

Models

If model is omitted, the API defaults to "nb_flash". Cost is a flat per-model charge (no surcharge for the image to edit or for references).

ModelProviderDescriptionCost
pe_image_v1Pixel Engine (own model)Draws a sprite at the exact width and height you ask for (16-128 px), on its pixel grid, background removed. Text-to-image only; requires width and height. Above 64 px, sizes must be even (odd sizes are rounded up and the response says so). remove_background: false keeps the flat grey ground.6 credits
nb_flash_2_1Google (Nano Banana 2.1)Recommended for pixel art, and the best at following reference_images and at edits. The update to Nano Banana 2.12 credits
nb_proGoogle (Nano Banana Pro)Highest detail on complex prompts.36 credits
oai_gpt25_lowOpenAI (GPT Image 2.5 — Low)Cheapest and fastest; quick drafts.6 credits
oai_gpt25_highOpenAI (GPT Image 2.5 — High)Good for rotations, poses and props.12 credits
oai_gpt25_maxOpenAI (GPT Image 2.5 — Max)Top detail on complex prompts and edits; slower.36 credits
oai_gpt2_lowOpenAI (GPT Image 2 — Low)Legacy. Same price as oai_gpt25_low; prefer that.6 credits
oai_gpt2_mediumOpenAI (GPT Image 2 — Medium)Legacy. Same price as oai_gpt25_high; prefer that.12 credits
oai_gpt2_highOpenAI (GPT Image 2 — High)Legacy. Same price as oai_gpt25_max; prefer that.36 credits
nb_flashGoogle (Nano Banana 2)Default when model is omitted. Legacy: Google deprecated it on 2026-10-06. Same price as nb_flash_2_1; prefer that.12 credits
GPT Image 2.5 tiers run on OpenAI's Flare model for text-to-image and on Sunburst when a reference image is supplied. Same cost either way. The GPT Image 2 keys keep working and still call gpt-image-2; they will be retired later with notice, so new integrations should use the 2.5 keys. Likewise nb_flash (Nano Banana 2) keeps working; new integrations should send nb_flash_2_1.

PixelConfig

Required on this endpoint — every output is post-processed into pixel art. Provide one of two modes, never both.

Count mode — cluster output to N colors
{ "colors": 24 }
Palette mode — force specific colors
{ "palette": ["#ffaa00", "#223344", "#ffffff"] }
FieldTypeConstraints
colorsinteger2–256.
palettestring[]Array of 6-character hex color strings (e.g. "#ff0000").
Palette mode is an experimental feature. Forcing a specific palette can produce worse results than letting the model choose its own colors. If quality matters more than exact color matching, prefer count mode (colors).

Image constraints (reference image)

Only applies when image or image_url is provided. Data URL prefixes are stripped automatically.

  • Format: PNG or JPEG.
  • Max decoded size: 5 MB.
  • image_url: Must be an HTTPS URL.

Response

Response 200
{
  "api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "queued",
  "error": null
}

Poll GET /jobs?id=<api_job_id> for status. On success, output.content_type will be "image/png" and output.metadata will contain width and height of the generated image.

Errors

HTTPCodeCause
400invalid_requestMissing or invalid field (prompt, model, pixel_config, image format, both image and image_url provided, etc.).
400image_too_largeReference image exceeds 5 MB decoded.
400image_fetch_failedimage_url could not be downloaded or timed out.
401unauthorizedInvalid or inactive API key, or expired access token.
402insufficient_creditsNot enough available credits.
405method_not_allowedRequest method is not POST.
500internal_errorServer-side failure.
POST/pixelate

Converts an image to clean pixel art. Automatically detects the pixel grid, quantizes colors, and resamples the image to the detected grid resolution. Returns immediately with a job ID; processing runs asynchronously. Poll GET /jobs to track progress and retrieve the output PNG.

Cost: Free — does not deduct credits.

Request body

JSON
{
  "image": "<base64-encoded image or data URL>",
  "colors": 24
}
FieldTypeRequiredDescription
imagestringYesBase64-encoded image, or a data URL (data:image/png;base64,…). PNG or JPEG. See image constraints below.
colorsintegerNoMaximum number of colors for automatic palette extraction — a ceiling, not a target; the quantizer merges similar colors and often uses fewer. Also accepted nested as pixel_config.colors, the shape the other endpoints use. Integer between 2 and 256. Default: 24. Mutually exclusive with palette.
palettestring[]NoArray of hex color strings (e.g. "#ffaa00") to force an exact palette. Mutually exclusive with colors.
colors and palette are mutually exclusive. Providing both returns 400 invalid_request. If neither is provided, the API defaults to colors: 32.
Palette mode is an experimental feature. Forcing a specific palette can produce worse results than letting the algorithm choose its own colors. If quality matters more than exact color matching, prefer count mode (colors).

Image constraints

Data URL prefixes are stripped automatically.

  • Format: PNG or JPEG.
  • Max decoded size: 10 MB.
  • Max dimension: 2048 px on either axis.
  • Aspect ratio: Between 1:2 and 2:1.

Response

Response 200
{
  "api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "queued",
  "error": null
}

Poll GET /jobs?id=<api_job_id> for status. On success, output.content_type will be "image/png" and output.metadata will contain width and height of the output image.

Errors

HTTPCodeCause
400invalid_requestMissing or invalid field (image format, colors out of range, etc.).
400image_too_largeImage exceeds 10 MB decoded or 2048 px on either axis.
400invalid_requestBoth colors and palette were provided.
401unauthorizedInvalid or inactive API key, or expired access token.
405method_not_allowedRequest method is not POST.
500internal_errorServer-side failure.
POST/remove-background

Removes the background from a still PNG or animated WebP, returning the same format with a transparent background. No prompt or model selection — this is a pure image-processing operation. Returns immediately with a job ID; processing runs asynchronously. Poll GET /jobs to track progress and retrieve the output.

Cost: 2 credits.

Run this endpoint after POST /animate or POST /keyframes completes to strip the background from the generated animation.

Request body

JSON
{
  "image": "<base64-encoded image or data URL>",
  "rmbg_alpha_threshold": 128
}
FieldTypeRequiredDescription
imagestringOne ofBase64-encoded image, or a data URL (data:image/png;base64,…). PNG or animated WebP. Mutually exclusive with image_url.
image_urlstringOne ofHTTPS URL to download the source image. Mutually exclusive with image.
rmbg_alpha_thresholdintegerNoHard alpha cutoff (0–255). Lower values keep more partial transparency around edges; higher values snap harder to fully opaque or fully transparent. When omitted, a source-dependent default is applied automatically.
Exactly one of image or image_url must be provided. Providing both — or neither — returns 400 invalid_request.

Image constraints

Data URL prefixes are stripped automatically.

  • Format: PNG or WebP (still or animated WebP both supported).
  • Max decoded size: 10 MB.
  • Dimensions: No fixed cap. Larger inputs take longer to process.

Response

Response 200
{
  "api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "queued",
  "error": null
}

Poll GET /jobs?id=<api_job_id> for status. On success, output.content_type matches the input format — "image/png" for PNG inputs, "image/webp" for WebP inputs (animated WebP stays animated). output.metadata.rmbg_threshold reflects the threshold value that was applied.

Errors

HTTPCodeCause
400invalid_requestMissing or invalid field, both image and image_url provided, or neither provided.
400image_too_largeImage exceeds 10 MB decoded.
400image_fetch_failedimage_url could not be downloaded or timed out.
401unauthorizedInvalid or inactive API key, or expired access token.
402insufficient_creditsNot enough available credits.
405method_not_allowedRequest method is not POST.
500internal_errorServer-side failure.
POST/cancel

Cancel a queued or in-progress job, or an entire batch. Credits held for the cancelled job(s) are released immediately. Provide exactly one of api_job_id or batch_id.

Cost: Free — does not deduct credits.

Request body

JSON — cancel a single job
{
  "api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
JSON — cancel a whole batch
{
  "batch_id": "b1f2c3d4-5678-90ab-cdef-1234567890ab"
}
FieldTypeRequiredDescription
api_job_idstringOne ofThe api_job_id returned by POST /animate, POST /animate-batch, POST /keyframes, POST /generate-image, POST /pixelate, or POST /remove-background. Passing a batch sub-job's ID cancels its entire batch.
batch_idstringOne ofThe batch_id returned by POST /animate-batch. Cancels every non-terminal sub-job in the batch.
Provide exactly one of api_job_id or batch_id. Supplying both — or neither — returns 400 invalid_request. Already-completed sub-jobs in a batch are left untouched; only non-terminal ones are cancelled.

Response

Response 200 — single job
{
  "api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "cancelled"
}
Response 200 — batch
{
  "batch_id": "b1f2c3d4-5678-90ab-cdef-1234567890ab",
  "status": "cancelled",
  "cancelled_count": 3
}

For a batch, cancelled_count is the number of sub-jobs that were non-terminal at cancel time and have now been cancelled.

Errors

HTTPCodeCause
400invalid_requestInvalid JSON body, or not exactly one of api_job_id / batch_id provided.
401unauthorizedInvalid or inactive API key, or expired access token.
404job_not_foundNo job with that ID, or the job belongs to a different API key or app.
404batch_not_foundNo batch with that ID, or the batch belongs to a different API key or app.
409invalid_requestJob is already in a terminal state (message includes the current status).
500internal_errorServer-side failure.
POST/enhance-prompt

Rewrites a short user prompt into a precise animation caption optimized for the generation model. Optionally accepts a reference image — when provided, the AI identifies the character from the image rather than inventing appearance details. This is a synchronous endpoint; the result is returned directly (typically 1–3 seconds).

Cost: Free — does not deduct credits.

Request body

JSON
{
  "prompt": "dash sword attack",
  "image": "<base64-encoded image or data URL>",
  "model": "pixel-engine-v1.5",
  "render_mode": "pixel"
}
FieldTypeRequiredDescription
promptstringYesThe user's raw prompt text. May be an empty string when an image is provided. Maximum 2,000 characters.
imagestringNoBase64-encoded image, or a data URL (data:image/png;base64,…). Accepted formats depend on model. See image constraints below.
modelstringNoWhich generation model the prompt is being written for. Defaults to "pixel-engine-v1.1". See Models below.
render_modestringModel-dependent"pixel" or "detailed". Required for pixel-engine-v1.5. The -engine- models imply their own: sending the matching value is accepted, a contradicting one is rejected. It selects both the image constraints and the rewriting style, so send the same value you will send to POST /animate.
At least one of prompt (non-empty string) or image must be provided.

Models

The model field should match the model you intend to use with POST /animate. Image constraints are enforced per model. If omitted, defaults to "pixel-engine-v1.1".

Modelrender_modeBest forInput formatsImage size
pixel-engine-v1.5"pixel"Pixel art sprites and charactersPNGUp to 320×320 px
pixel-engine-v1.5"detailed"Illustrations and non-pixel game artPNG or JPEG256×256 px to 2048×2048 px
pixel-engine-v1.1—Pixel art sprites and charactersPNGUp to 256×256 px
frame-engine-v1.1—Illustrations and non-pixel game artPNG or JPEG256×256 px to 2048×2048 px
Each model and mode has its own rewriting style, so the enhanced prompt you get back for pixel-engine-v1.5 is not the one you would get for pixel-engine-v1.1. On pixel-engine-v1.5 a prompt under 15 words is rewritten automatically by POST /animateanyway — call this endpoint when you want to see or edit the rewrite first.

Image constraints

Same per-model constraints as POST /animate. Data URL prefixes are stripped automatically.

  • Max decoded size: 5 MB, every model.
  • Aspect ratio: Between 1:2 and 2:1, every model.
Modelrender_modeFormatDimensions
pixel-engine-v1.5"pixel"PNG onlyEach axis must be 320 px or smaller.
pixel-engine-v1.5"detailed"PNG or JPEGEach axis must be between 256 px and 2048 px.
pixel-engine-v1.1—PNG onlyEach axis must be 256 px or smaller.
frame-engine-v1.1—PNG or JPEGEach axis must be between 256 px and 2048 px.

Response

Response 200
{
  "enhanced_prompt": "The character dashes forward with a burst of speed, executing a wide, sweeping sword slash that leaves a large white crescent trail."
}
FieldTypeDescription
enhanced_promptstringThe rewritten prompt, ready to pass directly to POST /animate. Plain text, no Markdown or formatting. Typically 25–50 words.

Behavior

When an image is provided, the model uses it as a reference for the rewritten caption. Without an image, it rewrites based on the text prompt alone. If only an image is provided, it generates a generic caption from the image.

Errors

HTTPCodeCause
400invalid_requestBad JSON, missing required fields, or invalid field values.
400image_too_largeImage exceeds 5 MB decoded.
401unauthorizedMissing, invalid, or inactive API key, or expired access token.
502upstream_errorThe AI returned an empty response. Retry may help.
500internal_errorServer-side failure.
GET/jobs

Returns the current state of a job. On completion, includes a download URL or error details.

Query parameters

ParameterRequiredDescription
idYesThe api_job_id returned by POST /animate, POST /keyframes, POST /generate-image, POST /pixelate, or POST /remove-background — or any single sub-job ID from POST /animate-batch. To poll a whole batch at once, use GET /batch-jobs instead.

Response

Response 200 — queued
{
  "api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "status": "queued",
  "progress": 0.0,
  "created_at": "2026-03-02T18:00:00.000Z",
  "finished_at": null,
  "cancelled_at": null,
  "billing": {
    "credits_held": 20,
    "credits_charged": 0,
    "hold_status": "open"
  },
  "training_opt_out": false,
  "inputs": {
    "prompt": "a character walking through a forest",
    "negative_prompt": "",
    "model": "pixel-engine-v1.1",
    "pixel_config": { "colors": 16 },
    "output_frames": 8,
    "seed": 12345,
    "output_format": "webp",
    "matte_color": "#808080"
  },
  "output": null,
  "error": null
}

Status values

ValueMeaning
"queued"Job accepted, waiting to be picked up.
"pending"Job is actively running.
"success"Generation complete. output is populated. billing.credits_charged > 0.
"failure"Generation failed. error is populated, hold is released.
"cancelled"Cancelled via POST /cancel. error is populated, hold is released.

progress is a float 0.0–1.0. May remain 0 until the job is actively running.

cancelled_at is an ISO-8601 timestamp set when a job is cancelled via POST /cancel, otherwise null.

training_opt_out is true when the request that created the job sent "training_opt_out": true. An account-wide opt-out is not reflected here. See Training opt-out.

Billing object

Present whenever a wallet hold was created for the job. null if no hold exists.

billing
{
  "credits_held": 20,
  "credits_charged": 0,
  "hold_status": "open"
}
FieldTypeDescription
credits_heldintegerCredits reserved (held) for this job.
credits_chargedintegerCredits actually charged. 0 until the hold is captured on success.
hold_statusstring"open" (job in progress), "released" (cancelled/failed, credits returned), "captured" (charged on success), "expired" (hold timed out).

Inputs object

Reflects the generation parameters submitted with POST /animate, POST /keyframes, POST /generate-image, POST /pixelate, or POST /remove-background. Always present. Fields match the original request body (excluding image / image_url). If seed was not provided in the original request, it will be absent here.

Output object (on success)

output — status: "success"
{
  "url": "https://...",
  "content_type": "image/webp",
  "metadata": { ... },
  "expires_at": "2026-03-03T18:00:00.000Z"
}
FieldDescription
urlTemporary download URL for the generated file.
content_type"image/webp", "image/gif", or "image/png" (spritesheet).
metadataOutput dimensions and format details. See shapes below.
expires_atISO timestamp until which the output is guaranteed to be available (24 hours after the job).
Output files are available for at least 24 hours after job creation; after that we may remove them, and polling then returns 410 job_expired. The signed url is valid for 1 hour; re-poll GET /jobs to get a fresh one before it expires.

Metadata shapes

webp and gif
{ "width": 64, "height": 64, "frame_count": 8, "fps": 8.0 }
spritesheet
{
  "width": 512,
  "height": 64,
  "output_format": "spritesheet",
  "frame_count": 8,
  "frame_w": 64,
  "frame_h": 64
}

Spritesheets are a single horizontal strip: width == frame_count × frame_w, height == frame_h.

Output dimensions

Output dimensions depend on whether the job runs in a pixel-art pipeline or a general-purpose pipeline, not on the output format. All formats (webp, gif, spritesheet) for a given job render at the same per-frame resolution.

PipelineUsed byOutput dimensions
Pixel artPOST /animate with "pixel-engine-v1.1", or with "pixel-engine-v1.5" and render_mode: "pixel"; POST /keyframes with render_mode: "pixel"Output frames exactly match the original input image dimensions. A 64×64 input produces 64×64 frames in every format.
GeneralPOST /animate with "frame-engine-v1.1", or with "pixel-engine-v1.5" and render_mode: "detailed"; POST /keyframes with render_mode: "detailed"Output frames are rendered at the model's internal resolution: 640 px on the long side, with the short side scaled to preserve the input's aspect ratio and rounded to a multiple the model can render — 8 for frame-engine-v1.1, 32 for pixel-engine-v1.5, 64 for POST /keyframes. The divisor changes the answer, so the worked examples are per-divisor: a 1024×768 input gives 640×480 at 8 and at 32, and 640×512 at 64; a 1080×1920 input gives 360×640 at 8, 352×640 at 32, and 384×640 at 64.
A maximum-size general-pipeline spritesheet — 24 frames at 640×640 px from frame-engine-v1.1, or 20 frames at 640×640 px from render_mode: "detailed", packed horizontally as one PNG strip — can reach ~15–20 MB. Output files are guaranteed for 24 hours after job creation; if you need to keep them, download and store them on your own infrastructure before the expires_at timestamp.

Error object (on failure)

error — status: "failure"
{
  "code": "generation_failed",
  "message": "Generation failed"
}

Error object (on cancel)

error — status: "cancelled"
{
  "code": "job_cancelled",
  "message": "Job was cancelled"
}

Errors

HTTPCodeCause
400invalid_requestid is not a UUID. (With no id at all, /jobs lists your recent jobs instead.)
401unauthorizedInvalid or inactive API key, or expired access token.
404job_not_foundNo job with that ID, or the job belongs to a different API key or app.
410job_expiredJob output is no longer available. Outputs can be downloaded for at least 24 hours.
500internal_errorServer-side failure.
GET/jobs

Call /jobs with no id to list your most recent jobs, newest first. To retry a submit whose response never arrived without paying twice, prefer an Idempotency-Key: a job still in validation may not appear in this list yet. An API key sees the jobs it submitted; an OAuth access token sees the jobs that app submitted for that user.

Request
GET /jobs?since=2026-09-30T12:00:00Z&limit=20

Query parameters

ParameterTypeRequiredDescription
limitintegerNoJobs per page, 1–100. Default 20.
sincestringNoISO-8601 timestamp. Only jobs created at or after it.
beforestringNoISO-8601 timestamp. Only jobs created before it. Pass the previous page's next_before to page backwards.

Response

Response 200
{
  "jobs": [
    {
      "api_job_id": "18f9f71c-23fa-4a5a-9290-ba9f267f37a4",
      "status": "success",
      "progress": 1,
      "job_mode": "animate",
      "created_at": "2026-10-01T01:07:50.405Z",
      "finished_at": "2026-10-01T01:09:49.953Z",
      "cancelled_at": null,
      "output_expired": false,
      "billing": { "credits_held": 26, "credits_charged": 26, "hold_status": "captured" },
      "inputs": { "prompt": "…", "model": "pixel-engine-v1.5", "output_frames": 4 },
      "error": null
    }
  ],
  "has_more": true,
  "next_before": "2026-10-01T01:07:50.405Z"
}

Each entry has the same fields as a single GET /jobs?id= response except output: fetch the job by id for its download URL. output_expired is true once the output is no longer available (possible from 24 hours after the job). Batch sub-jobs also carry batch_id and batch_position.

Errors

HTTPCodeCause
400invalid_requestlimit, since or before is malformed.
401unauthorizedInvalid or inactive API key, or expired access token.
500internal_errorServer-side failure.
GET/batch-jobs

Returns the current state of every sub-job in a batch, plus a roll-up summary. Poll this once per interval to track an entire POST /animate-batch submission instead of polling each sub-job individually.

Cost: Free — does not deduct credits.

Query parameters

ParameterRequiredDescription
batch_idYesThe batch_id returned by POST /animate-batch.

Response

Response 200
{
  "batch_id": "b1f2c3d4-5678-90ab-cdef-1234567890ab",
  "batch_size": 2,
  "summary": {
    "queued": 0,
    "pending": 1,
    "success": 1,
    "failure": 0,
    "cancelled": 0
  },
  "sub_jobs": [
    {
      "api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "batch_position": 0,
      "status": "success",
      "progress": 1.0,
      "created_at": "2026-03-02T18:00:00.000Z",
      "finished_at": "2026-03-02T18:01:30.000Z",
      "cancelled_at": null,
      "billing": { "credits_held": 20, "credits_charged": 20, "hold_status": "captured" },
      "inputs": { "prompt": "a character walking", "model": "pixel-engine-v1.1" },
      "output": {
        "url": "https://...",
        "content_type": "image/webp",
        "metadata": { "width": 64, "height": 64, "frame_count": 8, "fps": 8.0 },
        "expires_at": "2026-03-03T18:00:00.000Z"
      },
      "error": null
    },
    {
      "api_job_id": "9c858901-8a57-4791-81fe-4c455b099bc9",
      "batch_position": 1,
      "status": "pending",
      "progress": 0.4,
      "created_at": "2026-03-02T18:00:00.000Z",
      "finished_at": null,
      "cancelled_at": null,
      "billing": { "credits_held": 12, "credits_charged": 0, "hold_status": "open" },
      "inputs": { "prompt": "a character jumping", "model": "pixel-engine-v1.1" },
      "output": null,
      "error": null
    }
  ]
}
FieldTypeDescription
batch_idstringThe batch identifier.
batch_sizeintegerNumber of sub-jobs in the batch.
summaryobjectCount of sub-jobs in each status (queued, pending, success, failure, cancelled). The batch is done once queued + pending == 0.
sub_jobsarrayOne entry per sub-job, ordered by batch_position (the anchor is position 0). Each entry mirrors the GET /jobs response shape, with an added batch_position field.
Per-sub-job billing, inputs, output, and error objects have the same shapes documented under GET /jobs. Outputs are guaranteed for 24 hours after batch creation; a sub-job whose output has been cleaned up reports a job_expired error in its error field while the rest of the batch stays intact.

Errors

HTTPCodeCause
400invalid_requestbatch_id query parameter missing.
401unauthorizedInvalid or inactive API key, or expired access token.
404batch_not_foundNo batch with that ID, or the batch belongs to a different API key or app.
405method_not_allowedRequest method is not GET.
500internal_errorServer-side failure.

See also

The Introduction covers everything needed before making your first request: base URL, authentication and API key management, the credit system, the shared error response format, and the recommended polling pattern for async jobs.