Open license · Grows with use · OpenAI-compatible

Free, open images.
Shaped by everyone.

A free, openly licensed image library shaped by what people search for. Every prompt returns the closest match in milliseconds; the ones the library can't answer yet are generated in the background and added for everyone. It only grows because people use it — no searches, no new images. The more we all search, the better it gets for all of us.

Zero egress fees ~100 ms cache hits Drop-in OpenAI API
A red arm and a black arm locked in an arm-wrestling handshake
Cloudflare
GMI Cloud
Backblaze
What you get back

Closest match, not always exact.

wagmi.photos searches the shared library before anything else. Everyday prompts almost always land a strong match. Hyper-specific prompts return the closest image that already exists — close, but maybe not every detail.

1Generic prompt
"a dog and a cat"
"result": "hit" · strong match · 0.1 s
A golden retriever and a grey cat sitting side by side — the library's match High match
2Very specific prompt
"a flamingo in a top hat doing my taxes"
"result": "hit" · flamingo ✓ · top hat ✗ · taxes ✗
A flamingo on a tropical beach — no top hat, taxes not filed Closest match · may differ
A smiling man at his laptop giving a thumbs up, happy with the closest match
Closest match from library
A cheerful cartoon avatar reacting with a big “Nice!”
wagmi.photos

Faster. Cheaper. Better.

Built for speed and efficiency, so you create more for less — and every cache hit is served free from the shared library.

Speed

Average time per image
wagmi hit
0.1 s
FLUX schnell
~1.5 s
Imagen 4
~9 s
GPT Image 1
~30 s
Instant on a cache hit

Price

List price per image
wagmi hit
$0.000
FLUX schnell
$0.003
Imagen 4
$0.040
GPT Image 1
$0.042
Free on a cache hit

Times and prices vary with model, load, and settings; a cache hit skips generation entirely. Sources: OpenAI · Google · fal.ai · Artificial Analysis.

How it works

An image library shaped by the people who use it

Your request flows down, your image comes straight back up — and every prompt you send shapes what gets built next. The library is a record of what people actually want; with no one searching, nothing new is ever made.

Your request
"a vintage bicycle against a brick wall"
POST /v1/images/generations
The response
https://cdn.wagmi.photos/assets/pd12m-8f31…/image.webp
"result": "hit" · 41 ms · $0.055 saved

Cloudflare edge worker — authenticates your key, embeds your prompt with BGE on Workers AI, and answers from the edge. It never runs a GPU in the request path.

The shared library
  1. 1Your prompt's BGE vector is matched against the stored prompt of every image in the library.
  2. 2Near match — the image is served instantly. That's a hit.
  3. 3Truly new — you get a 202 and the prompt joins the build queue. No waiting.
  4. 4The backfill generates the most-requested misses, so tomorrow they're hits.
GMI Cloud

Runs the background GPUs that generate truly new images.

Backblaze B2

Stores every image durably — zero egress back to the edge.

Vectorize

Indexes each new image's prompt vector so the next similar prompt is a hit.

No users, no library.

Every search is a vote for what gets made next. The library isn't ours — it's the shape of what everyone's looking for. Use it and you grow it.

We're all gonna make it.
Safety

Every prompt is checked before it's built

Two filters run before we ever spend a GPU. If a prompt trips either one, we don't generate it — and you still get the closest image already in the library.

Trademark & brand filter

Prompts that name brands, logos, or protected characters are stopped before generation — so we never mint images that infringe someone else's marks.

Content moderation

Every prompt runs an automated safety check — hate, violence, sexual, and self-harm — and anything flagged is turned away.

Closest match, always

A stopped prompt still returns the nearest image already in the library. You get a result — we just never generate the risky one.

OpenAI compatible

Use the OpenAI SDK.
Get wagmi caching.

No new SDK, no custom response format. Point your existing image-generation requests at wagmi.photos and we return OpenAI-compatible responses with an extra shared_cache block.

Try it in the playground →
Same SDK Same response shape Cache metadata
OpenAI SDK
from openai import OpenAI

client = OpenAI(
    base_url="https://api.wagmi.photos/v1",
    api_key="YOUR_WAGMI_KEY",
)

img = client.images.generate(
    prompt="a corgi wearing sunglasses on a beach",
    extra_body={"cache_tolerance": 0.15,
                "generate_on_miss": True},
)
print(img.data[0].url)
API
curl -X POST https://api.wagmi.photos/v1/images/generations \
  -H "Authorization: Bearer $WAGMI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "a corgi wearing sunglasses on a beach",
       "cache_tolerance": 0.15, "generate_on_miss": true}'
