Documentation

API Reference

Look up each supported public endpoint with auth, payload, status, and response details.

Last updated: July 17, 2026

This is the customer integration reference for the public ImageGrid API. It covers plan discovery, account context, source uploads, async jobs, generated tiles, artifact metadata, and signed artifact downloads.

Account signup, email verification, plan activation, billing, and API key issuance happen in the web UI. Use this reference for the JSON API your application calls.

  • Base API host: https://api.imagegrid.dev
  • Public docs host: https://imagegrid.dev
  • Machine-readable spec: OpenAPI JSON

How to use this reference

Use this page when you need the endpoint-by-endpoint contract. For task-oriented walkthroughs, start with Getting Started, Uploads and Jobs, or Artifacts and Downloads.

Each endpoint block follows the same order:

Field Meaning
Auth Whether the request needs an API key, signed URL, or no credentials.
Request Path parameters, query parameters, body format, and content type.
Success Expected success status and response shape.
Common failures Statuses a client should handle intentionally.

Authentication

Use API keys for authenticated API routes. Send the key in either header:

HTTP
Authorization: Bearer igk_...
HTTP
X-API-Key: igk_...

Signed artifact download URLs do not use API-key auth. Use the download_url exactly as returned by GET /v1/artifacts/{id} before it expires.

Request lifecycle

Most image workflows follow this sequence:

  1. Create an API key in the web UI.
  2. Upload a source image with POST /v1/assets.
  3. Create a processing job with POST /v1/jobs.
  4. Poll GET /v1/jobs/{id} until the job reaches a terminal state.
  5. Read artifact metadata with GET /v1/artifacts/{id}.
  6. Download bytes with the returned signed download_url.

Tile workflows add one more option: jobs that create a tileset can serve individual XYZ tiles through GET /v1/tilesets/{id}/xyz/{z}/{x}/{y} with API-key auth.

Endpoint index

Method Path Auth Purpose
GET /v1/plans None List public plans and plan limits.
GET /v1/account API key Read account identity and current key permissions.
POST /v1/assets API key Upload a source image asset.
POST /v1/jobs API key Create an async image-processing job.
GET /v1/jobs/{id} API key Poll job state and generated artifacts.
GET /v1/tilesets/{id}/xyz/{z}/{x}/{y} API key Download one generated XYZ tile.
GET /v1/artifacts/{id} API key Read artifact metadata and a short-lived download URL.
GET /v1/artifacts/{id}/download Signed URL Download artifact bytes.

GET /v1/plans

Lists the public commercial plans currently available for self-serve customers.

Property Value
Auth None
Request body None
Rate limit 120 requests/minute/IP
Success 200 OK
Common failures 429, 500

Example:

BASH
curl https://api.imagegrid.dev/v1/plans

Response:

JSON
{
  "plans": [
    {
      "code": "starter",
      "display_name": "Starter",
      "description": "For smaller sites, storefronts, creators, and lighter production workloads.",
      "status": "active",
      "is_public": true,
      "billing_amount_minor": 1000,
      "billing_interval": "monthly",
      "included_processing_credits": 2000,
      "limits": {
        "max_upload_bytes": 20971520,
        "max_input_edge_pixels": 6000,
        "max_input_megapixels": 24,
        "max_output_edge_pixels": 6000,
        "max_output_megapixels": 24,
        "max_generated_tiles_per_job": 25000,
        "max_artifact_bytes_per_job": 1073741824,
        "retention_ttl_seconds": 86400,
        "max_grid_render_megapixels": 4,
        "max_tile_patch_megapixels_per_job": 1,
        "max_tile_patch_patches_per_job": 1,
        "max_in_flight_jobs": 10
      }
    }
  ]
}

included_processing_credits is the customer-facing allowance for the billing period. limits carries hard caps that still apply while credit remains. Limit keys with no configured value are omitted. The same credit pool applies across resize, optimize, tile, grid-render, and tile-patch traffic.

GET /v1/account

Returns account context for the authenticated API key.

Property Value
Auth API key
Request body None
Rate limit 240 requests/minute/account
Success 200 OK
Common failures 401, 429

Example:

BASH
curl \
  -H "Authorization: Bearer igk_..." \
  https://api.imagegrid.dev/v1/account

Response:

