ImagesWP
API reference · v1

ImagesWP REST API

One JSON API for search and metadata, one CDN host for delivery. Both take the same image ids, and delivery URLs accept transform parameters directly — there is no separate rendering endpoint to call.

Overview

The API is REST over HTTPS. Requests take query parameters, responses are JSON encoded as UTF‑8, and every endpoint is versioned in the path. TLS 1.2 or newer is required; plain HTTP is redirected once and then refused.

HostPurposeAuth
api.imageswp.comSearch, metadata, uploads, accountBearer key
cdn.imageswp.comImage delivery and transformsPublic or signed
  • Base URL for the JSON API: https://api.imageswp.com/v1
  • Base URL for delivery: https://cdn.imageswp.com/v1
  • Image ids are opaque, URL-safe and stable: img_7f3a
  • All timestamps are RFC 3339 in UTC: 2026-03-14T09:22:41Z

Authentication

Send your API key as a bearer token on every request to api.imageswp.com. Keys are 40 characters, prefixed by environment, and are shown once when issued.

HEADER
Authorization: Bearer iwp_live_9c4f2ab7e01d4a63b8f5726d3ec8a1f0
  • iwp_live_… keys read the collection, your uploads and your usage.
  • iwp_test_… keys behave identically but are metered separately and never billed.
  • A missing or malformed header returns 401 unauthorized. A valid key without the right scope returns 403 forbidden.
Keep keys server side. A live key in browser JavaScript is a live key in someone else’s crawler. Delivery URLs need no key at all, so a browser never has a reason to hold one. If you need per-user restrictions on delivery, use signed URLs instead.

Quickstart

Search for something, take the urls.raw value off the first result, and append the transform you want. That is the whole integration.

SHELL
# 1. find an image
curl -s "https://api.imageswp.com/v1/images/search?q=coastline&per_page=1" \
  -H "Authorization: Bearer $IMAGESWP_KEY" | jq '.results[0].urls.raw'

# -> "https://cdn.imageswp.com/v1/img_2c91"

# 2. serve it at the size you need
<img src="https://cdn.imageswp.com/v1/img_2c91?w=800&fit=cover&format=auto"
     width="800" height="533" alt="Volcanic ridge under haze">

Retrieve an image

Returns the full metadata record for one image, including EXIF where the photographer released it and a blurhash you can render while the real file is in flight.

GET https://api.imageswp.com/v1/images/{id}
SHELL
curl -s "https://api.imageswp.com/v1/images/img_7f3a" \
  -H "Authorization: Bearer $IMAGESWP_KEY"
JSON
{
  "id": "img_7f3a",
  "title": "Suspension bridge at sunset",
  "width": 4800,
  "height": 3200,
  "bytes": 7418240,
  "blurhash": "L9C%b0IU00~qofj[ayfQ4nWB",
  "dominant_color": "#c8794b",
  "tags": ["architecture", "travel"],
  "exif": {
    "camera":   "Canon EOS R6",
    "aperture": "f/8",
    "shutter":  "1/500",
    "iso":      200
  },
  "license": "ImagesWP Open License 1.0",
  "urls": { "raw": "https://cdn.imageswp.com/v1/img_7f3a" },
  "created_at": "2026-03-14T09:22:41Z"
}

Delivery URLs

Delivery needs no API key and no round trip through the JSON API. Take an id, put it on the CDN host, and append whatever transform you need.

GET https://cdn.imageswp.com/v1/{id}[.format]?params

The extension is optional and equivalent to format=. These three URLs are the same request:

URL
https://cdn.imageswp.com/v1/img_7f3a.avif?w=1440
https://cdn.imageswp.com/v1/img_7f3a?w=1440&format=avif
https://cdn.imageswp.com/v1/img_7f3a?width=1440&fm=avif   # short aliases

Response headers

HeaderValue
Cache-Controlpublic, max-age=31536000, immutable
Content-TypeNegotiated format, e.g. image/avif
VaryAccept when format=auto is used
X-IWP-CacheHIT, MISS or REVALIDATED
X-IWP-EdgeEdge location that served the byte stream, e.g. iad1
Timing-Allow-Origin*, so your RUM can read the real timings
Purging. Transformed frames are immutable because the parameters are part of the cache key: change a parameter and you get a different object, never a stale one. Replacing the underlying image is the only case that needs a purge, and POST /v1/images/{id}/purge clears every derived frame in under 30 seconds.

