Developer Docs

Pixfaro API & MCP

Every image model behind one endpoint: your agent asks for an image; Pixfaro holds the provider accounts, keys, retries and format differences, and bills one prepaid balance.

REST API REST

Base URL https://api.pixfaro.com. JSON everywhere. Errors use one envelope:

{ "error": { "code": "insufficient_balance", "message": "…", "request_id": "rq_a1c4f0" } }

Every response carries an x-request-id header — include it when you contact support. Money is always a USD decimal string ("0.080", never a float). Times are ISO 8601 UTC.

Authentication

Principal How
API key Authorization: Bearer pf_live_…
MCP OAuth 2.1 at https://mcp.pixfaro.com (remote) or PIXFARO_KEY env (stdio)

Keys are created on the dashboard. Scopes: generate (default — image endpoints + balance) and full (adds billing, logos, and brand-kit management).

POST /v1/images/generations

Generate an image. Sync — the response is the finished image.

{
  "model": "nano-banana-2",
  "prompt": "a lighthouse at night, minimal flat style",
  "aspect_ratio": "16:9",
  "resolution": "1K",
  "overlay": "default"
}
Field Required Notes
model yes id from GET /v1/models
prompt yes 1–4000 chars
aspect_ratio no "w:h", e.g. "1:1" (default), "16:9", "9:16"
resolution no per-model tiers from GET /v1/models prices (default 1K)
overlay no corner branding: "default" applies your saved brand kit, or an explicit object (below)

n > 1 and response_format other than "url" are not supported yet — one image per request, delivered as a hosted URL (your agent's context never carries base64).

200:

{
  "id": "img_8f2a…", "url": "https://api.pixfaro.com/i/…", "model": "nano-banana-2",
  "resolution": "1K", "latency_ms": 10400, "cost": "0.081", "balance_after": "12.32",
  "overlay_applied": false, "request_id": "rq_a1c4f0"
}

Errors: 402 insufficient_balance (body includes balance, needed, topup_url), 400 invalid_model / invalid_prompt / invalid_request, 409 model_disabled, 429 rate_limited (+ retry_after_s), 502 provider_failedno charge, and the body says so explicitly: "charged": false.

Overlay object

Brands a corner of the image with your handle or logo. Exactly one of text (≤ 64 chars) or logo_id (a logo_… from POST /v1/logos):

{ "overlay": { "text": "@yourbrand", "position": "bottom-right", "opacity": 0.9 } }

Optional: position (default bottom-right), opacity (0.2–1.0), size, margin, and for text font / weight / color ("auto" picks ink or paper per corner brightness). Save your defaults once via PUT /v1/brand-kit, then "overlay": "default" everywhere. A bad overlay fails the request before generation — you are not charged.

POST /v1/images/edits

Edit a previous generation with a natural-language instruction. Same response shape as generations.

{ "model": "nano-banana-2", "image": "img_8f2a…", "instruction": "make the sky darker" }

GET /v1/models

Public, no auth. Cached ~5 min.

[{ "id": "nano-banana-2", "name": "Nano Banana 2",
   "best_for": "general-purpose images: blog art, social posts, mockups",
   "p50_ms": 10700, "p95_ms": 13600, "price": "0.080",
   "prices": { "1K": "0.080", "2K": "0.121", "4K": "0.181" },
   "mode": "sync", "enabled": true }]

price is the 1K figure; prices maps every supported resolution tier to its retail price. enabled: false marks models that are coming soon (calling one returns 409 model_disabled).

GET /v1/balance

{ "balance": "12.32" }

Account endpoints (scope full)

Endpoint What
POST /v1/topups { "amount_usd": 25 }{ "checkout_url": … } (Stripe; integer 5–1000, default 10)
GET/PATCH /v1/autoreload auto top-up: { enabled, threshold, amount, monthly_cap } — explicit opt-in
POST /v1/logos upload a transparent PNG (≤ 1 MB, ≤ 2048px/side, ≤ 10 live logos) — raw body or multipart
GET /v1/logos · DELETE /v1/logos/:id list / remove logos
GET/PUT/DELETE /v1/brand-kit saved overlay defaults used by "overlay": "default"

Top-ups, keys, and usage are also on the dashboard.

POST /v1/abuse-reports

Public, no auth — report a generated image that violates our acceptable use policy: { "image_url", "reason", "details"?, "reporter_email"? }image_url must be a Pixfaro-served image link (…/i/…).

Rate limits

Per key: 60 requests/min. Per account: 5 keys. 429 responses carry retry_after_s. Need more? Ask — limits are raised case-by-case.

Versioning

Path-versioned (/v1/). Additive changes (new optional fields) don't bump the version; breaking changes go to /v2/ with 6 months of /v1/ support. The x-pixfaro-deprecation header announces sunsets ahead of time.

MCP server MCP

One MCP connection gives your agent every major image model. Two ways in:

Transport For How
Remote (streamable HTTP + OAuth 2.1) claude.ai, Claude Desktop, any HTTP-capable client add https://mcp.pixfaro.com/mcp — the client runs the OAuth flow, you sign in with your Pixfaro account
Local (stdio, npm) Claude Code, Cursor, Windsurf, config-file setups npx -y @pixfaro/mcp with PIXFARO_KEY in env

Source: github.com/pixfaro/mcp — the client is intentionally small enough to read before you hand it a key.

Setup

Claude Code:

claude mcp add pixfaro -e PIXFARO_KEY=pf_live_… -- npx -y @pixfaro/mcp

Cursor / Windsurf / Claude Desktop (config file):

{
  "mcpServers": {
    "pixfaro": {
      "command": "npx",
      "args": ["-y", "@pixfaro/mcp"],
      "env": { "PIXFARO_KEY": "pf_live_…" }
    }
  }
}

claude.ai / Claude Desktop connector (remote, no key in a file): add custom connector with URL https://mcp.pixfaro.com/mcp.

Tools

Tool What it does
generate_image prompt (+ optional model, aspect_ratio) → hosted image URL, with cost and remaining balance in the reply
edit_image natural-language edit of a previous generation by its img_… id
list_models live models with price, latency, and what each is best for
get_balance current prepaid balance

Replies are agent-readable text carrying a hosted URL — never base64, so your agent's context stays small. When the balance runs low, replies append a top-up warning.

Environment (stdio)

Variable Meaning
PIXFARO_KEY API key (pf_live_…) from pixfaro.com
PIXFARO_API_URL endpoint override (staging / self-hosted)

CLI

The same repo ships the pixfaro CLI for scripts, CI, and pipelines — the literal one-command time-to-first-image:

export PIXFARO_KEY=pf_live_…
npx pixfaro gen "a lighthouse at night, minimal flat style" -a 16:9 -o cover.png
npx pixfaro edit img_8f2a… "make the sky darker" -o v2.png
npx pixfaro models
npx pixfaro balance

-o downloads the image; without it the CLI prints the hosted URL. A failed download never swallows the URL you already paid for.