Skip to content
Image Asset Server

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> or x-api-key.
  • Rate limits: 120 requests per minute per client, announced in RateLimit-Policy / RateLimit headers; 429 comes with Retry-After. See versioning & rate limits.
  • Errors: JSON { "error": "message" } with a 4xx/5xx status.

Find images across every source in one call.

GET/v1/searchSearch every source

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.

Parameters

NameInTypeDescription
qquerystringShort query, written like a designer would.
categoryquerystringComma-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.
stylequerystringComma-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).
orientationquerystringComma-separated: landscape, portrait, square.
min_resolutionquerystringShort side at least: 720, 1080, 1440, 2160, or hd / fhd / large / 4k. Vectors always pass.
transparentquerybooleanOnly images with a transparent background.
formatquerystringComma-separated formats: jpg, png, svg, webp, tif.
commercialquerybooleanOnly images whose licence verdict is yes or yes-with-credit.
freequerybooleanOnly free images.
downloadablequerybooleanOnly images with direct file links.
strictquerybooleanDrop images whose orientation, size or transparency is unknown when that filter is set.
providersquerystringComma-separated source ids (see /v1/providers).
limitqueryintegerMax results (default 24).
offsetqueryintegerPer-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-Reset
  • 400Invalid parameters or unknown source id.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 401API key required (self-hosted servers only).Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.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.

GET/v1/images/{id}Image details, files and display URL

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

Parameters

NameInTypeDescription
id *pathstringImage 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-Reset
  • 400Malformed id or unknown source.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 404Unknown image.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
  • 501The source has no detail pages here; open url on the source site.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 502The source site failed.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

Example

curl "https://image.shep.bot/v1/images/nasa:PIA03606"
GET/v1/images/{id}/filesPick the right file

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

Parameters

NameInTypeDescription
id *pathstringImage id <provider>:<nativeId> (URL-encode it: ids can contain spaces, slashes and colons).
widthqueryintegerWanted 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.
formatquerystringPreferred format: jpg, png, svg, webp, tif.
rolequery"original" | "rendition" | "thumbnail"Only files with this role: original, rendition, thumbnail.
allquerybooleanEvery file, including thumbnails.

Responses

  • 200Selected files and total size.FileSelectionheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 404Unknown image.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

curl "https://image.shep.bot/v1/images/nasa:PIA03606/files"
GET/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

NameInTypeDescription
id *pathstringImage id <provider>:<nativeId> (URL-encode it: ids can contain spaces, slashes and colons).
widthqueryintegerWanted 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.
formatquerystringPreferred format: jpg, png, svg, webp, tif.
rolequery"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-Reset
  • 404Unknown image, or no file matches.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 409No direct download: get it from the source page.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

curl -L -O "https://image.shep.bot/v1/images/nasa:PIA03606/download"
GET/v1/images/{id}/creditsCredits for an image

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

Parameters

NameInTypeDescription
id *pathstringImage id <provider>:<nativeId> (URL-encode it: ids can contain spaces, slashes and colons).
formatquery"md" | "json" | "zip"

Responses

  • 200The credits.stringheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 404Unknown image.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.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.

POST/v1/setsPick images for a page, deck or post

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

  • 200The plan and its exports.SetResponseheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 400Invalid body.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.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.

GET/v1/providersList sources

Every 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-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

curl "https://image.shep.bot/v1/providers"
GET/v1/catalogCatalog census

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

  • 200Catalog census.Catalogheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 404The census has not been built on this server.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

curl "https://image.shep.bot/v1/catalog"
GET/v1/statsUsage statistics

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

  • 200Usage statistics.Statsheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

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

MCP

Model Context Protocol endpoint for AI agents.

POST/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-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.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.

GET/healthHealth check

Responses

  • 200OKobject

Example

curl "https://image.shep.bot/health"
GET/openapi.jsonThis OpenAPI document

Responses

  • 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 *stringSPDX id where one exists (CC0-1.0, CC-BY-4.0…), else LicenseRef-*.
name *string
urlstring (uri)
commercialUseboolean
attributionRequiredboolean
shareAlikeboolean
redistributionbooleanMay the image itself be re-uploaded or passed on?
editorialbooleanPeople, 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
notestring

