# API reference

> Image Asset Server API 0.1.0: every endpoint, parameter and response. Machine-readable: https://image.shep.bot/openapi.json

## GET /v1/search

Search every source (`searchImages`)

Fans out to every enabled source in parallel (each with its own timeout), then merges and ranks. Words like `4k`, `high resolution`, `vertical`, `16:9`, `png`, `svg`, `transparent` in `q` become filters (see `filters` in the response); explicit parameters win. Unknown orientation, size or transparency stay in the list, ranked below known matches, unless `strict=true`. A slow or failing source never fails the search: it shows up in `providers` with its status.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `q` | query | string | Short query, written like a designer would. |
| `category` | query | string | Comma-separated categories; a parent includes its children. Top level: nature, animals, city, architecture, people, food, objects, tech, transport, space, science, art, archive, background, icons, other; children like `nature.ocean`, `art.painting`, `space.planets`, `archive.map`. |
| `style` | query | string | Comma-separated kinds and looks: photo, illustration, painting, drawing, vector, icon, transparent, black-white. `vector` and `icon` filter strictly; the others rank first (filtered only with strict=true). |
| `orientation` | query | string | Comma-separated: landscape, portrait, square. |
| `min_resolution` | query | string | Short side at least: 720, 1080, 1440, 2160, or hd / fhd / large / 4k. Vectors always pass. |
| `transparent` | query | boolean | Only images with a transparent background. |
| `format` | query | string | Comma-separated formats: jpg, png, svg, webp, tif. |
| `commercial` | query | boolean | Only images whose licence verdict is `yes` or `yes-with-credit`. |
| `free` | query | boolean | Only free images. |
| `downloadable` | query | boolean | Only images with direct file links. |
| `strict` | query | boolean | Drop images whose orientation, size or transparency is unknown when that filter is set. |
| `providers` | query | string | Comma-separated source ids (see /v1/providers). |
| `limit` | query | integer | Max results (default 24). |
| `offset` | query | integer | Per-source offset for paging (e.g. 24 for page 2). |

