pictographic / developersTry the API

PICTOGRAPHIC / IMAGE API

A little color.
One simple URL.

Turn your colors into soft, textured gradients. Choose a seed, pick a size, and use the image wherever you need it.

No token for GETCSS color namesCached at the edge

Make it yours

LIVE PLAYGROUND

Keep the seed to repeat a result. Change it for a new composition.

Your colors, blended.
YOUR IMAGE URL
/api/image?colors=coral,rebeccapurple,royalblue&seed=2000&size=512x320&format=webp

01 / GET STARTED

Drop it into your HTML

GET returns the image directly. No API key, token, or JavaScript is needed for an image tag.

GET/api/image
HTML
<img
  src="https://gradient.pictographic.ai/api/image?colors=red,blue&amp;seed=2000&amp;size=512x320&amp;format=webp"
  width="512" height="320"
  alt="A red and blue gradient"
>

For CSS backgrounds, use the same URL inside background-image: url("…"). Use ordinary & separators in CSS and JavaScript; &amp; is for HTML attributes.

JAVASCRIPT · URL BUILDER
const query = new URLSearchParams({
  colors: ['coral', 'rgb(40, 100, 209)', '#EBC6FF'].join(','),
  seed: '2000',
  size: '512x320',
  format: 'webp',
});
const image = document.querySelector('img');
image.src = `https://gradient.pictographic.ai/api/image?${query}`;

02 / THE REQUEST

Four things to send

All four primary parameters are required. Order and repeated colors influence the gradient.

ParameterAccepted valueExample
colorsNonempty list of opaque CSS colors, separated by commasred,blue
seedInteger from 0 to 42949672952000
sizeWidth × height, each 1–2048 pixels512x320
formatpng or webpwebp
grain optionalNumber from 0 to 6; default 1.8. Use 0 for a smooth image.0
preview optionaltrue or false; default false. A preview fits within 384 pixels and always returns PNG.true

Successful responses have Content-Type: image/png or image/webp. The body contains image bytes, not JSON or base64.

03 / YOUR PALETTE

Speak in color

Names

coral

CSS names such as red, blue, and rebeccapurple. Case-insensitive.

Hex

#663399

Short or long hex, with or without #. Encode # as %23 in URLs.

Functions

rgb(40, 100, 209)

Opaque rgb() and hsl() work too. Commas inside functions stay together.

Mix formats in one palette. red, #f00, and rgb(255,0,0) resolve to the same color and cache entry. Use URLSearchParams to encode special characters.

Generate with hex colors

For orange #FF7308 and blue #2864D1, the simplest URL omits the # characters:

HEX · WITHOUT #
https://gradient.pictographic.ai/api/image?colors=FF7308,2864D1&seed=2000&size=512x320&format=webp

Open this image ↗

If you keep #, encode each one as %23. A literal # starts a URL fragment, so everything after it would not reach the API:

HEX · ENCODED #
https://gradient.pictographic.ai/api/image?colors=%23FF7308,%232864D1&seed=2000&size=512x320&format=webp

Open this image ↗

Generate with RGB colors

The same orange and blue are rgb(255,115,8) and rgb(40,100,209). Use the complete rgb(r,g,b) function for each color. Commas inside parentheses belong to that color; the comma between the functions separates colors.

RGB · ENCODED URL
https://gradient.pictographic.ai/api/image?colors=rgb%28255%2C115%2C8%29,rgb%2840%2C100%2C209%29&seed=2000&size=512x320&format=webp

Open this image ↗

All three URLs above generate the same image and share the same server-side cache entry. In JavaScript, let URLSearchParams handle the encoding:

JAVASCRIPT · HEX OR RGB
// Either list produces the same gradient:
const hexColors = ['#FF7308', '#2864D1'];
const rgbColors = ['rgb(255,115,8)', 'rgb(40,100,209)'];

const query = new URLSearchParams({
  colors: rgbColors.join(','), // Or hexColors.join(',')
  seed: '2000',
  size: '512x320',
  format: 'webp',
});
document.querySelector('img').src =
  `https://gradient.pictographic.ai/api/image?${query}`;

In the playground, enter one hex or RGB color per line. For POST JSON, send the original strings in the colors array, for example ["#FF7308", "rgb(40,100,209)"]; do not URL-encode JSON values.

