API reference
Full Sprite AI REST API reference: endpoints for generating sprites and animations, request and response formats, parameters, and example calls.
GET/api/me
Your account: plan, balance, and rate limit.
curl https://www.sprite-ai.art/api/me \
-H "Authorization: Bearer sai_sk_your_key_here"const res = await fetch("https://www.sprite-ai.art/api/me", {
headers: { Authorization: "Bearer sai_sk_your_key_here" },
});
const account = await res.json();import requests
account = requests.get(
"https://www.sprite-ai.art/api/me",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
).json(){
"user_id": "...",
"email": "you@example.com",
"plan": "studio",
"rate_limit_per_minute": 60,
"monthly_token_allotment": 1000,
"monthly_tokens_used": 340,
"purchased_token_balance": 0,
"total_token_balance": 660,
"monthly_renews_at": "2026-07-01T00:00:00.000Z",
"billing_period": "monthly"
}GET/api/balance
Token balance only, a subset of /api/me.
curl https://www.sprite-ai.art/api/balance \
-H "Authorization: Bearer sai_sk_your_key_here"const res = await fetch("https://www.sprite-ai.art/api/balance", {
headers: { Authorization: "Bearer sai_sk_your_key_here" },
});
const { total_token_balance } = await res.json();import requests
balance = requests.get(
"https://www.sprite-ai.art/api/balance",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
).json(){
"plan": "studio",
"total_token_balance": 660,
"purchased_token_balance": 0,
"monthly_token_allotment": 1000,
"monthly_tokens_used": 340,
"monthly_renews_at": "2026-07-01T00:00:00.000Z",
"billing_period": "monthly"
}GET/api/asset-types
Asset types with their token cost and size range.
curl https://www.sprite-ai.art/api/asset-types \
-H "Authorization: Bearer sai_sk_your_key_here"const res = await fetch("https://www.sprite-ai.art/api/asset-types", {
headers: { Authorization: "Bearer sai_sk_your_key_here" },
});
const { asset_types } = await res.json();import requests
asset_types = requests.get(
"https://www.sprite-ai.art/api/asset-types",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
).json()["asset_types"]| Type | Token cost | Size |
|---|---|---|
character | 1 | 32–400 px |
item | 1 | 32–400 px |
creature | 1 | 32–400 px |
tile | 4 | 8–512 px |
background | 4 | 8–512 px |
ui | 4 | 8–512 px |
effect | 4 | 8–512 px |
GET/api/limits
Request bounds and token costs for your key.
curl https://www.sprite-ai.art/api/limits \
-H "Authorization: Bearer sai_sk_your_key_here"const res = await fetch("https://www.sprite-ai.art/api/limits", {
headers: { Authorization: "Bearer sai_sk_your_key_here" },
});
const limits = await res.json();import requests
limits = requests.get(
"https://www.sprite-ai.art/api/limits",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
).json(){
"rate_limit_per_minute": 60,
"sprite": { "min_size": 8, "max_size": 512, "prompt_max_length": 1500 },
"animation": { "min_frames": 4, "max_frames": 24, "frames_must_be_even": true }
}POST/api/sprites
Generate a still sprite. Synchronous: the PNG comes back inline. Costs 1 token (4 for tile, background, ui, effect).
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | What to draw. 3–1500 chars. |
asset_type | string | No | Inferred from the prompt when omitted. |
width | integer | No | 8–512 px. Default 64. |
height | integer | No | 8–512 px. Default 64. |
direction | string | No | Facing direction, e.g. south. |
camera_perspective | string | No | e.g. side, top_down, isometric. |
public | boolean | No | Add to the public gallery. Default false. |
reference_asset_id | string | No | UUID of a sprite you own, used as a style reference. |
curl https://www.sprite-ai.art/api/sprites \
-H "Authorization: Bearer sai_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "prompt": "a knight with a blue cape", "asset_type": "character" }'const res = await fetch("https://www.sprite-ai.art/api/sprites", {
method: "POST",
headers: {
Authorization: "Bearer sai_sk_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
prompt: "a knight with a blue cape",
asset_type: "character",
}),
});
const data = await res.json(); // data.image.pngBase64import base64, requests
res = requests.post(
"https://www.sprite-ai.art/api/sprites",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
json={"prompt": "a knight with a blue cape", "asset_type": "character"},
)
data = res.json()
with open("knight.png", "wb") as f:
f.write(base64.b64decode(data["image"]["pngBase64"])){
"id": "a1b2c3d4-...",
"status": "completed",
"width": 64,
"height": 64,
"assetType": "character",
"tokensSpent": 1,
"image": { "format": "png", "pngBase64": "iVBORw0KGgoAAAANS..." }
}The PNG is inline in image.pngBase64. There is no hosted URL.
POST/api/sprites/import
Add a sprite you already have (a local PNG, or any pixel sprite) and get back an id you can animate (source_generation_id) or use as a style reference (reference_asset_id). Free: importing spends no tokens and runs no AI.
The image must be a single sprite (PNG, JPEG, or WebP), 16–256px per side, not a sprite sheet. Imported sprites are always private.
| Field | Type | Required | Description |
|---|---|---|---|
image | string | Yes | The sprite, as base64 or a data:image/...;base64 URL. |
title | string | No | Label for the sprite. Default "Imported sprite". |
asset_type | string | No | Asset-type tag (metadata only). |
curl https://www.sprite-ai.art/api/sprites/import \
-H "Authorization: Bearer sai_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "image": "<png base64>", "title": "hero" }'import { readFileSync } from "node:fs";
const image = readFileSync("hero.png").toString("base64");
const res = await fetch("https://www.sprite-ai.art/api/sprites/import", {
method: "POST",
headers: {
Authorization: "Bearer sai_sk_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({ image, title: "hero" }),
});
const { id } = await res.json(); // animate with source_generation_id: idimport base64, requests
image = base64.b64encode(open("hero.png", "rb").read()).decode()
res = requests.post(
"https://www.sprite-ai.art/api/sprites/import",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
json={"image": image, "title": "hero"},
).json()
sprite_id = res["id"] # animate with source_generation_id{
"id": "a1b2c3d4-...",
"status": "completed",
"width": 64,
"height": 64,
"title": "hero"
}GET/api/sprites/{id}
Fetch one of your past sprites.
curl https://www.sprite-ai.art/api/sprites/a1b2c3d4-... \
-H "Authorization: Bearer sai_sk_your_key_here"const res = await fetch(
"https://www.sprite-ai.art/api/sprites/a1b2c3d4-...",
{ headers: { Authorization: "Bearer sai_sk_your_key_here" } },
);
const sprite = await res.json();import requests
sprite = requests.get(
"https://www.sprite-ai.art/api/sprites/a1b2c3d4-...",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
).json()GET/api/sprites
List your sprites and animations, newest first.
| Parameter | Type | Description |
|---|---|---|
limit | integer | 1–100. Default 20. |
offset | integer | For pagination. Default 0. |
status | string | Filter by status. |
asset_type | string | Filter by type, e.g. animation. |
curl "https://www.sprite-ai.art/api/sprites?limit=20" \
-H "Authorization: Bearer sai_sk_your_key_here"const res = await fetch(
"https://www.sprite-ai.art/api/sprites?limit=20",
{ headers: { Authorization: "Bearer sai_sk_your_key_here" } },
);
const { sprites } = await res.json();import requests
sprites = requests.get(
"https://www.sprite-ai.art/api/sprites?limit=20",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
).json()["sprites"]POST/api/animations
Start an animation job from a source sprite. Asynchronous: returns an id immediately, then you poll until it finishes (~90s). The token cost scales with frame_count.
Reference the source by source_generation_id: the id of a sprite you own, from POST /api/sprites (generate) or POST /api/sprites/import. No image bytes travel through this call; we fetch them server-side. The source must be a single still sprite, no larger than 256px on either side, not a sprite sheet or an existing animation.
| Field | Type | Required | Description |
|---|---|---|---|
source_generation_id | string | Yes | UUID of a sprite you generated or imported. |
preset | string | Yes | Motion preset (Walk, Run, Idle, ...) or Custom. |
frame_count | integer | No | Even, 4–16. Default 8. Drives the token cost. |
custom_prompt | string | Custom only | Free-form motion. Required when preset is Custom. |
public | boolean | No | Add to the public gallery. Default false. |
The Custom preset requires a paid (Creator or higher) plan. On a free plan it returns 402 with code upgrade_required. Built-in presets work on any plan.
curl https://www.sprite-ai.art/api/animations \
-H "Authorization: Bearer sai_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "source_generation_id": "a1b2c3d4-...", "preset": "Walk", "frame_count": 8 }'const res = await fetch("https://www.sprite-ai.art/api/animations", {
method: "POST",
headers: {
Authorization: "Bearer sai_sk_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
source_generation_id: spriteId, // from generate or import
preset: "Walk",
frame_count: 8,
}),
});
const { id } = await res.json(); // poll GET /api/animations/{id}import requests
job = requests.post(
"https://www.sprite-ai.art/api/animations",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
json={"source_generation_id": sprite_id, "preset": "Walk", "frame_count": 8},
).json()
job_id = job["id"] # poll GET /api/animations/{id}{ "id": "a1b2c3d4-...", "status": "processing" }GET/api/animations/{id}
Poll an animation job. While running it returns processing with an optional progress (0–1). When status is completed, the sheet is in image.spritesheetBase64. On failed, tokens are refunded automatically. Poll about every 5 seconds.
# poll every ~5s until status is completed or failed
curl https://www.sprite-ai.art/api/animations/a1b2c3d4-... \
-H "Authorization: Bearer sai_sk_your_key_here"const headers = { Authorization: "Bearer sai_sk_your_key_here" };
while (true) {
await new Promise((r) => setTimeout(r, 5000));
const job = await (await fetch(
"https://www.sprite-ai.art/api/animations/" + id, { headers },
)).json();
if (job.status === "completed") { console.log(job.image.spritesheetBase64); break; }
if (job.status === "failed") { console.error("render failed"); break; }
}import time, requests
headers = {"Authorization": "Bearer sai_sk_your_key_here"}
while True:
time.sleep(5)
job = requests.get(
"https://www.sprite-ai.art/api/animations/" + job_id, headers=headers,
).json()
if job["status"] == "completed":
print(job["image"]["spritesheetBase64"]); break
if job["status"] == "failed":
print("render failed"); break{
"id": "a1b2c3d4-...",
"status": "completed",
"frameWidth": 64,
"frameHeight": 64,
"frameCount": 8,
"fps": 12,
"image": { "format": "png", "spritesheetBase64": "iVBORw0KGgoAAAANS..." }
}A single horizontal-strip PNG. Slice it with frameCount, frameWidth, frameHeight.
POST/api/animations/{id}/cancel
Cancel a running job and refund its tokens. If the job already completed or failed, it returns an error since there is nothing to cancel.
curl -X POST https://www.sprite-ai.art/api/animations/a1b2c3d4-.../cancel \
-H "Authorization: Bearer sai_sk_your_key_here"await fetch(
"https://www.sprite-ai.art/api/animations/" + id + "/cancel",
{ method: "POST", headers: { Authorization: "Bearer sai_sk_your_key_here" } },
);import requests
requests.post(
"https://www.sprite-ai.art/api/animations/" + job_id + "/cancel",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
){ "id": "a1b2c3d4-...", "status": "cancelled" }POST/api/restyles
Redraw a sprite you own in a different style: same character, same pose, new look. Asynchronous like animations: returns an id immediately, then you poll until it finishes (~15s typical, up to ~90s if a GPU worker has to boot). Flat cost: 4 tokens, presets and custom prompts alike.
Reference the source by source_generation_id: the id of a sprite you own, from POST /api/sprites (generate) or POST /api/sprites/import. No image bytes travel through this call; we fetch them server-side. The source must be 16-512px on each side; the result comes back at the source's size.
| Field | Type | Required | Description |
|---|---|---|---|
source_generation_id | string | Yes | UUID of a sprite you generated or imported, 16-512px per side. |
preset | string | One of preset / custom_prompt | Locked style: fire, ice, gold, zombie, holy, cursed, poison, royal, shadow, steampunk. |
custom_prompt | string | One of preset / custom_prompt | Free-form style instruction, up to 500 chars. Same price as a preset, any plan. |
public | boolean | No | Add to the public gallery. Default false. |
curl https://www.sprite-ai.art/api/restyles \
-H "Authorization: Bearer sai_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "source_generation_id": "a1b2c3d4-...", "preset": "gold" }'const res = await fetch("https://www.sprite-ai.art/api/restyles", {
method: "POST",
headers: {
Authorization: "Bearer sai_sk_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
source_generation_id: spriteId, // from generate or import
preset: "gold", // or custom_prompt: "obsidian armor, glowing runes"
}),
});
const { id } = await res.json(); // poll GET /api/restyles/{id}import requests
job = requests.post(
"https://www.sprite-ai.art/api/restyles",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
json={"source_generation_id": sprite_id, "preset": "gold"},
).json()
job_id = job["id"] # poll GET /api/restyles/{id}{ "id": "a1b2c3d4-...", "status": "processing" }GET/api/restyles/{id}
Poll a restyle job. While running it returns processing; when status is completed, the sprite is in image.pngBase64 at native resolution. On failed, tokens are refunded automatically. Poll about every 3 seconds.
# poll every ~3s until status is completed or failed
curl https://www.sprite-ai.art/api/restyles/a1b2c3d4-... \
-H "Authorization: Bearer sai_sk_your_key_here"const headers = { Authorization: "Bearer sai_sk_your_key_here" };
while (true) {
await new Promise((r) => setTimeout(r, 3000));
const job = await (await fetch(
"https://www.sprite-ai.art/api/restyles/" + id, { headers },
)).json();
if (job.status === "completed") { console.log(job.image.pngBase64); break; }
if (job.status === "failed") { console.error("restyle failed"); break; }
}import time, requests
headers = {"Authorization": "Bearer sai_sk_your_key_here"}
while True:
time.sleep(3)
job = requests.get(
"https://www.sprite-ai.art/api/restyles/" + job_id, headers=headers,
).json()
if job["status"] == "completed":
print(job["image"]["pngBase64"]); break
if job["status"] == "failed":
print("restyle failed"); break{
"id": "a1b2c3d4-...",
"status": "completed",
"width": 64,
"height": 64,
"isPublic": false,
"slug": null,
"image": { "format": "png", "pngBase64": "iVBORw0KGgoAAAANS..." }
}POST/api/restyles/{id}/cancel
Cancel a running restyle and refund its tokens. If the job already completed or failed, it returns an error since there is nothing to cancel.
curl -X POST https://www.sprite-ai.art/api/restyles/a1b2c3d4-.../cancel \
-H "Authorization: Bearer sai_sk_your_key_here"await fetch(
"https://www.sprite-ai.art/api/restyles/" + id + "/cancel",
{ method: "POST", headers: { Authorization: "Bearer sai_sk_your_key_here" } },
);import requests
requests.post(
"https://www.sprite-ai.art/api/restyles/" + job_id + "/cancel",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
){ "id": "a1b2c3d4-...", "status": "cancelled" }POST/api/normal-maps
Generate a tangent-space normal map for a sprite or animation you own, for dynamic lighting in a game engine. Our own model, trained on real 3D geometry rather than edge-detect heuristics: the output encodes the subject's actual form, and its alpha channel is a pixel-exact copy of the source silhouette. Synchronous: the finished PNG comes back inline in a few seconds, no job to poll. Cost: 1 token per frame.
An animation source is normal-mapped per frame automatically (the model is deterministic, so frames never flicker) and comes back as the same-layout horizontal strip. Load it in your engine exactly like the animation itself.
| Field | Type | Required | Description |
|---|---|---|---|
source_generation_id | string | Yes | UUID of a sprite or animation you own. Frames must be 32-256px per side. |
strength | number | No | Detail injection, 0-5, default 0. 0 is truest to the geometry; ~2.5 re-adds the sprite's drawn shading for a hand-crafted look. |
flip_green | boolean | No | Flip green for DirectX / +Y-down engines (Unreal). Default false = OpenGL / +Y-up (Godot, Unity, WebGL). |
columns | number | No | Only for a still that is really a sprite sheet: its column count. Ignored for animations (layout is known). columns x rows <= 24. |
rows | number | No | Sheet row count, with columns. Default 1. |
curl https://www.sprite-ai.art/api/normal-maps \
-H "Authorization: Bearer sai_sk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "source_generation_id": "a1b2c3d4-..." }'const res = await fetch("https://www.sprite-ai.art/api/normal-maps", {
method: "POST",
headers: {
Authorization: "Bearer sai_sk_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
source_generation_id: spriteId, // a sprite OR an animation
}),
});
const map = await res.json(); // completed inline, no polling
// convention most engines auto-detect: save as <sprite-name>_n.pngimport base64, requests
map = requests.post(
"https://www.sprite-ai.art/api/normal-maps",
headers={"Authorization": "Bearer sai_sk_your_key_here"},
json={"source_generation_id": sprite_id},
).json()
with open("sprite_n.png", "wb") as f:
f.write(base64.b64decode(map["image"]["pngBase64"])){
"id": "e5f6a7b8-...",
"status": "completed",
"width": 64,
"height": 64,
"frameCount": 1,
"tokensSpent": 1,
"image": { "format": "png", "pngBase64": "iVBORw0KGgoAAAANS..." }
}Errors
Every error returns the same JSON shape. Branch on code, not message.
{ "code": "invalid_request", "message": "...", "details": {} }| HTTP | Code | Cause |
|---|---|---|
400 | invalid_request | Body failed validation. |
401 | invalid_api_key | Key missing or not recognized. |
402 | insufficient_tokens | Not enough tokens. |
402 | upgrade_required | Needs a paid plan. |
403 | api_key_revoked | The key was revoked. |
404 | not_found | Not found, or not yours. |
422 | nsfw_prompt | Prompt rejected by the filter. |
429 | rate_limited | Too many requests. |
500 | provider_failure | Render failed. Tokens refunded. |
Last updated August 11, 2026