Open license · Grows with use · OpenAI-compatible

Free, open images.
Shared by everyone.

A free, openly licensed image library that gets better the more it's used. Every prompt returns the closest match in milliseconds; the phrases the library can't answer well yet get generated in the background and added — so the pool keeps expanding and the matches keep sharpening for everyone.

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
How it works

An image library that grows as more people use it

Your request flows down, your image comes straight back up — and every new image joins the shared library, so the next person's prompt is more likely to be a hit.

Your request
"a vintage bicycle against a brick wall"
POST /v1/images/generations
The response
https://cdn.wagmi.photos/img/pd12m-8f31…
"result": "hit" · 41 ms · $0.04 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.

Why it wins

Built for speed and price.

What one image costs

List price per 1024×1024 image · July 2026
GPT Image 1 (medium)
$0.042
Imagen 4 (standard)
$0.040
FLUX.1 [schnell]
$0.003
wagmi.photos hit
$0.000

A cache hit serves an existing image from the shared library — no generation fee, no egress. A truly new prompt is generated once at the model's price, then it's free for everyone after. Library access needs a wagmi.photos plan (from $0/mo) — you pay for access, never per image.

Sources: OpenAI API pricing · Google Gemini API pricing · fal.ai — FLUX.1 [schnell] · retrieved July 2026

How long one image takes

Typical generation time · July 2026
GPT Image 1
~30 s
Imagen 4
~9 s
FLUX.1 [schnell]
~1.5 s
wagmi.photos hit
0.1 s

Generation times vary with load and settings. A cache hit skips generation entirely — one vector search at the edge, and the image is on its way.

Source: Artificial Analysis generation-time benchmarks · retrieved July 2026. Cache-hit latency is the wagmi.photos edge target.

The API

One endpoint. Cache included.

Point the official OpenAI SDK at a new base URL — no other changes. You get back the OpenAI response shape plus a shared_cache block telling you whether it was a hit, how close the match was, and what it saved you.

Try it in the playground →
POST /v1/images/generations 200 OK · 41 ms
Request
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
  }'

Response

{
  "data": [{
    "url": "https://cdn.wagmi.photos/
            img/pd12m-8f31…"
  }],
  "shared_cache": {
    "result": "hit",
    "similarity": 0.9312,
    "source": "pd12m",
    "model_used": "flux-schnell",
    "cost_saved_usd": 0.04
  }
}
Pricing

Simple, predictable pricing

Scale your image generation without the scaling costs. No egress fees, no surprises.

Free

Perfect for sandboxing, prototyping, and integrating the cache.

$0/mo
  • Restricted cache lookup rate
  • Standard CDN asset delivery
  • Access to public domain index
  • Immediate GPU fallbacks
  • SLA uptime guarantees
Launch demo

BYOK

Bring your own GMI Cloud keys. Private GPU generations, straight into the cache.

$5/mo
  • Unlimited semantic cache lookups
  • Custom GMI Cloud GPU compute
  • Private object storage syncing
  • Dedicated key generation access
  • Zero markup on model generations
Bind your keys

Stop paying for the same image twice.

Plug in wagmi.photos and let every generation pull its weight.

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. 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.
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.
What is BYOK?
Bring Your Own Key. Plug in your own GMI Cloud GPU keys to run generations privately on your own compute, straight into the cache — for when you want your exact prompts built on demand rather than waiting on shared, demand-ranked backfill.

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

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/img/pd12m-8f31…" }],
  "shared_cache": {
    "result": "hit",
    "similarity": 0.93,
    "cost_saved_usd": 0.04,
    "model_used": "flux-schnell",
    "source": "pd12m",
    "sizes": { "thumb": "…", "medium": "…", "large": "…" }
  }
}

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.

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.

## 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. 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.