Responses: `200` Ranked results, the filters in force and a per-source report. (SearchResponse); `400` Invalid parameters or unknown source id. (Error); `401` API key required (self-hosted servers only). (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://image.shep.bot/v1/search?category=nature.ocean&style=painting&orientation=portrait&min_resolution=1080&format=svg&providers=nasa%2Cwikimediacommons"
```

## GET /v1/images/{id}

Image details, files and display URL (`getImage`)

Full metadata, the licence with its verdict and credit line, every file (original, resized copies, thumbnail) and the file a browser should show.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Image id `<provider>:<nativeId>` (URL-encode it: ids can contain spaces, slashes and colons). |

Responses: `200` The image and its files. (ImageDetails); `400` Malformed id or unknown source. (Error); `404` Unknown image. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error); `501` The source has no detail pages here; open `url` on the source site. (Error); `502` The source site failed. (Error)

```bash
curl "https://image.shep.bot/v1/images/nasa:PIA03606"
```

## GET /v1/images/{id}/files

Pick the right file (`selectFiles`)

The best file for a width and format (the original by default), or every file with `all=true`, with sizes and the licence.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Image id `<provider>:<nativeId>` (URL-encode it: ids can contain spaces, slashes and colons). |
| `width` | query | integer | Wanted width in pixels (e.g. 1600 for a web hero): the smallest file at least that wide, else the biggest below. An SVG original always fits. |
| `format` | query | string | Preferred format: jpg, png, svg, webp, tif. |
| `role` | query | "original" \| "rendition" \| "thumbnail" | Only files with this role: original, rendition, thumbnail. |
| `all` | query | boolean | Every file, including thumbnails. |

Responses: `200` Selected files and total size. (FileSelection); `404` Unknown image. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://image.shep.bot/v1/images/nasa:PIA03606/files"
```

## GET /v1/images/{id}/download

Download (redirect to the source) (`downloadImage`)

Answers 302 to the chosen file on the source: the image never passes through this server. `width` picks a resized copy (the smallest at least that wide), `format` a format. The licence and credit line come back as `X-License` and `X-Attribution` headers; get the credits as files from `/v1/images/{id}/credits`.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Image id `<provider>:<nativeId>` (URL-encode it: ids can contain spaces, slashes and colons). |
| `width` | query | integer | Wanted width in pixels (e.g. 1600 for a web hero): the smallest file at least that wide, else the biggest below. An SVG original always fits. |
| `format` | query | string | Preferred format: jpg, png, svg, webp, tif. |
| `role` | query | "original" \| "rendition" \| "thumbnail" | Only files with this role: original, rendition, thumbnail. |

Responses: `302` Redirect to the file.; `404` Unknown image, or no file matches. (Error); `409` No direct download: get it from the source page. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl -L -O "https://image.shep.bot/v1/images/nasa:PIA03606/download"
```

## GET /v1/images/{id}/credits

Credits for an image (`imageCredits`)

ATTRIBUTION.md (default), credits.json, or a zip holding both. No image inside.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Image id `<provider>:<nativeId>` (URL-encode it: ids can contain spaces, slashes and colons). |
| `format` | query | "md" \| "json" \| "zip" |  |

Responses: `200` The credits. (string); `404` Unknown image. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://image.shep.bot/v1/images/nasa:PIA03606/credits"
```

## POST /v1/sets

Pick images for a page, deck or post (`planImageSet`)

One image per slot, matching the slot's orientation and kind, at least half the slot's width where possible, commercial-safe by default and directly downloadable; alternatives per slot. Returns the plan and the files to save: images.json (src, size, alt text, licence and credit per pick), credits.html (<figure> snippets with credit captions), download.sh and the credits.

Responses: `200` The plan and its exports. (SetResponse); `400` Invalid body. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl -X POST "https://image.shep.bot/v1/sets" \
  -H "content-type: application/json" -H "accept: application/json, text/event-stream" \
  -d '{}'
```

## GET /v1/providers

List sources (`listProviders`)

Every image site with the categories it carries, pricing, licence, the filters it applies itself and whether files can be downloaded directly.

Responses: `200` Sources. (object); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://image.shep.bot/v1/providers"
```

## GET /v1/catalog

Catalog census (`getCatalog`)

How many images every source holds, counted once a day: listings per source, by top-level category, licence and the source's own categories, free counts, listings added in the last 30 days, and highlights such as the most downloaded image. `atLeast: true` marks lower bounds (sources that cap their counts). Sources whose count failed today keep their last good numbers with `stale`. The same file is at `/catalog.json`; one point per day is in `/catalog-history.json`.

Responses: `200` Catalog census. (Catalog); `404` The census has not been built on this server. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://image.shep.bot/v1/catalog"
```

## GET /v1/stats

Usage statistics (`getStats`)

Aggregate usage of this server: searches by surface (web, API, MCP), downloads, MCP tool calls, the client families and categories searched most, and per-source health (success rate, p50/p95 latency). Counts come from Prometheus (`source: prometheus`, last 24 hours and 7 days) or, when it is unavailable, from this process since it started (`source: process`). No queries, IPs or user agents are exposed. Cached for 60 seconds.

Responses: `200` Usage statistics. (Stats); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://image.shep.bot/v1/stats"
```

## POST /mcp

MCP endpoint (Streamable HTTP) (`mcp`)

Stateless Model Context Protocol endpoint for AI agents. Tools: `search_images`, `get_image`, `build_image_set`, `list_sources` (and `download_image` on local installs, which saves files with their credits). Point any MCP client at this URL; see /docs/mcp for per-client setup.

Responses: `200` JSON-RPC 2.0 response. (object); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl -X POST "https://image.shep.bot/mcp" \
  -H "content-type: application/json" -H "accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_images","arguments":{"query":"mountain lake at sunrise","orientation":"landscape","min_resolution":1080,"commercial_only":true}}}'
```

## GET /health

Health check (`health`)

Responses: `200` OK (object)

```bash
curl "https://image.shep.bot/health"
```

## GET /openapi.json

This OpenAPI document (`openapi`)

Responses: `200` OpenAPI 3.1 (object)

```bash
curl "https://image.shep.bot/openapi.json"
```

Schemas: Category, ImageStyle, Orientation, CommercialVerdict, NativeFilter, License, Price, ImageAsset, ImageFile, ImageDetails, ImageFilters, ProviderSearchReport, SearchResponse, Provider, FileSelection, SetRequest, ImageSlot, SetResponse, CountWithBound, SourceCensus, Catalog, UsageWindow, Ranked, ProviderHealth, Stats, Error. See https://image.shep.bot/openapi.json.

---
Source: https://image.shep.bot/docs/api/reference
