# Spritekick API

> Generate the same character references and transparent, game-ready animations as Spritekick Studio, from your own code.

- Base URL: `https://spritekick.com/api/v1`
- Authentication: `Authorization: Bearer YOUR_API_KEY`
- Machine-readable contract: https://spritekick.com/api/openapi.json (OpenAPI 3.1)
- This page in HTML: https://spritekick.com/api/docs
- This page in Markdown: https://spritekick.com/api/docs.md

## Get a key

An account holder creates named keys at https://spritekick.com/account#api and can show, hide, copy, or revoke each key independently there. A key
carries either read-only or read/write scope. Send it in the `Authorization: Bearer` header and nowhere else: the API
reads no cookie, no query parameter, and no body field.

## Quick start

Start with the catalog. It is the source of truth for every supported option.

```bash
curl https://spritekick.com/api/v1/catalog \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

Create a character with the same camera and style choices shown in Studio.

```bash
curl https://spritekick.com/api/v1/characters \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Kiko","description":"A fox courier","orientation":"platformer","style":"pixel"}'
```

After its reference job completes, create an animation.

```bash
curl https://spritekick.com/api/v1/characters/CHARACTER_ID/animations \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"pose":"walk","quality":"standard"}'
```

Read `GET /animations/{animationId}` until `sheet.status` is `ready`, then download `sheet.links.png`
or any other `sheet.links` entry (see Download formats below) with the same bearer key. The default download routes return
`202` with `Retry-After: 3` while the export is pending. The optional `links.viewer` opens Studio for review.

## Download formats

Every export can be downloaded six ways. The first five hold the same sheet.

- `sheet.png` (`links.png`): the transparent PNG sheet alone.
- `sheet.zip` (`links.sheetZip`): the PNG sheet and its manifest as `<name>.png` and `<name>.json`.
- `frames.zip` (`links.frames`): one PNG for each frame, and `manifest.json`.
- `manifest.json` (`links.manifest`): the grid, frame size, pivot, rate and loop flag.
- `godot.zip` (`links.godot`): a Godot 4 folder with the sheet, a `SpriteFrames` resource (`.tres`) that holds
  every frame with its rate and loop flag, and an `AnimatedSprite2D` scene (`.tscn`) whose origin is the
  character's footing. Unpack the folder anywhere in a Godot project and open the scene.
- `video.mp4` (`links.video`): the raw video, the same as Studio's "Raw video (MP4)" format. It is the animation
  itself, cut to the export's clip and to one fixed rectangle that holds the character on every frame. It keeps the
  background, the animation's own frame rate and tempo, and has no sound. The frame rate, sprite height, scale,
  layout and speed settings shape only the sheet, so exports that differ only in those hold the same video.

## Export settings

Exports cost no tokens and use the same controls as Studio. Request another export with
`POST /animations/{animationId}/renders` and a JSON object:

```json
{"fps":15,"spriteHeight":64,"scalePercentage":100,"layout":"grid","clip":"cycle","speed":1}
```

- Frame rate: 8, 10, 12, 15 (default), or 24.
- Sprite height: 32, 48, 64, 96, 128, 192, or the original size (default).
- Scale percentage: an integer from 1 to 100; default 100.
- Layout: `grid` (default) or `row`.
- Speed: 0.5, 0.75, 1 (default), 1.25, 1.5, 2, 2.5, or 3. A speed keeps the frame rate and changes how many frames one
  pass holds, so `2` plays the animation twice as fast with half the frames.
- Clip: `cycle` (default) or `full`. The cycle falls back to the full animation when no cycle is found.
- Sampling follows the character style: Pixel Art uses nearest sampling; other styles use smooth sampling.
- A measured cycle plays at the pose tempo. The manifest gives the actual playback rate and each frame's sample timestamp.
- Custom trim ranges are not supported in v1.

The request returns `202` for a pending export or `200` for a cached ready export. Poll its `links.self`
and download any of its links when ready. New exports are limited to 10 per
minute per API key; cached exports do not use that limit. Non-default exports expire after 7 days and can be requested again.
If an export fails with `render_failed`, request the same settings again to start a new export. It has a new id,
uses no tokens, and counts toward the export limit.
The API serves exports only; the uncut source animation cannot be downloaded.

## Objects and textures

`POST /characters` takes an optional `kind`: `character` (default), `object`, or `texture`.

- An `object` is a building, prop, vehicle or other entity. It uses a camera and style like a character, and it uses
  the object animations: the catalog animations whose `kind` is `object`, or a custom animation.
- A `texture` is one flat surface seen from straight above, made seamless so it repeats. It takes no `orientation`.
  It takes an optional `tiling`: `both` (default), `horizontal`, or `vertical`. A one-way tiling keeps the
  other edges as drawn, for wall bands and trims. A texture has no animations.
- When its reference job completes, download the tile from `links.texture` or `GET /characters/{characterId}/texture.png?size=256`.
  Every size is the 1024-pixel tile reduced by a power of two, so every size repeats exactly.

```json
{"kind":"texture","name":"Mossy cobbles","description":"Mossy grey cobblestones with dark grout","style":"painted","tiling":"both"}
```

## Animation resolution

`POST /characters/{characterId}/animations` and `POST /animations/{animationId}/revisions` take an optional
`resolution` field:

```json
{"pose":"walk","quality":"standard","resolution":"low"}
```

- `standard` (default): the style's normal resolution. Omitting the field or sending `null` is the same.
- `low`: the lowest available resolution, for any style. Detail is softer, most visibly at large export sizes.
  The token cost does not change.
- Each request chooses for itself. A revision is `standard` unless it sends `"low"` again.
- Every animation reports its `resolution`, and `GET /catalog` lists the supported values.

## Endpoints

Every path is relative to `https://spritekick.com/api/v1`.