JSON
{
  "account": {
    "id": "00000000-0000-0000-0000-000000000000",
    "slug": "acme",
    "display_name": "Acme"
  },
  "subject_type": "api_key",
  "api_key": {
    "id": "00000000-0000-0000-0000-000000000000",
    "name": "production-runtime",
    "role_code": "api_runtime"
  },
  "permissions": [
    "account.read"
  ],
  "plan": {
    "code": "growth",
    "display_name": "Growth",
    "status": "active",
    "access_source": "stripe"
  },
  "quotas": {
    "processing_credits_monthly": {
      "limit": 10000,
      "interval_seconds": 2592000
    },
    "max_grid_render_megapixels": {
      "limit": 100
    }
  },
  "effective_limits": {
    "grid_megapixels": 100,
    "tile_estimate": 100000,
    "storage_estimate_bytes": 4294967296,
    "processing_credits": 10000
  },
  "usage": {
    "processing_credits": {
      "used": 2500,
      "remaining": 7500,
      "limit": 10000
    },
    "cdn_delivery_bytes": {
      "used": 0
    }
  },
  "features": {
    "cdn_delivery": true
  },
  "entitlements": {
    "cdn_delivery": {
      "enabled": true,
      "feature_code": "cdn_delivery",
      "status": "active",
      "source": "stripe",
      "provider": "bunny",
      "add_on_code": "cdn_delivery",
      "cancel_at_period_end": false
    }
  }
}

Use this endpoint as a lightweight credentials check when wiring a new integration. Integrations that need ImageGrid-managed CDN delivery should check features.cdn_delivery or entitlements.cdn_delivery.enabled before enabling CDN-backed behavior.

POST /v1/assets

Uploads a source image and returns stored asset metadata.

Property Value
Auth API key
Content type multipart/form-data
Required body file part
Rate limit 30 requests/minute/account
Success 201 Created
Common failures 400, 401, 403, 415, 429, 503

Supported source formats are still-image jpeg, png, webp, gif, avif, heif, and jxl when the current runtime can decode them. GIF output is flattened to a single still frame.

Plan upload caps are enforced before processing. Current self-serve upload caps are 20 MiB on Starter and 50 MiB on Growth; larger workloads can use the contact path for review.

Example:

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

Response:

JSON
{
  "id": "00000000-0000-0000-0000-000000000000",
  "account_id": "00000000-0000-0000-0000-000000000000",
  "source_type": "upload",
  "status": "ready",
  "original_filename": "source.png",
  "content_type": "image/png",
  "checksum_sha256": "abc123...",
  "byte_size": 182736,
  "width": 1600,
  "height": 900,
  "storage_key": "assets/.../original.png",
  "created_at": "2026-04-15T12:00:00Z"
}

POST /v1/jobs

Creates an async image-processing job.

Property Value
Auth API key
Content type application/json
Operations resize, optimize, tile, grid_render, tile_patch
Rate limit 60 requests/minute/account
Success 201 Created
Common failures 400, 401, 404, 429

Accepted jobs may wait longer in the queue when the service is busy. ImageGrid does not return a separate queue-busy error for ordinary backlog pressure. A capacity-style 429 with code: "worker_capacity_exceeded" is reserved for jobs that exceed current processing limits.

Resize request:

JSON
{
  "asset_id": "00000000-0000-0000-0000-000000000000",
  "operation": "resize",
  "options": {
    "width": 320,
    "fit": "inside",
    "format": "webp"
  }
}

Grid render request:

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

Success response:

JSON
{
  "id": "00000000-0000-0000-0000-000000000000",
  "asset_id": "00000000-0000-0000-0000-000000000000",
  "operation": "resize",
  "status": "queued",
  "options": {
    "width": 320,
    "fit": "inside",
    "format": "webp",
    "quality": 80
  },
  "result": {},
  "queued_at": "2026-04-15T12:00:00Z",
  "updated_at": "2026-04-15T12:00:00Z",
  "attempt_count": 0,
  "max_attempts": 3,
  "artifacts": []
}

See Operations for the full options schema for each operation.

GET /v1/jobs/{id}

Reads the current state of a job and any generated artifacts.

Property Value
Auth API key
Path parameters id UUID
Request body None
Rate limit 240 requests/minute/account
Success 200 OK
Common failures 400, 401, 404, 429

When polling is throttled, respect the Retry-After header and retry with exponential backoff plus jitter instead of hot-loop polling.

Response:

JSON
{
  "id": "00000000-0000-0000-0000-000000000000",
  "asset_id": "00000000-0000-0000-0000-000000000000",
  "operation": "resize",
  "status": "succeeded",
  "options": {
    "width": 320,
    "fit": "inside",
    "format": "webp",
    "quality": 80
  },
  "result": {},
  "queued_at": "2026-04-15T12:00:00Z",
  "started_at": "2026-04-15T12:00:02Z",
  "completed_at": "2026-04-15T12:00:03Z",
  "updated_at": "2026-04-15T12:00:03Z",
  "attempt_count": 1,
  "max_attempts": 3,
  "artifacts": [
    {
      "id": "00000000-0000-0000-0000-000000000000",
      "kind": "primary",
      "content_type": "image/webp",
      "byte_size": 9201,
      "width": 320,
      "height": 180,
      "checksum_sha256": "abc123...",
      "metadata": {},
      "created_at": "2026-04-15T12:00:03Z"
    }
  ]
}