Colors must be opaque. transparent, alpha below 1, currentColor, and CSS variables are not supported.

04 / REUSE THE RESULT

Render once. Reuse the URL.

Successful images are cached at the serving Cloudflare location for up to one year. Public GET images also have a one-year browser cache. The immutable directive lets browsers reuse a fresh image without revalidation. Equivalent GET and POST settings share an edge cache entry, including equivalent CSS color values.

Your URLCached imageYour page
  • The playground shows BROWSER CACHE when the image is reused locally without a network transfer. A browser-cached response can still contain an old X-Gradient-Cache: MISS header from its first download.
  • X-Gradient-Cache: HIT means the image was reused without rendering it again. MISS means it was generated.
  • Newly generated images include an ETag. A matching GET If-None-Match returns an empty 304 Not Modified when the image is cached.
  • Reuse the same seed and settings for repeat visitors. Random seeds create distinct images and cache entries.
  • Cache hits do not use the public render allowance. Caches are local to each Cloudflare location and may evict images before expiry; they are not permanent storage.
  • POST responses use Cache-Control: no-store for clients while still reusing the edge image cache.

This documentation is served as static assets; reading it does not invoke the Rust renderer. The playground makes image requests only when it loads or you select Generate image.

05 / SERVER INTEGRATION

Prefer a JSON request?

POST uses the same endpoint and returns the same image bytes. It requires a bearer token; keep it on your server. For public HTML embedding, use GET.

CURL · SERVER SIDE
curl 'https://gradient.pictographic.ai/api/image' \
  -H "Authorization: Bearer $GRADIENT_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"colors":["red","blue"],"seed":2000,"size":{"width":512,"height":320},"format":"webp"}' \
  --output gradient.webp

POST → get an image URL

Add Accept: application/json to generate the image and receive its public GET URL. Use the returned URL directly in an image tag or CSS background; it needs no token.

CURL · GENERATE A URL
curl 'https://gradient.pictographic.ai/api/image' \
  -H "Authorization: Bearer $GRADIENT_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  --data '{"colors":["#FF7308","#2864D1"],"seed":2000,"size":{"width":512,"height":320},"format":"webp"}'
JSON RESPONSE
{"url":"https://gradient.pictographic.ai/api/image?colors=ff7308%2C2864d1&seed=2000&size=512x320&format=webp&grain=1.8&preview=false"}
JAVASCRIPT · SERVER SIDE
const response = await fetch('https://gradient.pictographic.ai/api/image', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.GRADIENT_TOKEN}`,
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },
  body: JSON.stringify({
    colors: ['#FF7308', '#2864D1'],
    seed: 2000,
    size: { width: 512, height: 320 },
    format: 'webp',
  }),
});
if (!response.ok) throw new Error(await response.text());
const { url } = await response.json();
console.log(url); // Send this public URL to your frontend.

Without this Accept header, POST continues to return image bytes. URL responses support explicit color lists and URLs up to 8 KiB; legacy palette IDs and longer generated URLs return 400. The URL preserves colors, seed, dimensions, format, grain, and preview settings.

The former /api/gradients/render path remains supported and shares the same server-side image cache.

The optional grain and preview fields also work in JSON. The older {config, preview} format remains supported.

06 / GOOD TO KNOW

Limits & errors

Public uncached GET renders are limited to approximately 60 per minute per IP at each Cloudflare location. Shared IPs share the allowance. This is not a global spending cap.

GET queries can be up to 8 KiB; POST bodies up to 1 MiB. There is no fixed color-count cap, but a render work budget applies: field pixels × effective colors must not exceed 25 million. A 384 × 384 field permits up to 169 colors; large images and large palettes cost more to render. Colors are never silently removed.

StatusMeaningWhat to do
400Invalid, missing, duplicate, or unknown inputCheck colors and parameter ranges.
401Missing or invalid POST tokenSend a valid bearer header, or use public GET.
413 / 414Body / query is too largeShorten the list; use POST for long queries.
422Render work budget exceededReduce color count or image size.
429Too many uncached GET rendersRespect Retry-After: 60 and reuse URLs.
500 / 503Rendering failed / temporarily unavailableRetry later.

Errors return JSON, for example {"error":"Invalid color…"}. Unsupported methods return 405. Check availability at /api/gradients/health.