Price

free *boolean
amountnumber
currencystring

ImageAsset

id *string<provider>:<nativeId>
provider *string
nativeId *string
title *string
descriptionstring
url *string (uri)The image's page on the source site.
authorstring
authorUrlstring (uri)
tags *string[]
category *Category
categoryEvidenceobject
stylesImageStyle[]
orientationOrientation
widthintegerPixel width of the largest version (vectors: their view box).
heightinteger
vectorbooleanScalable vector art (SVG): any size.
transparentbooleanHas a transparent background (icons, SVGs, PNG cut-outs).
yearintegerYear the work was made (art and archive images).
thumbnailUrlstring (uri)Small version (≈200–640 px) for grids, on the source.
previewUrlstring (uri)Display-size version (≈800–1600 px), on the source.
formatsstring[]
licenseLicense
attributionstringReady-to-paste credit line when the licence asks for one.
pricePrice
requiresAccountboolean
downloadable *boolean
createdAtstring (date-time)
popularitynumber
sameAsstring[]
scorenumber

ImageFile

url *string (uri)
filename *string
format *stringjpg, png, webp, svg, gif, tif…
mimestring
role *"original" | "rendition" | "thumbnail"original the full-quality file; rendition a resized copy; thumbnail a small copy for browsing.
widthinteger
heightinteger
sizeBytesinteger
requiresAuthboolean

ImageDetails

ImageAsset & object

ImageFilters

categoriesCategory[]
stylesImageStyle[]
orientationsOrientation[]
minResolutionintegerShort side in pixels. Vectors always pass.
transparentboolean
formatsstring[]
commercialOnlyboolean
freeOnlyboolean

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
totalinteger
searchUrlstring (uri)
errorstring
filteredLocallyNativeFilter[]
tookMs *integer

SearchResponse

query *stringThe 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"
licenseLicense
apiKeyEnvstringEnvironment variable holding the source's API key on a self-hosted server.
supportsDownload *boolean
nativeFiltersNativeFilter[]Filters the source applies itself; the rest are applied locally.
enabledboolean

FileSelection

id *string
licenseLicense
attributionstring
totalBytesinteger
files *ImageFile[]

SetRequest

slots *object
widthintegerDefault width in pixels for slots without their own.
orientationOrientation
stylesImageStyle[]Default kind for slots that don't say, e.g. ["photo"].
commercialOnlyboolean
providersstring[]
alternativesinteger
namestring

ImageSlot

index *integer
description *string
width *integerThe slot's target width in pixels.
imageImageAsset
fileImageFile
altstringSuggested alt text.
alternatives *ImageAsset[]
notestringWhy nothing (or something imperfect) was picked: upscaling, cropping, editorial use.

SetResponse

plan *object
exports *objectFile 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
atLeastbooleanThe count is a lower bound.

SourceCensus

id *string
name *string
homepage *string (uri)
licensestringThe source's single licence id, when uniform.
pricing"free" | "freemium" | "paid"
supportsDownloadboolean
total *integerListings on the source (free and paid).
atLeastboolean
freeinteger
byCategory *objectListings per top-level category; each listing counts once.
byLicenseobject
categoriesobjectThe source's own categories or tags (may overlap).
addedLast30Daysinteger
downloadsintegerTotal downloads, when the source publishes them.
highlightsobject[]
method *stringHow the source was counted.
countedAt *string (date-time)
staleobject

Catalog

countedAt *string (date-time)
totals *object
byCategory *objectListings per top-level category across sources.
byLicense *object
sources *SourceCensus[]
linkedobject[]

UsageWindow

key *string24h, 7d, or process (since the last restart).
label *string
searches *integer
searchesWithResults *integer
bySurface *object
imageViews *integer
downloads *integer
toolCalls *integerMCP tool calls.
pageViews *integerWebsite pages served.

Ranked

name *string
count *integer

ProviderHealth

provider *string
requests *integerSearches 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"
sincestring (date-time)Start of counting for source: process.
windows *UsageWindow[]
breakdownLabel *stringPeriod 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
urlstring (uri)The image's page on the source, when the file must be fetched there.
requiresAccountboolean
retryAfterinteger

AI agent? This page is also available as markdown.