Failed jobs keep the same shape and can add error_code and error_message. See Errors for retry guidance.

For completed tile, grid_render, and tile_patch jobs, accounts with the cdn_delivery entitlement receive direct browser delivery fields in result:

JSON
{
  "tileset_id": "00000000-0000-0000-0000-000000000000",
  "version": 3,
  "format": "png",
  "public_tile_url_template": "https://cdn.imagegrid.dev/cdn/tilesets/00000000-0000-0000-0000-000000000000/v/3/xyz/{z}/{x}/{y}.png?expires=1784275200&sig=abcd...",
  "tile_url_template": "https://cdn.imagegrid.dev/cdn/tilesets/00000000-0000-0000-0000-000000000000/v/3/xyz/{z}/{x}/{y}.png?expires=1784275200&sig=abcd..."
}

The template contains {z}, {x}, and {y} placeholders for XYZ clients. It resolves to public tile bytes with CORS enabled and versioned public cache headers. The /v/{version}/ path and signature change when a tileset version changes, including tile_patch rerenders and rotation/preprocess rebuilds. The signed expiry prevents edge caches from outliving the delivery window. Deleted or expired tilesets stop resolving at the origin.

Browser tile clients should prefer public_tile_url_template or tile_url_template when present and substitute {z}, {x}, and {y} directly. Accounts without cdn_delivery do not receive these fields and should keep using an authenticated or local proxy fallback.

GET /v1/tilesets/{id}/xyz/{z}/{x}/{y}

Downloads one generated XYZ tile from a tileset owned by the authenticated account.

Property Value
Auth API key
Path parameters id UUID, z zoom level, x tile column, y tile row including extension such as 0.png
Request body None
Success 200 OK with tile bytes
Common failures 400, 401, 404

This endpoint is useful when a tile, grid_render, or tile_patch workflow produces a reusable tileset and the client wants to request individual map-style tiles through an authenticated application server or proxy. It remains the fallback when public CDN delivery fields are not present.

Example:

HTTP
GET /v1/tilesets/{id}/xyz/4/0/0.png
Authorization: Bearer igk_...

Successful responses return tile bytes with the generated tile content type, such as image/png, image/jpeg, or image/webp.

GET /v1/artifacts/{id}

Loads artifact metadata plus a short-lived signed download URL.

Property Value
Auth API key
Path parameters id UUID
Request body None
Rate limit 240 requests/minute/account
Success 200 OK
Common failures 400, 401, 404, 429

Response:

JSON
{
  "id": "00000000-0000-0000-0000-000000000000",
  "kind": "primary",
  "content_type": "image/webp",
  "byte_size": 9201,
  "width": 320,
  "height": 180,
  "checksum_sha256": "abc123...",
  "metadata": {},
  "created_at": "2026-04-15T12:00:03Z",
  "download_url": "https://api.imagegrid.dev/v1/artifacts/00000000-0000-0000-0000-000000000000/download?expires=1760000000&sig=abcd...",
  "download_expires_at": "2026-04-15T12:15:03Z"
}

Fetch this endpoint again if a previously issued signed URL expires.

GET /v1/artifacts/{id}/download

Downloads artifact bytes directly. This endpoint uses signed expires and sig query parameters rather than API-key auth.

Property Value
Auth Signed URL
Path parameters id UUID
Query parameters expires Unix timestamp, sig HMAC signature
Request body None
Rate limit 600 requests/minute/IP
Success 200 OK with artifact bytes
Common failures 400, 403, 404, 429

Example:

HTTP
GET /v1/artifacts/{id}/download?expires=<unix>&sig=<hex>

Use the full download_url returned by GET /v1/artifacts/{id}. Do not construct signatures client-side.

Status and error model

Successful write requests use 201 Created; successful reads use 200 OK. Error responses are JSON and always include at least an error string:

JSON
{
  "error": "invalid api key"
}

Some policy failures include a stable code, such as worker_capacity_exceeded, when the client can make a more specific decision. See Errors for validation failures, signed-download failures, retry behavior, and async job failure fields.

Source of truth

The machine-readable contract lives at OpenAPI JSON. This page is the readable companion for humans who want examples, integration order, and failure notes alongside the endpoint list.