Cache hit · 41 ms · $0.055 saved
{
  "data": [{ "url": "https://cdn.wagmi.photos/assets/pd12m-8f31…/image.webp" }],
  "shared_cache": {
    "result": "hit",
    "similarity": 0.9312,
    "source": "pd12m",
    "model_used": "flux-schnell",
    "cost_saved_usd": 0.055
  }
}
Pricing

One plan. Every image.

A free, openly licensed image library that gets better the more it's used — full-resolution and open to everyone, plus a single upgrade that adds a commercial license and unlimited access. Two dollars a month, cheaper than every stock site.

Free

Search the whole library and pull the closest match, instantly. It grows the more it's used — and so does what you get back.

$0/forever
  • Unlimited search & instant closest-match
  • Full-resolution image URL in every response
  • Full open-license public library
  • Missing prompts generated in the background
  • Commercial-use license & indemnity
  • Unlimited rate + API access
Start browsing

Openly licensed. Close enough, on purpose.

Every image here is openly licensed — the seed pool is public-domain PD12M, and generated images are shared under the same permissive terms. Reach for wagmi.photos when you don't need a pixel-exact, one-off render: you need a good image now, with a license you don't have to think about. Need guaranteed commercial use? That's the one upgrade.

FAQ

Questions, answered

The short version of how the shared library works, what you get back, and what it costs.

What is wagmi.photos?
A free, openly licensed image library that gets better the more it's used. Every prompt is matched against every image already generated — you get the closest match instantly, and prompts the library can't answer yet are generated in the background and added to the shared pool.
Do I always get exactly my prompt?
No — you always get the closest existing match, served instantly from the edge. Everyday prompts almost always land a strong match; hyper-specific ones return the nearest image that already exists — close, but maybe not every detail. If nothing close exists yet, your exact prompt is queued and generated in the background, so it becomes a hit for everyone next time.
What does cache_tolerance do?
It sets how close a match has to be to count as a hit versus an approximate match. Without a BYOK key it never changes what you get back — you always receive the closest image — it just controls the label and which prompts get flagged as gaps worth generating. With a BYOK key enabled, tolerance also decides when your key fires: anything below the floor generates fresh instead of settling for the closest match.
What happens when my prompt isn't in the library yet?
By default (generate_on_miss: true) the prompt is queued and generated in the background by the shared backend, then stored in the library — so the pool keeps growing toward real demand. Set generate_on_miss: false to only ever pull from the cache and never trigger a generation.
Is it OpenAI-compatible?
Yes. Point the official OpenAI image SDK at the wagmi.photos base URL — no other code changes. You get the standard response shape plus a shared_cache block telling you whether it was a hit, how close the match was, and what it saved you.
Is it really free? What's the license?
Images are shared under a permissive open license and free to use. You pay for access to the library through a plan (from $0/mo), never per image — and every cache hit is $0 to serve.

Generator config

Strict (Exact) Loose (General concept)
Tolerance: 0.15 Normal Match
On cache miss

Session history

No runs yet.

No image rendered

Enter a prompt and click generate to query the cache and generate images.

Querying index & caches...

Cache result
Saved $0.00 Total savings added
HIT
Cosine similarity -
Model -
Source -
Cache latency -

Telemetry & performance

0 Total requests
0 Cache hits
0 Cache misses
0% Cache hit rate

Total savings realized

Estimated credits and network latency costs saved through semantic hits.

$0.00

Plan

Loading…

Bring your own key

Add your own OpenAI or GMI Cloud API key and the playground generates a fresh image whenever the library has no close-enough match. Generated images join the shared library. Spend shown is an estimate (images × list price) — your provider bills you directly.

Loading…

Credentials & authentication

For calling the wagmi.photos API from your own code (Authorization: Bearer sc-…). The playground here is already authenticated by your login.
No keys yet.

Advanced actions

This clears your browser's local state — the telemetry counters, session history, and playground settings. Your account and API keys are stored server-side and are not affected.

Docs

API reference

One OpenAI-compatible endpoint, a shared image library in front of it. Everything below is the whole API.

Authentication

All generation requests need a Bearer key, and keys belong to your account. Log in with a magic link (we email it to you — no password), then create a key on the Account page. Or call the endpoint directly with your logged-in session cookie:

POST /v1/keys/generate
# requires a logged-in session — unauthenticated calls return 401
curl -X POST https://api.wagmi.photos/v1/keys/generate \
  -H "Cookie: wagmi_session=…" \
  -H "Content-Type: application/json" \
  -d '{ "label": "my-laptop" }'

{ "key": "sc-nA93…", "created_at": 1783468800 }

Key minting is rate-limited (10 per minute per IP). Store the key yourself — it is hashed (SHA-256) before it touches our database, so it cannot be shown again. Send it on every request as Authorization: Bearer sc-your-key.

Generate or fetch an image

POST /v1/images/generations

The request shape matches the OpenAI Images API, so the official SDKs work by pointing base_url at https://api.wagmi.photos/v1. Your prompt is embedded with BGE and matched against the stored prompt of every image in the shared library; the closest match above your tolerance floor is served instantly.

Request body

FieldTypeDefaultDescription
promptstringrequired What you want. Prompts are normalized (trimmed, lowercased, whitespace collapsed) before matching and queueing.
cache_tolerancenumber 0–10.15 How far a match may drift from your prompt. 0 accepts only the closest matches, 1 accepts the loosest. See how matching works.
generate_on_missbooleantrue Whether a miss queues background GPU generation for this prompt. Set false for cache-only behaviour. See semantics.
ninteger1 Only 1 is supported; anything else returns 422.
sizestring Accepted for OpenAI compatibility. Every response already includes thumb, medium and large URLs.
modelstring Accepted for OpenAI compatibility. Matching is model-agnostic; shared_cache.model_used reports the model that created the served image.

Example

curl -X POST https://api.wagmi.photos/v1/images/generations \
  -H "Authorization: Bearer $WAGMI_KEY" -H "Content-Type: application/json" \
  -d '{
    "prompt": "a lighthouse in a storm",
    "cache_tolerance": 0.15,
    "generate_on_miss": false
  }'

Response — served from the library (200)

{
  "created": 1783468800,
  "data": [{ "url": "https://cdn.wagmi.photos/assets/pd12m-8f31…/image.webp" }],
  "shared_cache": {
    "result": "hit",
    "similarity": 0.93,
    "cost_saved_usd": 0.055,
    "model_used": "flux-schnell",
    "source": "pd12m",
    "sizes": { "thumb": "…", "medium": "…", "large": "…" },
    "original_url": "https://pd12m.s3.us-west-2.amazonaws.com/…"
  }
}

original_url is the external source image when one exists, and null for generated images.

Response — nothing close enough yet (202)

{
  "created": 1783468800,
  "data": [],
  "shared_cache": {
    "result": "pending",
    "similarity": 0,
    "cost_saved_usd": 0,
    "generation_queued": true
  }
}

Result values

resultStatusMeaning
hit200 Similarity is at or above your tolerance floor. The image is served; nothing is queued.
approximate200 The best image falls below your floor. It is served anyway so you have something to show, and the prompt is queued for generation (unless opted out). generation_queued is included and cost_saved_usd is 0 — only true hits count as savings.
pending202 The library has nothing to serve. data is empty and the prompt is queued for generation (unless opted out). Retry the same prompt later — once built, it is a hit for everyone.
generated200 You have a BYOK provider key enabled and the result would have been approximate or pending, so a fresh image was generated with your key and added to the shared library. shared_cache.byok carries your usage: {"used", "cap", "est_spend_usd"}. When your key can't fire (monthly cap reached, provider error), the normal approximate/pending response is returned with shared_cache.byok.status set to cap_reached or provider_error.

With BYOK enabled, a prompt that fails the content policy (denylist or moderation) returns 400 with {"error": "content_policy", "category": "…"} and nothing is generated or counted.

How matching works

Matching is prompt-to-prompt: your prompt's BGE text embedding (bge-base-en-v1.5 on Workers AI) is compared by cosine similarity against the stored prompt embedding of every library image. Your cache_tolerance (clamped to 0–1) maps linearly to the similarity floor: floor = 0.87 − tolerance × (0.87 − 0.75), so tolerance 0 → floor 0.87 and tolerance 1 → floor 0.75. The single nearest library prompt is compared against that floor — at or above it you get a hit, below it an approximate. Realistic scores live in the ~0.7–0.95 band. See how semantic matching works for the full picture.

