Référence API

Quick Start

CloudPhoto resizes, transforms, compresses & optimizes your images on-demand from a single URL. The v2 API uses query parameters for maximum flexibility — works from any language, no SDK required.
https://cdn.cloudphoto.io/<token>/img?<params>&sig=<signature>&url=<source_image_url>
Golden rule — url is always the LAST parameter. Everything after url= is the source image URL, including its own query string (e.g. Centris media.ashx?id=...&t=pi). All CloudPhoto parameters come before url=. The source URL is taken raw — no encoding needed.
Parameter names. Each parameter has a long, canonical form (used throughout this doc) and a short alias — both are accepted: width/w, height/h, format/f, quality/q, aspect_ratio/ar, gravity/g, filters/fx, metadata/md.
Signing is required. Every v2 request must carry a valid sig — an HMAC keyed by your token's secret. The examples below include a real one so you can see exactly where it goes; full recipe under Signing your URLs. (The demo token is technically exempt, but the examples sign anyway.)
Example — resize to 600px wide, served in the best format the browser accepts (the sig is computed from the token's secret):
https://cdn.cloudphoto.io/demo/img?width=600&amp;sig=hoxDw18eiRCB_oyTPvVTSg&amp;url=https://samples-photos.com/tennis.jpg
The default is auto: each browser gets the best format it accepts — AVIF if supported, then WebP, falling back to the source format. Pass an explicit &format=webp (or jpg/png) for a single fixed format across all clients, or &format=original to keep the source format.
Production URLs go through the CDN cdn.cloudphoto.io (cached, fast). The examples below hit the origin app.cloudphoto.io directly — both expose the same API.

Parameters

Parameter (alias) Description
token Your CloudPhoto customer token (first path segment).
width (w) Target width in pixels. Alone, keeps the aspect ratio.
height (h) Target height in pixels. Alone, keeps the aspect ratio.
fit Resize operation (see Operations). Omitted → derived from the dimensions.
aspect_ratio (ar) Target aspect ratio (16:9 or 1.5). With a single dimension, derives the other and crops to the ratio.
dpr Device pixel ratio (1–5) for retina. Multiplies the requested dimensions.
format (f) Output format: auto (default, negotiated via Accept), or force webp/avif/jpg/png/original.
quality (q) Quality 1–100, or auto. Defaults tuned per format.
gravity (g) Focus region for crop (see Filters → gravity), including entropy (content-aware smart crop, no AI).
filters (fx) Dot-separated chain of filters (see Filters), e.g. brightness120.saturation140.blur3.
org_if_sml 1 = never upscale: if the source is smaller than the target, serve it at its own size.
metadata (md) 1 = keep image metadata (EXIF/IPTC). Stripped by default for lighter files.
ci_info 1 = return transformation metadata as JSON (format, dimensions, weight, cache, timings) instead of the image.
force 1 = bypass cache and regenerate.
sig HMAC signature of the request — required on every token except demo (see Signing your URLs). Goes right before url=.
url The source image URL. Always last, taken raw.

Signing your URLs

Every v2 request must be signed — except the public demo token used in the examples above. An unsigned or tampered request on your token returns a placeholder image with a 403. This stops anyone who sees one of your URLs from reusing your token to generate unlimited new variants (each new variant costs a download, image processing, storage and bandwidth).
Each token has a secret (in your CloudPhoto dashboard). You compute an HMAC-SHA256 over the request, keyed by that secret, keep the first 16 bytes and base64url-encode them (no padding) → a 22-character sig, placed right before url=.
The signed message is all your parameters except sig, then url=<source> — the exact bytes you put in the URL (no re-encoding):
message = "width=600&filters=sharpen10" + "&" + "url=https://example.com/photo.jpg"
sig     = base64url( HMAC_SHA256(secret, message)[0..15] )
Ruby:
require "openssl"
require "base64"

secret  = "<your token secret>"          # from the dashboard — keep it server-side
before  = "width=600&filters=sharpen10"  # your parameters, WITHOUT sig
source  = "https://example.com/photo.jpg"
message = [before.presence, "url=#{source}"].compact.join("&")
sig     = Base64.urlsafe_encode64(OpenSSL::HMAC.digest("SHA256", secret, message)[0, 16], :padding => false)

url = "https://cdn.cloudphoto.io/<token>/img?#{before}&sig=#{sig}&url=#{source}"
Sign on your backend, never in browser JavaScript. HMAC is symmetric — anyone with the secret can sign (and forge). Build signed URLs server-side, or expose a small signing endpoint; never ship the secret in a JS bundle.
No expiry, cache-friendly. Signed URLs don't expire — they cache for a month like any other. To revoke access, rotate the token's secret.
format=auto. Sign your URL exactly as written (or omit formatauto is the default). Format negotiation happens server-side and the image is served directly on the same URL — no redirect, your signature is never touched.

Operations

The fit parameter selects the resize behavior. When omitted: width+heightcrop, a single dimension → width/height.
Operation Description
none No resize — only re-encode / apply filters.
width Resize to a width, height proportional.
height Resize to a height, width proportional.
crop Fill the exact widthxheight box and crop the overflow (use gravity to choose the region).
cover Force the exact widthxheight, ignoring the ratio (may distort).
fit Fit entirely inside widthxheight (letterbox), padded with the color filter (transparent for PNG).
bound Fit inside widthxheight keeping the ratio, without padding (output may be smaller).

Filters

Filters go in the filters parameter (alias fx), separated by dots: filters=contrast20.colorFF0000.colorize30. The value is appended to the name without a separator, so values never contain a dotgamma120 means gamma 1.2, opacity50 means 50%. Gravity has its own gravity parameter.
Geometry
Filter Description
rot<deg> Rotate by <deg> degrees. The empty area uses the color filter.
flip Mirror vertically.
flop Mirror horizontally.
trim<fuzz> Remove uniform borders (<fuzz>% tolerance, default 5).
border<n> Add an <n>px border in the color filter color.
Color
Filter Description
color<HEX> Color used by fit padding, colorize, border and rot (e.g. colorFF0000, colortransparent).
colorize<0-100> Overlay the color tint at the given opacity.
colorspace<X> Output colorspace: sRGB, RGB, Gray.
grayscale Convert to grayscale.
sepia<n> Sepia tone (default 80%).
negate Invert the colors (negative).
gamma<n> Gamma correction, <n>÷100 (gamma120 = 1.2).
brightness<n> Brightness, 100 = neutral (0–200).
saturation<n> Saturation, 100 = neutral.
hue<n> Hue rotation, 100 = neutral.
contrast<0-100> Increase contrast.
threshold<n> Black & white at the <n>% threshold.
autocontrast Auto-stretch the tonal range.
opacity<0-100> Global opacity (needs an alpha-capable output: PNG/WebP).
Effects
Filter Description
blur<n> Gaussian blur.
sharpen<n> Sharpen (unsharp mask).
pixelate<n> Pixelate in blocks.
oilpaint<n> Oil-paint effect (<n> radius).
vignette<n> Dark vignette (<n> spread).
Gravity (gravity parameter, alias g) — used by crop: Center, North, NorthEast, East, SouthEast, South, SouthWest, West, NorthWest, and entropy (content-aware smart crop, no AI — picks the most detailed region).

Responsive images

Use dpr for retina, and a plain HTML srcset with several widths — just vary the width parameter (no SDK, any framework):
<img
  src="https://cdn.cloudphoto.io/demo/img?width=800&format=auto&url=https://example.com/photo.jpg"
  srcset="https://cdn.cloudphoto.io/demo/img?width=400&format=auto&url=https://example.com/photo.jpg   400w,
          https://cdn.cloudphoto.io/demo/img?width=800&format=auto&url=https://example.com/photo.jpg   800w,
          https://cdn.cloudphoto.io/demo/img?width=1200&format=auto&url=https://example.com/photo.jpg 1200w"
  sizes="(max-width: 600px) 100vw, 800px"
  alt="Property photo">
format=auto lets the browser get AVIF/WebP automatically; each width is a separate cached variant.

Examples

Original image
1280×960
(350 ko)

width=600 — resize, best format auto-negotiated
600×450
(63,2 ko)
-82%