| Method | Path | Action |
| --- | --- | --- |
| GET | `/catalog` | List cameras, styles, qualities, and animations. |
| GET | `/tokens` | Read the account token balance. |
| GET | `/characters` | List your characters, objects and textures. |
| POST | `/characters` | Create a character, object or texture and generate its reference. |
| PATCH | `/characters/{characterId}` | Set visibility to public or private. New characters are public. |
| GET | `/characters/{characterId}` | Read one character and its reference status. |
| DELETE | `/characters/{characterId}` | Delete a character and all its animations. |
| POST | `/characters/{characterId}/reference` | Generate a missing or failed reference. |
| GET | `/characters/{characterId}/reference.png` | Download the reference image, or a texture's full tile. |
| GET | `/characters/{characterId}/texture.png` | Download a texture tile at one size (`?size=1024` to `32`). |
| GET | `/characters/{characterId}/animations` | List a character's animations. |
| POST | `/characters/{characterId}/animations` | Generate a standard, premium, or custom animation. |
| GET | `/animations/{animationId}` | Read animation progress, measurements and export status. |
| GET | `/animations/{animationId}/sheet.png` | Download the default transparent PNG sheet. |
| GET | `/animations/{animationId}/sheet.zip` | Download the default PNG sheet with its manifest. |
| GET | `/animations/{animationId}/frames.zip` | Download default PNG frames and manifest. |
| GET | `/animations/{animationId}/manifest.json` | Read the default sheet manifest. |
| GET | `/animations/{animationId}/godot.zip` | Download the default export as a Godot 4 SpriteFrames folder. |
| GET | `/animations/{animationId}/video.mp4` | Download the default export's raw video, cut to the character. |
| POST | `/animations/{animationId}/renders` | Request an export with Studio settings. |
| GET | `/renders/{renderId}` | Read export status and download links. |
| GET | `/renders/{renderId}/sheet.png` | Download an export's PNG sheet. |
| GET | `/renders/{renderId}/sheet.zip` | Download an export's PNG sheet with its manifest. |
| GET | `/renders/{renderId}/frames.zip` | Download an export's frame ZIP. |
| GET | `/renders/{renderId}/manifest.json` | Read an export's manifest. |
| GET | `/renders/{renderId}/godot.zip` | Download an export as a Godot 4 SpriteFrames folder. |
| GET | `/renders/{renderId}/video.mp4` | Download an export's raw video, cut to the character. |
| PATCH | `/animations/{animationId}` | Name or favorite an animation. |
| DELETE | `/animations/{animationId}` | Delete an animation. |
| POST | `/animations/{animationId}/revisions` | Generate a revision with a change note. |
| GET | `/jobs/{jobId}` | Read generation status and progress. |
| POST | `/jobs/{jobId}/feedback` | Rate a completed generation. |

## How generation works

- Generation is asynchronous. A `POST` that starts work answers `202 Accepted` with the job id and a `Location`
  header pointing at the resource to read next.
- `GET /jobs/{jobId}` reports `status` (`queued`, `generating`, `processing`, `complete`, `failed`, or
  `cancelled`), the current `stage`, and `progress` from 0 to 100.
- You do not have to poll. Every generation started through the API emails the account address when it lands or fails,
  with a link straight to it. Work started in Studio is not emailed: the page it was started on already follows it.
- Each request generates once. There is no reroll and no automatic retry, so a result is never silently replaced by a
  second attempt. Tell us about a bad one with `POST /jobs/{jobId}/feedback`.
- Characters are public by default. Anyone with a web link can view their generated references and animations without signing in. Set visibility to private to require owner sign-in. Uploads stay private, and all versioned API endpoints require an API key.
- `GET /tokens` reads the balance. The API cannot buy or refill tokens; that happens in the web application.

## Errors

Every failure is JSON in one shape:

```json
{"error":{"code":"not_found","message":"Character not found."}}
```

Generation inputs are checked before tokens are reserved. A `content_rejected` response means you must remove explicit sexual content from the text and submit the edited input. A `content_check_unavailable` response means the check could not finish; submit later. Neither response starts generation or charges tokens.

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `invalid_request, invalid_json, invalid_image` | The body or a query parameter is wrong. The message names the field. |
| 400 | `content_rejected` | Remove explicit sexual content from the text. No tokens were charged. |
| 503 | `content_check_unavailable` | The input check could not finish. Submit later. No tokens were charged. |
| 401 | `unauthorized` | The key is missing, malformed, or revoked. |
| 402 | `insufficient_tokens` | The balance is too low for this generation. Refills happen in the web application. |
| 403 | `insufficient_scope` | The key is read-only and the call writes. |
| 404 | `not_found` | No such character, animation, job, or asset on this account. |
| 409 | `conflict` | The resource is in the wrong state, such as rating a generation that is still running. |
| 413 | `request_too_large` | The upload request is over 21 MiB. |
| 422 | `render_failed, generation_failed, generation_refused` | The export or generation failed, or a content safety check declined the request. The message is safe to show to the customer. |
| 429 | `rate_limited` | Wait before requesting a new export configuration. |
| 503 | `generation_start_failed` | The work could not be started and the tokens were returned to the account. |

## Paging and limits

- List endpoints take `limit` (1 to 100, default 50) and an opaque `cursor`, and return the next cursor in
  `links.next`, or `null` on the last page.
- A source image or style reference is uploaded as `multipart/form-data` and must be 10 MB or less, inside a request
  under 21 MiB.

## Help

Signed-in customers reach a person through https://spritekick.com/support.