Transform parameters

Parameters compose in any order. Unrecognised parameters are ignored rather than rejected, so a typo degrades to the original image instead of a broken layout.

ParameterTypeDescription
w1–5000Output width in pixels. Aliased as width.
h1–5000Output height in pixels. Aliased as height.
fitenumcover (default, crops to fill), contain (letterboxes), fill (stretches), inside (never enlarges).
cropenumAnchor for fit=cover: center (default), top, bottom, left, right, faces, entropy.
formatenumauto (default), avif, webp, jpeg, png. Aliased as fm.
q1–100Quality. Defaults to 78 for lossy formats. Ignored for png.
dpr1–3Multiplies w and h. ?w=400&dpr=2 renders 800px wide.
blur0–100Gaussian radius. Useful for placeholders and background plates.
bghexFill colour behind fit=contain or a transparent PNG, e.g. bg=0d0f13.
stripbooleanDefaults to true. Set strip=false to keep EXIF and ICC data.

Responsive markup

Because a transform is just a URL, srcset needs no build step and no image component:

HTML
<img
  src="https://cdn.imageswp.com/v1/img_7f3a?w=960&format=auto"
  srcset="https://cdn.imageswp.com/v1/img_7f3a?w=480&format=auto   480w,
          https://cdn.imageswp.com/v1/img_7f3a?w=960&format=auto   960w,
          https://cdn.imageswp.com/v1/img_7f3a?w=1440&format=auto 1440w"
  sizes="(max-width: 720px) 100vw, 720px"
  width="960" height="600" loading="lazy" decoding="async"
  alt="Suspension bridge at sunset">

Rate limits

Limits apply to api.imageswp.com only. Delivery from cdn.imageswp.com is not rate limited — it is metered against your plan allowance and never throttled mid-month.

PlanBurstSustained
Free30 requests / 10 s5,000 / month
Pro120 requests / 10 s250,000 / month
Scale600 requests / 10 s2,000,000 / month

Every response carries the current window, so a client never has to guess:

HTTP
HTTP/2 200
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1773413041

# and when you go over
HTTP/2 429
Retry-After: 4
Retry 429 and 5xx with exponential backoff and full jitter, starting at the Retry-After value. Do not retry 4xx other than 429 — the request will fail the same way every time.

Errors

Errors use conventional status codes and always return the same envelope. The request_id is what support will ask for.

JSON
{
  "error": {
    "code": "invalid_parameter",
    "message": "per_page must be between 1 and 80.",
    "param": "per_page",
    "docs": "https://www.imageswp.com/docs/#search",
    "request_id": "req_01JQ8Z3M6K2VXH"
  }
}
StatusCodeMeaning
400invalid_parameterA parameter is missing, malformed or out of range.
401unauthorizedNo key, malformed header, or the key has been revoked.
403forbiddenValid key, wrong scope, or a signed URL failed verification.
404not_foundNo image with that id, or it is not visible to this key.
409already_existsUpload conflicts with an existing checksum.
413payload_too_largeUpload exceeds 64 MB.
415unsupported_mediaSource file is not JPEG, PNG, WebP, AVIF, HEIC or TIFF.
422transform_failedParameters are individually valid but cannot be satisfied together.
429rate_limitedBurst window exhausted. See Retry-After.
503temporarily_unavailableTransform capacity is saturated. Safe to retry.

Versioning

The version lives in the path. Within v1 we add fields, endpoints and parameters, but we do not remove or repurpose them. A field you read today will still be there, with the same meaning, for the life of the version.

  • Breaking changes ship as v2, and v1 stays available for at least 24 months afterwards.
  • Deprecations arrive as a Sunset header on affected responses, at least 180 days ahead.
  • Treat unknown JSON fields as additive and ignore them — new ones appear without notice.

Recent changes

DateChange
2026‑06‑18Added crop=faces and crop=entropy anchors.
2026‑04‑02format=auto now prefers AVIF wherever the Accept header allows it.
2026‑02‑11Search gained source, so uploads and the collection can be queried separately.
2025‑11‑30v1 declared stable.
Start building

Your first 5,000 requests are free.

Keys are issued the same day. No card, no sales call, no minimum term — you get a key, a rate limit and the docs, and you ship.