generate_on_miss semantics

Generation costs GPU time, so it is opt-out per request — but the queue is shared, and one prompt can be requested by many callers with different flags. The rules:

  • Default is generate. A miss with the field unset (or true) queues the prompt for background generation.
  • Opting out is per prompt, not per library. generate_on_miss: false still records the prompt and its demand count — it just tells the backfill to skip it.
  • Generation wins. If the prompt is already queued for generation, a later request with false does not un-queue it. And if the prompt was stored opted-out, the first request that arrives with the field unset or true upgrades it, so it gets generated. Once a prompt wants generation, it stays wanted.
  • The response tells you the effective state. shared_cache.generation_queued on pending and approximate responses reflects the merged result, not just your request — send false for a prompt someone else queued and you will get generation_queued: true back.
When to opt out: use generate_on_miss: false when you only want instant, $0 answers — placeholder art, previews, high-volume UI fills — and a miss should stay a miss instead of spending GPU time.

Errors

StatusWhen
400Body is not valid JSON, or not a JSON object.
401Missing or invalid API key.
422n is set to anything but 1, or generate_on_miss is not a boolean.
429Rate limit exceeded — generation requests (per account) and key minting (per IP) are each limited to 10 per minute.
502An upstream dependency failed; the body includes a detail string.

Health

GET /healthz

Returns {"status":"ok"}. No authentication.

Developers

A drop-in for the OpenAI Images API

Keep the official OpenAI SDK. Change one line — the base URL — and every request is answered cache-first, with a shared_cache block riding along in the response.

The only change

Before — OpenAI
base_url = "https://api.openai.com/v1"
After — wagmi.photos
base_url = "https://api.wagmi.photos/v1"

Swap your key for a wagmi.photos key (sc-…). Method names, the prompt field, and the way you read data[0].url stay exactly the same.

Python

from openai import OpenAI

client = OpenAI(
    base_url="https://api.wagmi.photos/v1",
    api_key="sc-your-key",
)

img = client.images.generate(
    prompt="a lighthouse in a storm",
    extra_body={
        "cache_tolerance": 0.15,
        "generate_on_miss": True,
    },
)

print(img.data[0].url)
# raw response also carries a shared_cache block

JavaScript

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.wagmi.photos/v1",
  apiKey: "sc-your-key",
});

const img = await client.images.generate({
  prompt: "a lighthouse in a storm",
  cache_tolerance: 0.15,
  generate_on_miss: true,
});

console.log(img.data[0].url);

cURL

curl -X POST https://api.wagmi.photos/v1/images/generations \
  -H "Authorization: Bearer $WAGMI_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "a lighthouse in a storm" }'

What stays the same, what you gain

Unchanged

  • The official OpenAI SDKs and method names
  • The prompt field and request flow
  • Reading the image from data[0].url

Added by wagmi.photos

  • A shared_cache block: result, similarity, cost saved
  • ~0.1 s cache hits at $0 per image
  • cache_tolerance and generate_on_miss controls
Response note: a 202 means nothing close was cached yet — data is empty and (unless you opted out) the prompt was queued to generate. Handle it like a soft miss: proceed without an image or retry later. Full details in the API reference.
Developers

How semantic matching works

Every library image is stored with the prompt that made it. A match is just the nearest stored prompt to your prompt — text to text, no keywords, no tags.

Prompts match prompts

wagmi.photos embeds text prompts into a 768-dimensional space with the bge-base-en-v1.5 model, running on Workers AI at the edge. Every image in the library is indexed by the embedding of its own prompt — there are no image vectors. Because your prompt and the stored prompts are embedded by the same model, "a golden retriever" lands right next to the prompts that already produced one.

From prompt to match

  1. Your prompt is normalized (trimmed, lowercased, whitespace collapsed).
  2. BGE turns it into a 768-dim text vector at the edge.
  3. Vectorize finds the single nearest stored prompt vector by cosine similarity.
  4. That similarity is compared to your tolerance floor — at or above it is a hit; below it is approximate.

Similarity, illustrated

"a dog and a cat"
hit · 0.93
"a flamingo in a top hat doing my taxes"
approximate · 0.78

Illustrative cosine-similarity scores — in practice they land in a fairly narrow ~0.7–0.95 band. The generic prompt lands squarely on an existing prompt; the very specific one only finds a distant cousin.

Tolerance sets the floor

