Documentation

Uploads and Jobs

Upload images, create async jobs, and structure resize, optimize, tile, grid_render, or tile_patch requests.

Last updated: May 11, 2026

Uploads and processing are intentionally split into two steps.

1. Upload the source asset

POST /v1/assets

  • Requires an API key.
  • Accepts still-image jpeg, png, webp, gif, avif, heif, and jxl uploads when the current runtime can decode them.
  • GIF and animated GIF inputs are handled as still images. Outputs are flattened to one frame.
  • Animated WebP is not part of the default upload path.
  • Validates MIME type and upload size.
  • Applies an account rate limit of 30 uploads per minute.
  • Stores the source image for later processing jobs.

Example:

BASH
curl -X POST \
  -H "Authorization: Bearer igk_..." \
  -F "file=@/path/to/source.png" \
  https://api.imagegrid.dev/v1/assets

2. Create an async job

POST /v1/jobs

  • Applies an account rate limit of 60 job-creation requests per minute.
  • Accepted jobs may stay queued longer when the service is busy.
  • Queue pressure does not introduce a separate busy rejection for ordinary backlog.
  • A synchronous 429 with code: "worker_capacity_exceeded" is only used when one job exceeds current processing limits.

Supported operations:

  • resize
  • optimize
  • tile
  • grid_render
  • tile_patch

Resize example:

JSON
{
  "asset_id": "6ea91098-6c8c-46ec-869a-a3ef2d4f4d2c",
  "operation": "resize",
  "options": {
    "width": 1600,
    "height": 900,
    "fit": "inside",
    "format": "webp"
  }
}

Optimize example:

JSON
{
  "asset_id": "6ea91098-6c8c-46ec-869a-a3ef2d4f4d2c",
  "operation": "optimize",
  "options": {
    "format": "jpeg",
    "quality": 82
  }
}

Tile example:

JSON
{
  "asset_id": "6ea91098-6c8c-46ec-869a-a3ef2d4f4d2c",
  "operation": "tile",
  "options": {
    "tile_size": 128,
    "format": "png",
    "strategy": "deepzoom"
  }
}

Grid render example:

JSON
{
  "operation": "grid_render",
  "options": {
    "width": 640,
    "height": 320,
    "block_width": 32,
    "block_height": 32,
    "format": "png"
  }
}

Tile patch example:

JSON
{
  "operation": "tile_patch",
  "options": {
    "tileset_id": "6ea91098-6c8c-46ec-869a-a3ef2d4f4d2c",
    "patches": [
      {
        "type": "color",
        "color": "#ff0000",
        "x": 0,
        "y": 0,
        "width": 32,
        "height": 32
      }
    ]
  }
}

3. Poll the job

GET /v1/jobs/{id}

The response includes status plus any generated artifacts.

Polling is rate limited to 240 requests per minute per account. If you receive 429, honor Retry-After and back off with jitter instead of retrying immediately.

Typical statuses:

  • queued
  • processing
  • succeeded
  • failed

Operational notes

  • Quotas may deny uploads or jobs before processing starts.
  • Optional AV scanning can fail closed when the scanner is unavailable.
  • Artifact bytes are not returned inline from the job endpoint. Use artifact metadata and signed download URLs instead.
  • grid_render and tile_patch do not take asset_id. resize, optimize, and tile do.
  • If your workflow needs animation preserved, read Animated Image Support before relying on the default still-image path.
  • See Operations for the complete option schemas and defaults.

Error-handling guidance

  • Treat 429-style quota or policy failures as actionable, not retry-forever failures.
  • Retry transient 5xx responses with backoff.
  • Record the asset ID and job ID in your logs so support can trace the run later.
  • Read Errors for signed download failures, validation details, and async job failure fields.