Image Asset Server API reference
One search API for free images: photos, museum art, illustrations, maps, SVG vectors and icons, with licence verdicts. Version 0.1.0, base URL https://image.shep.bot. Machine-readable:OpenAPI 3.1 JSON. Want to send requests from the browser? Open theinteractive API playground.
- Authentication: none on the public server. Self-hosted servers may require
Authorization: Bearer <key>orx-api-key. - Rate limits: 120 requests per minute per client, announced in
RateLimit-Policy/RateLimitheaders;429comes withRetry-After. See versioning & rate limits. - Errors: JSON
{ "error": "message" }with a 4xx/5xx status.
Search
Find images across every source in one call.
/v1/searchSearch every sourceFans 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.
Parameters
| Name | 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
200Ranked results, the filters in force and a per-source report.SearchResponseheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset400Invalid parameters or unknown source id.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset401API key required (self-hosted servers only).Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
Example
curl "https://image.shep.bot/v1/search?category=nature.ocean&style=painting&orientation=portrait&min_resolution=1080&format=svg&providers=nasa%2Cwikimediacommons"Images
Details, sizes, downloads and credits for one image.
/v1/images/{id}Image details, files and display URLFull metadata, the licence with its verdict and credit line, every file (original, resized copies, thumbnail) and the file a browser should show.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| id * | path | string | Image id <provider>:<nativeId> (URL-encode it: ids can contain spaces, slashes and colons). |
Responses
200The image and its files.ImageDetailsheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset400Malformed id or unknown source.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset404Unknown image.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy501The source has no detail pages here; openurlon the source site.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset502The source site failed.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
Example
curl "https://image.shep.bot/v1/images/nasa:PIA03606"/v1/images/{id}/filesPick the right fileThe best file for a width and format (the original by default), or every file with all=true, with sizes and the licence.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| id * | 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
200Selected files and total size.FileSelectionheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset404Unknown image.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
Example
curl "https://image.shep.bot/v1/images/nasa:PIA03606/files"/v1/images/{id}/downloadDownload (redirect to the source)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.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| id * | 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
302Redirect to the file.headers: Location, X-License, X-Attribution, RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset404Unknown image, or no file matches.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset409No direct download: get it from the source page.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
Example
curl -L -O "https://image.shep.bot/v1/images/nasa:PIA03606/download"/v1/images/{id}/creditsCredits for an imageATTRIBUTION.md (default), credits.json, or a zip holding both. No image inside.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| id * | path | string | Image id <provider>:<nativeId> (URL-encode it: ids can contain spaces, slashes and colons). |
| format | query | "md" | "json" | "zip" |
Responses
200The credits.stringheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset404Unknown image.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
Example
curl "https://image.shep.bot/v1/images/nasa:PIA03606/credits"Sets
Pick one image per slot for a page, deck or post in one call.
/v1/setsPick images for a page, deck or postOne 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
200The plan and its exports.SetResponseheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset400Invalid body.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
Example
curl -X POST "https://image.shep.bot/v1/sets" \
-H "content-type: application/json" -H "accept: application/json, text/event-stream" \
-d '{}'Sources
The image sites this server searches, what they hold, and how the server is used.
/v1/providersList sourcesEvery image site with the categories it carries, pricing, licence, the filters it applies itself and whether files can be downloaded directly.
Responses
200Sources.objectheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
Example
curl "https://image.shep.bot/v1/providers"/v1/catalogCatalog censusHow 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
200Catalog census.Catalogheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset404The census has not been built on this server.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
Example
curl "https://image.shep.bot/v1/catalog"/v1/statsUsage statisticsAggregate 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
200Usage statistics.Statsheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
Example
curl "https://image.shep.bot/v1/stats"MCP
Model Context Protocol endpoint for AI agents.
/mcpMCP endpoint (Streamable HTTP)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
200JSON-RPC 2.0 response.objectheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset429Rate limit exceeded. WaitRetry-Afterseconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
Example
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}}}'System
Health and machine-readable descriptions.
/healthHealth checkResponses
200OKobject
Example
curl "https://image.shep.bot/health"/openapi.jsonThis OpenAPI documentResponses
200OpenAPI 3.1object
Example
curl "https://image.shep.bot/openapi.json"Schemas
Category
One of: nature, nature.ocean, nature.water, nature.sky, nature.forest, nature.plants, nature.mountain, animals, city, city.skyline, architecture, people, people.work, people.lifestyle, people.sport, food, objects, tech, transport, space, space.earth, space.missions, space.planets, science, art, art.painting, art.drawing, art.sculpture, archive, archive.map, archive.poster, background, icons, other
ImageStyle
One of: photo, illustration, painting, drawing, vector, icon, transparent, black-white
Orientation
One of: landscape, portrait, square
CommercialVerdict
One of: yes, yes-with-credit, restricted, clearance-required, check-terms, no
NativeFilter
One of: categories, styles, orientation, resolution, transparent, formats, commercialOnly, freeOnly
License
| id * | string | SPDX id where one exists (CC0-1.0, CC-BY-4.0…), else LicenseRef-*. |
| name * | string | |
| url | string (uri) | |
| commercialUse | boolean | |
| attributionRequired | boolean | |
| shareAlike | boolean | |
| redistribution | boolean | May the image itself be re-uploaded or passed on? |
| editorial | boolean | People, insignia or brands without releases: fine for articles and education, not for ads. |
| assertedBy * | "source" | "site" | "uploader" | uploader = an unverified claim (verdict capped at check-terms). |
| verdict * | CommercialVerdict | |
| note | string |
Price
| free * | boolean | |
| amount | number | |
| currency | string |
ImageAsset
| id * | string | <provider>:<nativeId> |
| provider * | string | |
| nativeId * | string | |
| title * | string | |
| description | string | |
| url * | string (uri) | The image's page on the source site. |
| author | string | |
| authorUrl | string (uri) | |
| tags * | string[] | |
| category * | Category | |
| categoryEvidence | object | |
| styles | ImageStyle[] | |
| orientation | Orientation | |
| width | integer | Pixel width of the largest version (vectors: their view box). |
| height | integer | |
| vector | boolean | Scalable vector art (SVG): any size. |
| transparent | boolean | Has a transparent background (icons, SVGs, PNG cut-outs). |
| year | integer | Year the work was made (art and archive images). |
| thumbnailUrl | string (uri) | Small version (≈200–640 px) for grids, on the source. |
| previewUrl | string (uri) | Display-size version (≈800–1600 px), on the source. |
| formats | string[] | |
| license | License | |
| attribution | string | Ready-to-paste credit line when the licence asks for one. |
| price | Price | |
| requiresAccount | boolean | |
| downloadable * | boolean | |
| createdAt | string (date-time) | |
| popularity | number | |
| sameAs | string[] | |
| score | number |
ImageFile
| url * | string (uri) | |
| filename * | string | |
| format * | string | jpg, png, webp, svg, gif, tif… |
| mime | string | |
| role * | "original" | "rendition" | "thumbnail" | original the full-quality file; rendition a resized copy; thumbnail a small copy for browsing. |
| width | integer | |
| height | integer | |
| sizeBytes | integer | |
| requiresAuth | boolean |
ImageDetails
ImageAsset & object
ImageFilters
| categories | Category[] | |
| styles | ImageStyle[] | |
| orientations | Orientation[] | |
| minResolution | integer | Short side in pixels. Vectors always pass. |
| transparent | boolean | |
| formats | string[] | |
| commercialOnly | boolean | |
| freeOnly | boolean |
ProviderSearchReport
| provider * | string | |
| name * | string | |
| status * | "ok" | "error" | "timeout" | "skipped" | "link" | link = the source can only be searched on its own site: open searchUrl. |
| count * | integer | |
| total | integer | |
| searchUrl | string (uri) | |
| error | string | |
| filteredLocally | NativeFilter[] | |
| tookMs * | integer |
SearchResponse
| query * | string | The words searched after the filters were parsed out. |
| filters * | ImageFilters | |
| results * | ImageAsset[] | |
| providers * | ProviderSearchReport[] |
Provider
| id * | string | |
| name * | string | |
| homepage * | string (uri) | |
| description * | string | |
| categories * | Category[] | Top-level categories the source carries. |
| access * | "api" | "static" | "scrape" | "link" | api official API; static a curated manifest filtered locally; scrape public pages; link deep links only (paid/partner API, no key yet, or terms that forbid aggregation). |
| pricing * | "free" | "freemium" | "paid" | |
| license | License | |
| apiKeyEnv | string | Environment variable holding the source's API key on a self-hosted server. |
| supportsDownload * | boolean | |
| nativeFilters | NativeFilter[] | Filters the source applies itself; the rest are applied locally. |
| enabled | boolean |
FileSelection
| id * | string | |
| license | License | |
| attribution | string | |
| totalBytes | integer | |
| files * | ImageFile[] |
SetRequest
| slots * | object | |
| width | integer | Default width in pixels for slots without their own. |
| orientation | Orientation | |
| styles | ImageStyle[] | Default kind for slots that don't say, e.g. ["photo"]. |
| commercialOnly | boolean | |
| providers | string[] | |
| alternatives | integer | |
| name | string |
ImageSlot
| index * | integer | |
| description * | string | |
| width * | integer | The slot's target width in pixels. |
| image | ImageAsset | |
| file | ImageFile | |
| alt | string | Suggested alt text. |
| alternatives * | ImageAsset[] | |
| note | string | Why nothing (or something imperfect) was picked: upscaling, cropping, editorial use. |
SetResponse
| plan * | object | |
| exports * | object | File contents, ready to save: the picks as JSON, <figure> snippets with credit captions, a curl script and the credits. File URLs point at the sources. |
CountWithBound
| count * | integer | |
| atLeast | boolean | The count is a lower bound. |
SourceCensus
| id * | string | |
| name * | string | |
| homepage * | string (uri) | |
| license | string | The source's single licence id, when uniform. |
| pricing | "free" | "freemium" | "paid" | |
| supportsDownload | boolean | |
| total * | integer | Listings on the source (free and paid). |
| atLeast | boolean | |
| free | integer | |
| byCategory * | object | Listings per top-level category; each listing counts once. |
| byLicense | object | |
| categories | object | The source's own categories or tags (may overlap). |
| addedLast30Days | integer | |
| downloads | integer | Total downloads, when the source publishes them. |
| highlights | object[] | |
| method * | string | How the source was counted. |
| countedAt * | string (date-time) | |
| stale | object |
Catalog
| countedAt * | string (date-time) | |
| totals * | object | |
| byCategory * | object | Listings per top-level category across sources. |
| byLicense * | object | |
| sources * | SourceCensus[] | |
| linked | object[] |
UsageWindow
| key * | string | 24h, 7d, or process (since the last restart). |
| label * | string | |
| searches * | integer | |
| searchesWithResults * | integer | |
| bySurface * | object | |
| imageViews * | integer | |
| downloads * | integer | |
| toolCalls * | integer | MCP tool calls. |
| pageViews * | integer | Website pages served. |
Ranked
| name * | string | |
| count * | integer |
ProviderHealth
| provider * | string | |
| requests * | integer | Searches that reached the source. |
| ok * | integer | |
| errors * | integer | |
| timeouts * | integer | |
| okRate * | number | null | |
| p50Ms * | integer | null | |
| p95Ms * | integer | null |
Stats
| generatedAt * | string (date-time) | |
| source * | "prometheus" | "process" | |
| since | string (date-time) | Start of counting for source: process. |
| windows * | UsageWindow[] | |
| breakdownLabel * | string | Period covered by clients, tools and assetTypes. |
| clients * | Ranked[] | Searches by client family (claude-code, cursor, browser, curl…). |
| tools * | Ranked[] | MCP tool calls by tool. |
| assetTypes * | Ranked[] | Searches by category filter (any = no filter). |
| providers * | ProviderHealth[] | Per-source health over the last 24 hours. |
| catalog * | object |
Error
| error * | string | |
| url | string (uri) | The image's page on the source, when the file must be fetched there. |
| requiresAccount | boolean | |
| retryAfter | integer |
AI agent? This page is also available as markdown.