Your cache_tolerance (clamped to 0–1) maps linearly to the cosine-similarity floor a match must clear: floor = 0.87 − tolerance × (0.87 − 0.75).

tolerance 0 → floor 0.87 · strict, near-exact only floor 0.75 · loose, more hits ← tolerance 1

At or above the floor you get a hit. Below it, the closest image is still served as approximate and the prompt is queued to generate (unless you opted out).

Same model, same space — that is why a generic prompt reliably hits while a hyper-specific one returns the closest existing image. See the matching details in the API reference, or the walkthrough on the home page.
Developers

Give your agent cheap images

Paste this skill file into your coding agent — a Claude Code SKILL.md, a Cursor rule, or a system-prompt block — so it reaches for the shared cache before paying to generate.

The skill file

Save it as SKILL.md or drop it straight into your agent's instructions. It hands the agent the endpoint, the request shape, and — the part that matters — how to act on hit / approximate / pending.

---
name: wagmi-photos-images
description: Fetch images cheaply and instantly from the wagmi.photos shared cache before paying to generate. Use whenever a task needs an image and "close enough" beats pixel-perfect.
---

# wagmi.photos — cache-first images

Get an image in ~100 ms for $0 by matching the shared library first. Only pay a
generator when the prompt is genuinely new or must be exact.

## When to use this
- You need a stock-style or illustrative image and an approximate match is fine.
- You want to avoid generation cost and latency by default.

Do NOT rely on the cache when the image must match a hyper-specific prompt
exactly (brand assets, precise composition). Use a dedicated image model there.

## Endpoint
POST https://api.wagmi.photos/v1/images/generations
  Authorization: Bearer sc-your-key
  Content-Type: application/json

Body fields:
- prompt            (string, required)
- cache_tolerance   (0..1, default 0.15)  lower = stricter match
- generate_on_miss  (bool, default true)  false = never spend GPU on a miss

## Call it
curl -X POST https://api.wagmi.photos/v1/images/generations \
  -H "Authorization: Bearer $WAGMI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "a vintage bicycle against a brick wall",
       "cache_tolerance": 0.15,
       "generate_on_miss": true}'

## Act on shared_cache.result
- "hit"          (HTTP 200): use data[0].url. Free and instant, you are done.
- "approximate"  (HTTP 200): a close image is in data[0].url. Use it only if it
                  fits the task; the exact prompt was queued for next time.
- "pending"      (HTTP 202): nothing close yet, data is empty. Generate with
                  your own model if you need an image now. The prompt was queued
                  (unless you opted out), so retrying later will hit for $0.
- "generated"    (HTTP 200): the account has a BYOK provider key enabled and a
                  fresh image was generated with it (below-tolerance requests
                  only). data[0].url is the new image; shared_cache.byok reports
                  {used, cap, est_spend_usd}. If byok.status is "cap_reached" or
                  "provider_error" instead, the response degraded to the normal
                  approximate/pending shape.
- HTTP 400 {"error":"content_policy"}: the prompt was blocked by the denylist or
                  moderation (BYOK path only). Do not retry the same prompt.

## Rules for the agent
1. Default to the cache. Send generate_on_miss=false when you only want free,
   instant results and a miss is acceptable.
2. Never treat "approximate" as exact — verify it matches the request.
3. On 202, do not block waiting. Proceed without an image or fall back to a real
   generator, then retry the same prompt later for a cheap hit.
4. "generated" costs the account owner real provider spend — respect
   generate_on_miss=false as the way to guarantee a $0 call.
4. Reuse one wagmi.photos key. It is hashed server-side; keep it secret.

How the agent should behave

Default path — cheap & fast

  • Ask the cache first for anything illustrative.
  • Accept approximate when it fits the task.
  • Set generate_on_miss=false for throwaway previews.

When exact matters

  • Lower cache_tolerance toward 0 for near-exact only.
  • Leave generate_on_miss=true so misses get built.
  • On pending, fall back to a dedicated model.

Wire up a key

Keys are tied to your account. Log in with a magic link (email, no password), create a key on the Account page, then export it as WAGMI_KEY:

# 1. Log in at https://wagmi.photos/#/login (magic-link email)
# 2. Account → Create API key → copy the sc-… key (shown once)
export WAGMI_KEY=sc-…

Prefer the API? POST /v1/keys/generate also works with a logged-in session cookie — unauthenticated calls return 401. The full field reference lives in the API docs.

Could not load image resource.