Media search

Search a stock library of photos and videos, browse curated photos and popular videos, or fetch a single item by id. Every call is a GET and goes through the same authentication, rate-limit and quota pipeline as every other service.

Method & pathReturns
GET /api/v1/media/photos/searchPhotos matching query
GET /api/v1/media/photos/curatedA curated selection of photos
GET /api/v1/media/photos/{id}One photo
GET /api/v1/media/videos/searchVideos matching query
GET /api/v1/media/videos/popularPopular videos
GET /api/v1/media/videos/{id}One video

Parameters

Query-string parameters for the four list routes. Anything outside these rules returns 400 bad_request.

ParameterDefaultNotes
query—Required on the two search routes. Up to 200 characters.
per_page15Items per page, 1–50.
page11–1000.
orientation—landscape, portrait or square.
size—large, medium or small.
color—A colour name (blue) or a hex value.
locale—The language of query, e.g. en-US.

The single-item routes take only the numeric id in the path.

Response

The list routes return one envelope:

KeyType
page, per_pagenumber — the page you were served
total_resultsnumber — matches across all pages
has_moreboolean — whether asking for page + 1 returns more
photos or videosarray of items

Each item comes back whole. The fields you will use most:

ItemFields
Photoid, width, height, photographer, avg_color, alt, src (the image in several sizes: original, large, medium, small, tiny and more), license
Videoid, width, height, duration (seconds), user (id, name), image (a still), video_files (one entry per rendition: link, quality, width, height, file_type), video_pictures, license

license is a license and attribution string to display alongside the asset. The single-item routes return the item itself, in the same shape.

{
  "page": 1,
  "per_page": 3,
  "total_results": 8000,
  "has_more": true,
  "photos": [
    {
      "id": 3408744,
      "width": 6000,
      "height": 4000,
      "photographer": "Ana Ribeiro",
      "avg_color": "#5B7A8C",
      "alt": "Mountain lake at dawn with mist over the water",
      "src": {
        "original": "https://khabot.com/api/v1/media/files/aHR0cHM6Ly…Q.f3K9vR…",
        "medium": "https://khabot.com/api/v1/media/files/aHR0cHM6Ly…w.9qLm2x…",
        "tiny": "https://khabot.com/api/v1/media/files/aHR0cHM6Ly…A.Tz7cWp…"
      },
      "license": "<Library> — Photo by Ana Ribeiro · Free to use under the <Library> License"
    }
  ]
}

Trimmed for brevity — a real page holds per_page items, and each item has more fields and image sizes than shown.

When you show a photo or video, display its license text alongside it.

Using the asset URLs

Every asset URL in a result — src.* on a photo; image, video_files[].link and video_pictures[].picture on a video — is a khabot.com URL you can put straight into an <img> or <video> tag:

  • Public — no API key needed to fetch it, so it works in a browser.
  • Permanent — the file behind a URL never changes, so it can be cached indefinitely.
  • Seekable — range requests are supported, so videos can be scrubbed.
  • Not billed — only the search or lookup that returned the URL costs a unit.

The URLs are signed: use them exactly as returned. An altered URL is refused with 403 forbidden, and an unusually heavy burst of asset requests from one client may get 429 rate_limited with a retry-after header.

Billing

Each request bills one unit at the media-search price — a search, a list page or a single item alike, whatever per_page you ask for. Only successful requests bill: an invalid request or an unknown id costs nothing, and fetching the asset URLs is never billed.

Examples

# search photos
curl "https://khabot.com/api/v1/media/photos/search?query=mountain+lake&per_page=3&orientation=landscape" \
  -H "Authorization: Bearer kb_YOUR_KEY"

# popular videos, second page
curl "https://khabot.com/api/v1/media/videos/popular?page=2" \
  -H "Authorization: Bearer kb_YOUR_KEY"

# one photo by id
curl https://khabot.com/api/v1/media/photos/3408744 \
  -H "Authorization: Bearer kb_YOUR_KEY"

Errors

HTTPcodeWhen
400bad_requestquery missing on a search, page or per_page out of range, an invalid filter value, or a non-numeric id. The message says which. Not billed.
404not_foundNo photo or video has that id. Not billed.
503upstream_unavailableThe library could not be reached. Not billed; safe to retry.
503service_not_configuredMedia search is not switched on. Not billed.

Plan, quota and rate-limit walls are the same as every other service — see Errors.