API Reference
All endpoints are relative to https://api.pixelengine.ai/functions/v1. Every request requires an API key.
/balanceReturns the authenticated user's current credit balance.
Response
{
"monthly_balance": 1200,
"purchased_balance": 500,
"total_balance": 1700,
"reserved": 20,
"available": 1680
}| Field | Type | Description |
|---|---|---|
monthly_balance | integer | Current monthly credit pool. |
purchased_balance | integer | Current purchased credit pool. |
total_balance | integer | monthly_balance + purchased_balance. |
reserved | integer | Credits held by in-flight jobs (not yet deducted). |
available | integer | Credits available for new jobs (total_balance − reserved, floor 0). |
Errors
| HTTP | Code | Cause |
|---|---|---|
| 401 | unauthorized | Invalid or inactive API key. |
/billingReturns 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.
Query parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
start_date | No | 30 days before end_date | Inclusive start date in YYYY-MM-DD format (UTC). |
end_date | No | Today | Inclusive end date in YYYY-MM-DD format (UTC). |
The maximum period is 365 days.
Response
{
"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,
"net_change": -80,
"jobs_charged": 62
},
"balance": {
"monthly_balance": 920,
"purchased_balance": 500,
"total_balance": 1420,
"reserved": 20,
"available": 1400
}
}| Field | Type | Description |
|---|---|---|
period.start_date | string | ISO timestamp of the period start. |
period.end_date | string | ISO timestamp of the period end. |
totals.credits_used | integer | Total credits charged (sum of debit entries). |
totals.credits_added | integer | Total credits added (purchases, monthly refresh, etc.). |
totals.refunds | integer | Total credits taken back out of the wallet (for example a refunded purchase). These reduce your balance. |
totals.net_change | integer | credits_added − refunds − credits_used. Positive means credits gained, negative means net spend. |
totals.jobs_charged | integer | Number of jobs that consumed credits in the period. |
balance | object | Current balance snapshot — same shape as GET /balance. |
Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | Invalid date format, start_date after end_date, or period exceeds 365 days. |
| 401 | unauthorized | Invalid or inactive API key. |
| 404 | invalid_request | No wallet found for the authenticated user. |
| 500 | internal_error | Server-side failure. |
/animateSubmits 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
{
"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
}
}| Field | Type | Required | Description |
|---|---|---|---|
image | string | Yes | Base64-encoded image, or a data URL (data:image/png;base64,…). Accepted formats depend on model. See image constraints below. |
prompt | string | Yes | Non-empty text describing the desired animation. |
model | string | No | Which animation model to use. Defaults to "pixel-engine-v1.1". See Models below. |
render_mode | string | Model-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_prompt | string | No | What to avoid in the generation. Not supported by pixel-engine-v1.5 — see Models below. |
pixel_config | object | No | Pixel art color config. Defaults to { "colors": 24 }. Only allowed in pixel mode. See PixelConfig below. |
output_frames | integer | No | Number of animation frames. Default: 8. Range and whether odd counts are allowed depend on the model — see Models below. |
seed | integer | No | Seed for reproducibility. Integer between 1 and 9,999,999,999. If omitted, a random seed is used. |
output_format | string | No | "webp" (default), "gif", or "spritesheet". |
matte_color | string | No | 6-character hex color (e.g. "#ff0000") used to flatten any alpha channel before processing. Default: "#808080". |
transform | object | No | Place 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. |
Models
If model is omitted, the API defaults to "pixel-engine-v1.1".
| Model | render_mode | Best for | Input formats | Image size | output_frames |
|---|---|---|---|---|---|
pixel-engine-v1.5 | "pixel" | Pixel art sprites and characters | PNG | Up to 320×320 px | 3–16 |
pixel-engine-v1.5 | "detailed" | Illustrations and non-pixel images | PNG or JPEG | 256×256 px to 2048×2048 px | 3–16 |
pixel-engine-v1.1 | — | Pixel art. Often better for loops, walk cycles and idles | PNG | Up to 256×256 px | 2–16 (even) |
frame-engine-v1.1 | — | Illustrations and non-pixel images | PNG or JPEG | 256×256 px to 2048×2048 px | 2–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.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.
{ "colors": 24 }{ "palette": ["#ffaa00", "#223344", "#ffffff"] }| Field | Type | Constraints |
|---|---|---|
colors | integer | 2–256. |
palette | string[] | Array of hex color strings (e.g. "#ff0000") |
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_colorbefore processing.
| Model | Format | Dimensions | Notes |
|---|---|---|---|
pixel-engine-v1.1 | PNG only | Each axis must be 256 px or smaller | Designed for pixel art input. |
frame-engine-v1.1 | PNG or JPEG | Each axis must be between 256 px and 2048 px | Both 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
{
"api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "queued",
"error": null
}Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | Missing or invalid field (prompt, image format, output_frames, etc.). |
| 400 | image_too_large | Image exceeds 5 MB decoded. |
| 401 | unauthorized | Invalid or inactive API key. |
| 402 | insufficient_credits | Not enough available credits. |
| 405 | method_not_allowed | Request method is not POST. |
| 500 | internal_error | Server-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.
/animate-batchSubmits 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
{
"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"
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
jobs | array | Yes | Between 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). |
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
{
"batch_id": "b1f2c3d4-5678-90ab-cdef-1234567890ab",
"api_job_ids": [
"f47ac10b-58cc-4372-a567-0e02b2c3d479",
"9c858901-8a57-4791-81fe-4c455b099bc9"
],
"status": "queued"
}| Field | Type | Description |
|---|---|---|
batch_id | string | Identifier for the whole batch. Pass to GET /batch-jobs or POST /cancel. |
api_job_ids | string[] | 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. |
status | string | Always "queued" on a successful submission. |
Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | jobs 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]:). |
| 400 | image_too_large | A sub-job image exceeds 5 MB decoded. |
| 400 | payload_too_large | Total decoded image bytes across all sub-jobs exceed 30 MB. |
| 401 | unauthorized | Invalid or inactive API key. |
| 402 | insufficient_credits | Not enough available credits to cover the full batch. |
| 405 | method_not_allowed | Request method is not POST. |
| 500 | internal_error | Server-side failure. |
/keyframesSubmits 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
{
"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"
}| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Non-empty text describing the desired animation. |
render_mode | string | Yes | "pixel" or "detailed". Determines image format constraints and post-processing. See Render modes below. |
total_frames | integer | Yes | Total number of output frames. Integer between 3 and 20. |
frames | array | Yes | Between 1 and total_frames keyframe objects. Each provides a reference image at a specific position in the output sequence. |
frames[].index | integer | Yes | Frame position in the output sequence. Must be in range [0, total_frames − 1]. Each index may only appear once. |
frames[].image | string | One of | Base64-encoded image, or a data URL. Mutually exclusive with frames[].image_url. |
frames[].image_url | string | One of | HTTPS URL to download the keyframe image. Mutually exclusive with frames[].image. |
frames[].strength | number | No | Conditioning strength for this keyframe. Float between 0.0 and 1.0. Default: 1.0. |
frames[].placement | object | No | Where 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. |
transform | object | No | The shared canvas every keyframe is placed on. See Transform below. Supplying it also lifts the same-dimensions requirement on your input images. |
negative_prompt | string | No | What to avoid in the generation. |
pixel_config | object | No | Pixel art color config. Defaults to { "colors": 24 }. Only allowed for render_mode: "pixel". See PixelConfig above. |
seed | integer | No | Seed for reproducibility. Integer between 1 and 9,999,999,999. |
output_format | string | No | "webp" (default), "gif", or "spritesheet". |
matte_color | string | No | 6-character hex color (e.g. "#ff0000") used to flatten any alpha channel before processing. Default: "#808080". |
Render modes
| Mode | Input formats | Image size |
|---|---|---|
pixel | PNG only | Up to 256×256 px per axis |
detailed | PNG or JPEG | 256–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_colorbefore processing.
Response
{
"api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "queued",
"error": null
}Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | Missing or invalid field (prompt, render_mode, frames, dimensions, etc.). |
| 400 | image_too_large | Single image exceeds 10 MB or total exceeds 20 MB. |
| 400 | image_fetch_failed | An image_url could not be downloaded or timed out. |
| 401 | unauthorized | Invalid or inactive API key. |
| 402 | insufficient_credits | Not enough available credits. |
| 405 | method_not_allowed | Request method is not POST. |
| 500 | internal_error | Server-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.
{
"transform": {
"canvas_size": 128,
"fill_method": "edge-extend",
"fill_color": "#808080",
"offset_x": 0,
"offset_y": 0,
"flip_h": false,
"flip_v": false
}
}| Field | Type | Required | Description |
|---|---|---|---|
canvas_size | integer | Yes | Edge 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_method | string | No | How 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_color | string | No | 6-character hex color, used only when fill_method is "solid". Default: "#808080". |
offset_x | integer | No | Horizontal shift from center, in pixels. Positive moves right. Default: 0. |
offset_y | integer | No | Vertical shift from center, in pixels. Positive moves down. Default: 0. |
flip_h | boolean | No | Mirror the image horizontally. Default: false. |
flip_v | boolean | No | Mirror 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:
{
"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.
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./generate-imageGenerates 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
{
"prompt": "a knight standing in a torchlit dungeon",
"model": "nb_flash",
"pixel_config": { "colors": 24 },
"seed": 12345
}{
"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"] }
}| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Non-empty text describing the desired image (or, in image-to-image mode, the desired edit). |
model | string | No | Which generation model to use. Defaults to "nb_flash". See Models below. |
pixel_config | object | Yes | Pixel art color config — required on this endpoint (all outputs are pixel art). Provide either colors or palette, never both. See PixelConfig below. |
image | string | No | Optional reference image. 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_url | string | No | HTTPS URL to download the reference image. Mutually exclusive with image. |
seed | integer | No | Seed 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. |
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 optional reference image).
| Model | Provider | Description | Cost |
|---|---|---|---|
nb_flash | Google (Nano Banana 2) | Default. Solid all-around; great quality for the price. | 12 credits |
nb_pro | Google (Nano Banana Pro) | Highest overall quality. | 36 credits |
oai_gpt25_low | OpenAI (GPT Image 2.5 — Low) | Cheapest and fastest; quick drafts. | 6 credits |
oai_gpt25_high | OpenAI (GPT Image 2.5 — High) | Best for edits with a reference image: rotations, poses, props. | 12 credits |
oai_gpt25_max | OpenAI (GPT Image 2.5 — Max) | Top detail on complex prompts and edits; slower. | 36 credits |
oai_gpt2_low | OpenAI (GPT Image 2 — Low) | Legacy. Same price as oai_gpt25_low; prefer that. | 6 credits |
oai_gpt2_medium | OpenAI (GPT Image 2 — Medium) | Legacy. Same price as oai_gpt25_high; prefer that. | 12 credits |
oai_gpt2_high | OpenAI (GPT Image 2 — High) | Legacy. Same price as oai_gpt25_max; prefer that. | 36 credits |
PixelConfig
Required on this endpoint — every output is post-processed into pixel art. Provide one of two modes, never both.
{ "colors": 24 }{ "palette": ["#ffaa00", "#223344", "#ffffff"] }| Field | Type | Constraints |
|---|---|---|
colors | integer | 2–256. |
palette | string[] | Array of 6-character hex color strings (e.g. "#ff0000"). |
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
{
"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
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | Missing or invalid field (prompt, model, pixel_config, image format, both image and image_url provided, etc.). |
| 400 | image_too_large | Reference image exceeds 5 MB decoded. |
| 400 | image_fetch_failed | image_url could not be downloaded or timed out. |
| 401 | unauthorized | Invalid or inactive API key. |
| 402 | insufficient_credits | Not enough available credits. |
| 405 | method_not_allowed | Request method is not POST. |
| 500 | internal_error | Server-side failure. |
/pixelateConverts 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
{
"image": "<base64-encoded image or data URL>",
"colors": 24
}| Field | Type | Required | Description |
|---|---|---|---|
image | string | Yes | Base64-encoded image, or a data URL (data:image/png;base64,…). PNG or JPEG. See image constraints below. |
colors | integer | No | Maximum 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. |
palette | string[] | No | Array 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.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
{
"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
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | Missing or invalid field (image format, colors out of range, etc.). |
| 400 | image_too_large | Image exceeds 10 MB decoded or 2048 px on either axis. |
| 400 | invalid_request | Both colors and palette were provided. |
| 401 | unauthorized | Invalid or inactive API key. |
| 405 | method_not_allowed | Request method is not POST. |
| 500 | internal_error | Server-side failure. |
/remove-backgroundRemoves 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
{
"image": "<base64-encoded image or data URL>",
"rmbg_alpha_threshold": 128
}| Field | Type | Required | Description |
|---|---|---|---|
image | string | One of | Base64-encoded image, or a data URL (data:image/png;base64,…). PNG or animated WebP. Mutually exclusive with image_url. |
image_url | string | One of | HTTPS URL to download the source image. Mutually exclusive with image. |
rmbg_alpha_threshold | integer | No | Hard 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. |
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
{
"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
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | Missing or invalid field, both image and image_url provided, or neither provided. |
| 400 | image_too_large | Image exceeds 10 MB decoded. |
| 400 | image_fetch_failed | image_url could not be downloaded or timed out. |
| 401 | unauthorized | Invalid or inactive API key. |
| 402 | insufficient_credits | Not enough available credits. |
| 405 | method_not_allowed | Request method is not POST. |
| 500 | internal_error | Server-side failure. |
/cancelCancel 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
{
"api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}{
"batch_id": "b1f2c3d4-5678-90ab-cdef-1234567890ab"
}| Field | Type | Required | Description |
|---|---|---|---|
api_job_id | string | One of | The 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_id | string | One of | The batch_id returned by POST /animate-batch. Cancels every non-terminal sub-job in the batch. |
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
{
"api_job_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"status": "cancelled"
}{
"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
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | Invalid JSON body, or not exactly one of api_job_id / batch_id provided. |
| 401 | unauthorized | Invalid or inactive API key. |
| 404 | job_not_found | No job with that ID, or the job belongs to a different API key. |
| 404 | batch_not_found | No batch with that ID, or the batch belongs to a different API key. |
| 409 | invalid_request | Job is already in a terminal state (message includes the current status). |
| 500 | internal_error | Server-side failure. |
/enhance-promptRewrites 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
{
"prompt": "dash sword attack",
"image": "<base64-encoded image or data URL>",
"model": "pixel-engine-v1.5",
"render_mode": "pixel"
}| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | The user's raw prompt text. May be an empty string when an image is provided. Maximum 2,000 characters. |
image | string | No | Base64-encoded image, or a data URL (data:image/png;base64,…). Accepted formats depend on model. See image constraints below. |
model | string | No | Which generation model the prompt is being written for. Defaults to "pixel-engine-v1.1". See Models below. |
render_mode | string | Model-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. |
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".
| Model | render_mode | Best for | Input formats | Image size |
|---|---|---|---|---|
pixel-engine-v1.5 | "pixel" | Pixel art sprites and characters | PNG | Up to 320×320 px |
pixel-engine-v1.5 | "detailed" | Illustrations and non-pixel game art | PNG or JPEG | 256×256 px to 2048×2048 px |
pixel-engine-v1.1 | — | Pixel art sprites and characters | PNG | Up to 256×256 px |
frame-engine-v1.1 | — | Illustrations and non-pixel game art | PNG or JPEG | 256×256 px to 2048×2048 px |
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.
| Model | render_mode | Format | Dimensions |
|---|---|---|---|
pixel-engine-v1.5 | "pixel" | PNG only | Each axis must be 320 px or smaller. |
pixel-engine-v1.5 | "detailed" | PNG or JPEG | Each axis must be between 256 px and 2048 px. |
pixel-engine-v1.1 | — | PNG only | Each axis must be 256 px or smaller. |
frame-engine-v1.1 | — | PNG or JPEG | Each axis must be between 256 px and 2048 px. |
Response
{
"enhanced_prompt": "The character dashes forward with a burst of speed, executing a wide, sweeping sword slash that leaves a large white crescent trail."
}| Field | Type | Description |
|---|---|---|
enhanced_prompt | string | The 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
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | Bad JSON, missing required fields, or invalid field values. |
| 400 | image_too_large | Image exceeds 5 MB decoded. |
| 401 | unauthorized | Missing, invalid, or inactive API key. |
| 502 | upstream_error | The AI returned an empty response. Retry may help. |
| 500 | internal_error | Server-side failure. |
/jobsReturns the current state of a job. On completion, includes a download URL or error details.
Query parameters
| Parameter | Required | Description |
|---|---|---|
id | Yes | The 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
{
"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"
},
"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
| Value | Meaning |
|---|---|
"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.
Billing object
Present whenever a wallet hold was created for the job. null if no hold exists.
{
"credits_held": 20,
"credits_charged": 0,
"hold_status": "open"
}| Field | Type | Description |
|---|---|---|
credits_held | integer | Credits reserved (held) for this job. |
credits_charged | integer | Credits actually charged. 0 until the hold is captured on success. |
hold_status | string | "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)
{
"url": "https://...",
"content_type": "image/webp",
"metadata": { ... },
"expires_at": "2026-03-03T18:00:00.000Z"
}| Field | Description |
|---|---|
url | Temporary download URL for the generated file. |
content_type | "image/webp", "image/gif", or "image/png" (spritesheet). |
metadata | Output dimensions and format details. See shapes below. |
expires_at | ISO timestamp when the output file will be permanently deleted. |
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
{ "width": 64, "height": 64, "frame_count": 8, "fps": 8.0 }{
"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.
| Pipeline | Used by | Output dimensions |
|---|---|---|
| Pixel art | POST /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. |
| General | POST /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. |
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 expire 24 hours after job creation; if you need to keep them longer, download and store them on your own infrastructure before the expires_at timestamp.Error object (on failure)
{
"code": "generation_failed",
"message": "Generation failed"
}Error object (on cancel)
{
"code": "job_cancelled",
"message": "Job was cancelled"
}Errors
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | id query parameter missing. |
| 401 | unauthorized | Invalid or inactive API key. |
| 404 | job_not_found | No job with that ID, or the job belongs to a different API key. |
| 410 | job_expired | Job output has been deleted. Outputs are retained for 24 hours. |
| 500 | internal_error | Server-side failure. |
/batch-jobsReturns 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
| Parameter | Required | Description |
|---|---|---|
batch_id | Yes | The batch_id returned by POST /animate-batch. |
Response
{
"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
}
]
}| Field | Type | Description |
|---|---|---|
batch_id | string | The batch identifier. |
batch_size | integer | Number of sub-jobs in the batch. |
summary | object | Count of sub-jobs in each status (queued, pending, success, failure, cancelled). The batch is done once queued + pending == 0. |
sub_jobs | array | One 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. |
billing, inputs, output, and error objects have the same shapes documented under GET /jobs. Outputs expire 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
| HTTP | Code | Cause |
|---|---|---|
| 400 | invalid_request | batch_id query parameter missing. |
| 401 | unauthorized | Invalid or inactive API key. |
| 404 | batch_not_found | No batch with that ID, or the batch belongs to a different API key. |
| 405 | method_not_allowed | Request method is not GET. |
| 500 | internal_error | Server-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.