Papéis de Parede
Fundos
Fotos
Páginas para Colorir
Wallpapers.com Image API

Generate, edit, caption, OCR, and upscale images. Simple HTTP + an API key.

Start free — every account gets 1 AI + 10 Standard credits to try.
Open the Developer Console →

Base URL & Auth

https://api.wallpapers.com/v1/...

Authorization: Bearer wpk_your_key        # or  X-API-Key: wpk_your_key

Every request needs your key. Calls run at high priority. A missing/invalid key → 401; out of credits → 402.

Credits

Two pools: AI credits (GPU work) and Standard credits (CPU processing). New accounts start with 1 AI + 10 Standard free. See pricing to buy more or subscribe.

OperationEndpointCost
Generate (text→image)POST /v1/text-to-image2 AI
Image→image / stylePOST /v1/image-to-image2 AI
Edit (instruct / multi-image / inpaint / outpaint)POST /v1/edit2 AI
Face swap (image / video)POST /v1/face-swap2 AI / from 8 AI (by length)
Image to 3D (.glb mesh)POST /v1/image-to-3d3 AI
Image to video (live wallpaper)POST /v1/image-to-video8 AI
Alt-text / captionPOST /v1/image-to-text1 AI
Document OCR (image or PDF → Markdown)POST /v1/ocr1 AI
QA Vision (safety + quality, per-category confidence)POST /v1/image-qa1 AI
Photo metadata (EXIF, DPI, color, dimensions, quality)POST /v1/image-metadata1 Standard
LLM textPOST /v1/text1 AI
UpscalePOST /v1/upscale1 AI
Convert / resizePOST /v1/convert1 Standard

Responses include X-AI-Credits-Remaining and X-Standard-Credits-Remaining headers. Check anytime: GET /v1/me.

Variations bill per image: requesting num_images on a generate/edit call costs the op's price × the number of images (e.g. num_images:3 on Generate = 6 AI). If a generation fails, that image's credits are automatically refunded.

How image generation works (asynchronous)

Image generation — text-to-image, image-to-image, and edit — takes time, so these calls are asynchronous. You submit a job and get a job_id back immediately (HTTP 202) — the API never blocks waiting for the image. You then poll GET /v1/jobs/<job_id> every few seconds until status is "done", and download the image from the returned output_url (a 7-day link). Prefer push over polling? Pass a webhook URL and we'll POST the result to it on completion. Failed jobs are auto-refunded, so you're never billed for an image we couldn't deliver.

Generate an image

# 1) Submit the job — returns a job_id immediately (HTTP 202, never the bytes)
curl -X POST https://api.wallpapers.com/v1/text-to-image \
  -H "Authorization: Bearer wpk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"a misty pine forest at dawn","aspect":"16:9"}'
# → 202 {"job_id":"6f1c…","status":"processing","poll_url":"/v1/jobs/6f1c…"}

# 2) Poll every ~3s until it's done
curl -H "Authorization: Bearer wpk_your_key" \
     https://api.wallpapers.com/v1/jobs/6f1c…
# → {"job_id":"6f1c…","status":"processing"}      (keep polling)
# → {"job_id":"6f1c…","status":"done","output_url":"https://api.wallpapers.com/v1/file/…"}

# 3) Download the finished image from output_url
curl -L -o wallpaper.png "https://api.wallpapers.com/v1/file/…"

Params: prompt (required), aspect (16:9 | 9:16 | 1:1 | 4:3), optional width/height, negative_prompt, steps, guidance (CFG strength, default 4.0 — higher = follow the prompt more closely), seed, webhook (callback URL).

Multiple variations — add "num_images": N (1–4) to fan out N variations of the same prompt. Each variation is a full generation and is billed individually (cost × N). You get one job_id per image to poll: {"num_images":N,"jobs":[{"job_id":"…","status":"processing","poll_url":"/v1/jobs/…"}, …]}.

Image-to-image — POST /v1/image-to-image

curl -X POST https://api.wallpapers.com/v1/image-to-image \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"prompt":"make it snowy","image":"https://you.com/pic.jpg","strength":0.6}'
# → 202 {"job_id":"…","status":"processing"}  — then poll GET /v1/jobs/<id> for output_url

Re-render an image guided by a prompt. image is an http(s) URL or base64 (data-URI ok). Optional: strength (0–1, how far from the original — default 0.7), negative_prompt, steps, guidance (CFG strength), seed, num_images (1–4, billed per variation), webhook. Async — returns a job_id (202); poll GET /v1/jobs/<id> for the output_url.

Alt-text / caption — POST /v1/image-to-text

curl -X POST https://api.wallpapers.com/v1/image-to-text \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"image":"https://you.com/pic.jpg","task":"both"}'
# → {"description":"...","tags":[...],"alt":"..."}

image is an http(s) URL or base64 (data-URI ok). task selects the output: both (default) → {description, tags, alt}; caption → {description}; tags → {tags} (8–15 search tags); alt → {alt} (one WCAG alt-text sentence). Synchronous — unlike image generation, this returns the text directly in the response body (no job_id / polling).

Document OCR — POST /v1/ocr

Parse a document image or PDF into Markdown with Baidu Unlimited-OCR. This is separate from /v1/image-to-text: OCR preserves document text and layout, while image-to-text produces a short caption, tags, or accessibility alt text.

# Submit an image or PDF by public URL (HTTP 202)
curl -X POST https://api.wallpapers.com/v1/ocr \
  -H "Authorization: Bearer wpk_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://you.com/document.pdf","mode":"auto"}'
# → {"job_id":"…","status":"processing","status_url":"/v1/jobs/…"}

# Poll until done
curl -H "Authorization: Bearer wpk_your_key" \
  https://api.wallpapers.com/v1/jobs/<job_id>
# → {"status":"done","result":{"text":"# Parsed document\n…",
#      "format":"markdown","pages":3,"mode":"base",
#      "model":"baidu/Unlimited-OCR","output_tokens":1842}}

Asynchronous — poll GET /v1/jobs/<id>, or pass a webhook. Supply exactly one of url/file_url or file_b64/image_b64. Inputs are limited to 25 MB and PDFs to 32 pages. mode may be auto, gundam, or base; PDFs always use multi-page base mode. Optional: prompt, dpi (100–300), max_length (1024–32768), priority, and webhook. Cost: 1 AI; failures are automatically refunded.

Photo metadata — POST /v1/image-metadata

curl -X POST https://api.wallpapers.com/v1/image-metadata \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"image":"https://you.com/photo.jpg"}'

# Or upload the original file directly:
curl -X POST https://api.wallpapers.com/v1/image-metadata \
  -H "Authorization: Bearer wpk_your_key" \
  -F "image=@/path/to/photo.jpg"

Fast, synchronous, CPU-worker-backed inspection of a PNG, JPEG, WebP, GIF, TIFF, BMP or other Pillow-readable raster image. image accepts a public http(s) URL, a data URI, raw base64, or a multipart file upload (the field may be named image or file). Maximum encoded input size is 25 MB and maximum raster size is 100 MP. Private/local URLs are rejected.

{
  "metadata_version": "image_metadata_v2",
  "file": {"bytes": 2841932, "format": "JPEG", "mime_type": "image/jpeg",
           "sha256": "…", "sha1": "…", "md5": "…", "crc32": "…",
           "estimated_compression_ratio": 12.87},
  "image": {"width": 4032, "height": 3024, "display_width": 3024, "display_height": 4032,
            "pixel_count": 12192768, "display_aspect_ratio_exact": "3:4",
            "mode": "RGB", "bands": ["R","G","B"], "estimated_bits_per_pixel": 24,
            "has_alpha": false, "animated": false, "frames": 1},
  "dpi": {"reported": true, "x": 300, "y": 300, "unit": "pixels_per_inch",
          "print_size_inches": {"width": 13.44, "height": 10.08}},
  "color": {"dominant": "#32475a", "palette": ["#32475a", "…"],
            "palette_pct": [0.41, 0.22], "average": "#536779", "hues": ["blue"]},
  "visual": {"megapixels": 12.19, "aspectRatio": "4:3", "orientation": "portrait",
             "brightness": 0.42, "saturation": 0.31, "contrast": 0.55,
             "sharpness": 0.72, "entropy": 0.64, "pHash": "…"},
  "pixel_analysis": {
    "sample": {"width": 384, "height": 512, "downsampled": true},
    "channel_statistics_normalized_0_1": {"red": {"min": 0, "max": 1, "mean": 0.42, "…": "…"}},
    "luminance_statistics_normalized_0_1": {"min": 0.01, "max": 0.99, "percentiles": {"…": "…"}},
    "histograms_8bit_256_bins": {"red": [0,1,"…"], "green": ["…"], "blue": ["…"], "luminance": ["…"]},
    "unique_rgb_colors_in_sample": 98214, "colorfulness": 48.2,
    "shadow_clipping_pct": 0.2, "highlight_clipping_pct": 0.1,
    "edge_density_pct": 13.4,
    "hashes": {"average_hash_64": "…", "difference_hash_64": "…"}
  },
  "exif": {"Make": "Apple", "Model": "iPhone …", "DateTimeOriginal": "…", "…": "…"},
  "gps": {"GPSLatitudeRef": "N", "GPSLongitudeRef": "W",
          "decimal": {"latitude": 37.3317, "longitude": -122.0301}},
  "xmp": {}, "iptc": {}, "container": {},
  "format_specific": {"jpeg": {"chroma_subsampling": 2, "segments": ["…"],
                                      "quantization_tables": {"0": ["…"]}}},
  "embedded_metadata": {
    "exif": {"present": true, "bytes": 2418, "sha256": "…"},
    "icc_profile": {"present": true, "bytes": 3144, "description": "sRGB …"}
  }
}

The endpoint reads metadata from the original encoded bytes, so EXIF orientation, camera/lens fields, GPS, DPI and embedded profiles are preserved. Large binary maker notes and profiles are represented by byte count + SHA-256 rather than echoed back. It returns every readable EXIF/GPS/XMP/IPTC/container field, ICC profile properties, animation/frame timing, alpha coverage, exact aspect and print calculations, full 256-bin RGB/luminance histograms, channel percentiles, clipping/detail/color metrics, and format internals (PNG chunk CRCs, JPEG segments/quantization/subsampling, TIFF tags, GIF headers, WebP RIFF chunks, or BMP headers). Expensive pixel statistics are sampled at up to 512×512 and the response says when downsampling occurred. The visual and pixel_analysis blocks are deterministic CPU analysis—no GPU or vision model is used. Cost: 1 Standard credit.

QA Vision — POST /v1/image-qa

curl -X POST https://api.wallpapers.com/v1/image-qa \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"image":"https://you.com/upload.jpg"}'

Moderation and quality assessment for one image, returned as structured JSON with a confidence score per category — so you can set your own thresholds rather than accepting ours. Synchronous, typically 5–15s. 1 AI credit, refunded automatically if the vision service is unavailable.

{
  "verdict": "ok",              // ok | review | reject  (ADVISORY only)
  "risk_score": 0,              // 0-100, the strongest unsafe/caution signal
  "reasons": [],
  "description": "A yellow spiral on a solid green background.",
  "quality": { "score": 98, "issues": [] },
  "detected": [],               // categories actually present
  "findings": [                 // ALWAYS all 16, in a fixed order
    {"category":"sexual_explicit","detected":false,"confidence":100,"detail":""},
    {"category":"nudity_partial","detected":false,"confidence":100,"detail":""},
    ...
  ]
}

What each category means, and how we treat it. The tiers below are only our defaults for the advisory verdict — every category is reported to you with its own confidence whatever tier it sits in.

CategoryWhat countsOur default
Blocking — drives reject at ≥75% confidence, review at ≥50%
sexual_explicitVisible sexual act or genitaliareject
nudity_fullFully exposed genitalia or female nipplesreject
gore_graphicPhotorealistic real-world injury, mutilation, corpses. Horror art, skulls, monsters and decorative blood do not countreject
hate_symbolRecognised hate/extremist symbologyreject
illegal_activityDepicted criminal activityreject
minor_sexualisedAn apparent minor shown sexually or undressed. Requires both. Most serious finding — treat any hit as an escalation, not a queue itemreject
Caution — drives review at ≥50%. Legitimate often enough that a human should decide
sexual_suggestiveSuggestive posing/framing without explicit contentreview
nudity_partialLingerie, swimwear, partial exposure, artistic nudereview
violence_mildStylised, fictional or implied violencereview
minor_presentA person who appears under 18 is visible (on its own, not a violation)review
real_person_identifiableA recognisable celebrity or identifiable private individual — a likeness/rights risk, not a safety onereview
Informational — reported but never affect verdict or risk_score. Yours to act on
drugs_alcoholVisible drugs, drug use or alcoholinfo
weaponsFirearms, blades, other weaponsinfo
brand_or_logoVisible third-party brand, logo or trademarkinfo
watermark_or_creditStock watermark or credit line — usually means you are not looking at a licensed originalinfo
ai_generated_lookAppears AI-generated or syntheticinfo

If your policy differs from ours — and it probably does — ignore verdict and gate on the raw confidences. A dating app and a children's education site want very different thresholds on the same image.

confidence is how certain the model is of its answer, not how severe the content is: a confident "not present" is 95–100, genuine uncertainty is 40–60. Every category is returned on every call even when nothing is detected, so indexing findings is stable.

How do I check for a specific thing (e.g. nudity)? Two ways.

Quick — detected lists the categories present. Look for the ones your policy cares about:

r = requests.post(".../v1/image-qa", json={"image": url}, headers=H).json()

if {"nudity_full", "sexual_explicit"} & set(r["detected"]):
    block()                      # explicit / full nudity
elif "nudity_partial" in r["detected"] or "sexual_suggestive" in r["detected"]:
    send_to_human()              # lingerie, swimwear, artistic nude

Tunable — findings carries the confidence, so you set the bar. Every category is present on every call, so this never KeyErrors:

conf = {f["category"]: f["confidence"] for f in r["findings"] if f["detected"]}

if conf.get("nudity_full", 0) >= 90:      block()
if conf.get("nudity_partial", 0) >= 70:   send_to_human()
if conf.get("weapons", 0) >= 60:          log_only()      # your call, not ours

A real example — a lingerie photograph returns verdict: "review", risk_score: 95, and detected: ["sexual_suggestive", "nudity_partial", "real_person_identifiable"], while nudity_full and sexual_explicit stay false. That distinction is the point: partial vs full, and suggestive vs explicit, are separate categories so you can allow one and block the other.

Note detected: false with a high confidence means a confident "no" — not a weak yes. Only read confidence together with detected.

We never reject your image. verdict is a suggestion using sensible defaults (reject ≥75% confidence on explicit/gore/hate/illegal, review ≥50%); the decision is yours — gate on the raw confidence values that matter to your policy. Ordinary swimwear, artistic nudity and horror/fantasy art are treated as normal creative content, not violations.

Edit an image — POST /v1/edit

Edit an existing image. Set mode to choose the kind of edit:

image is an http(s) URL or base64 (data-URI ok). Optional on any mode: prompt, negative_prompt, steps, guidance (CFG strength, default 4.0 — higher = follow the edit instruction more closely), seed, num_images (1–4 variations, billed per variation), webhook. On instruct/multi you may also set width/height to force the output size (default = the input image's size). Async — returns a job_id (202); poll GET /v1/jobs/<id> until "done", then download output_url.

1. Instruct — edit the whole image from a text instruction (no mask):

Restyle a photo — anime, cartoon, oil painting and 20+ more. Pass mode: "instruct" with a style and the model restyles the whole image while holding pose, proportions and camera angle. style is optional; omit it for the base model.

image accepts an http(s) URL (we fetch it) or base64, with or without the data: prefix. prompt is optional too — leave it out and the style supplies its own instruction; send one to override.

# the styles, and which are backed by a trained adapter  (FREE — no credits)
curl -H "Authorization: Bearer wpk_your_key" https://api.wallpapers.com/v1/styles
# → {"styles":[{"style":"anime","kind":"lora","available":true}, …],"count":26}
KindStyles
lora — trained adapter, best fidelity anime cartoon comic polaroid
prompt — instruction preset, no adapter oil-painting watercolor chinese-ink pencil charcoal renaissance baroque cyberpunk synthwave steampunk pixel-art voxel claymation isometric cinematic old-photo ghibli dark-fantasy psychedelic papercraft embroidery lego
curl -X POST https://api.wallpapers.com/v1/edit \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"mode":"instruct","style":"anime","image":"https://you.com/photo.jpg"}'
# → 202 {"job_id":"…","poll_url":"/v1/jobs/…"}
# then: curl -H "Authorization: Bearer wpk_your_key" https://api.wallpapers.com/v1/jobs/<id>
#       and download output_url when status == "done"

Other mode values on the same endpoint: multi (reference several images in one prompt), inpaint (needs a mask; white = repaint), outpaint (needs direction + expand).

curl -X POST https://api.wallpapers.com/v1/edit \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"mode":"instruct","style":"anime",
       "image":"https://you.com/photo.jpg",
       "prompt":"Turn this photo into an anime style illustration"}'
# → 202 {"job_id":"…","poll_url":"/v1/jobs/…"}   then poll for output_url
# `image` accepts an http(s) URL OR base64 (with or without the data: prefix).
curl -X POST https://api.wallpapers.com/v1/edit \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"mode":"instruct","image":"https://you.com/pic.jpg",
       "prompt":"make it night-time with a full moon"}' \
  --output edited.png

2. Multi-image — reference several images in one edit (combine subjects, place a person in a scene, swap a face — pass the other image(s) in images):

  -d '{"mode":"multi","image":"https://you.com/scene.jpg",
       "images":["https://you.com/face.jpg"],
       "prompt":"replace the person's face with the face in the second image"}'

3. Inpaint — repaint only a masked region (mask: white = repaint, black = keep):

  -d '{"mode":"inpaint","image":"https://you.com/pic.jpg",
       "mask":"https://you.com/mask.png","prompt":"a vase of flowers"}'

4. Outpaint — extend the canvas; the model fills the new border (direction: all | up | down | left | right, expand: pixels):

  -d '{"mode":"outpaint","image":"https://you.com/pic.jpg",
       "direction":"all","expand":256,"prompt":"continue the landscape"}'

Face swap — POST /v1/face-swap

Swap a source face onto an image or a video target. Consent-gated: "consent": true is required (for consent-based use only — not impersonation or non-consensual content). Asynchronous: returns a job_id immediately; poll GET /v1/jobs/<id> for the output_url (a 7-day link to the result). Billed per swap — 2 AI for an image target; a video is billed by length starting at 8 AI (≤15s), with the per-second rate tapering down the longer the clip (e.g. ~32 AI for 1 min, ~104 AI for 5 min). The response's billed_credits field reports the exact charge; a failed swap is fully auto-refunded.

curl -X POST https://api.wallpapers.com/v1/face-swap \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"source_url":"https://you.com/face.jpg",
       "target_url":"https://you.com/clip.mp4",
       "consent":true}'
# → 202 {"job_id":"…","status":"processing","target_kind":"video","status_url":"/v1/jobs/…"}
# then: curl -H "Authorization: Bearer wpk_your_key" https://api.wallpapers.com/v1/jobs/<id>
#   → {"status":"done","kind":"video","output_url":"https://…/swapped.mp4"}

Inputs: source_url/target_url (any GET-able URL — pre-signed S3 ok) or source_b64/target_b64. Optional: target_kind (image|video, inferred from the target otherwise; an animated GIF counts as video — every frame is swapped — so it is billed at the video rate), webhook, and an options object — processors (face_swapper face_enhancer), face_swapper_model, pixel_boost (128x128|256x256|512x512), face_enhancer_model (gfpgan_1.4|codeformer|gpen_bfr_512), face_enhancer_blend (0–100), output_quality (0–100), output_fps (videos). Video swaps are billed by length — every frame is swapped, so a longer target costs more, but the per-second rate tapers down the longer the clip (bulk discount). See Pricing.

Priority. Keys enabled for priority can add "priority":"high" to a request to have it served ahead of standard requests — send it for your premium users' swaps and omit it for the rest. It is silently ignored for keys not granted priority (no error). The same field works on the image, image-to-3D, and image-to-video endpoints. Contact us to enable it on your key.

Content moderation. Every face-swap input is automatically screened for NSFW / disallowed content. If the source or target is blocked, the job ends as {"status":"rejected","reason":"content_policy"} when you poll — you are not charged (auto-refunded), and retrying the same input will be rejected again. Handle it as a normal user-facing outcome (ask for different media), not as an error to retry.

Image to 3D — POST /v1/image-to-3d

Turn a single image into a 3D model (a .glb mesh) with TripoSR. Asynchronous: returns a job_id immediately; poll GET /v1/jobs/<id> for the output_url (a 7-day link to the .glb). Billed 3 AI per generation.

curl -X POST https://api.wallpapers.com/v1/image-to-3d \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"image_url":"https://you.com/object.jpg"}'
# → 202 {"job_id":"…","status":"processing","status_url":"/v1/jobs/…"}
# then: curl -H "Authorization: Bearer wpk_your_key" https://api.wallpapers.com/v1/jobs/<id>
#   → {"status":"done","output_url":"https://…/model.glb"}

Inputs: image_url (any GET-able URL) or image_b64. Optional: webhook and an options object — foreground_ratio (0–1, default 0.85), mc_resolution (marching-cubes res, default 256). Works best on a single centered subject; the background is auto-removed before reconstruction.

Image to video — POST /v1/image-to-video

Animate a still image into a short looping video (a live wallpaper). Asynchronous: returns a job_id immediately; poll GET /v1/jobs/<id> for the output_url (a 7-day link to the .mp4). Billed 8 AI per generation (video is GPU-minutes).

curl -X POST https://api.wallpapers.com/v1/image-to-video \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"image_url":"https://you.com/scene.jpg","prompt":"gentle drifting clouds"}'
# → 202 {"job_id":"…","status":"processing","status_url":"/v1/jobs/…"}
# then: curl -H "Authorization: Bearer wpk_your_key" https://api.wallpapers.com/v1/jobs/<id>
#   → {"status":"done","output_url":"https://…/live.mp4"}

Inputs: image_url (any GET-able URL) or image_b64. Optional: prompt (describe the motion), webhook, and an options object — size, frames, steps, loop_seconds.

LLM text — POST /v1/text

curl -X POST https://api.wallpapers.com/v1/text \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"prompt":"Write 5 SEO tags for a misty forest wallpaper."}'
# → {"text":"..."}

Upscale — POST /v1/upscale

curl -X POST https://api.wallpapers.com/v1/upscale \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"image":"https://you.com/pic.jpg","scale":4}' \
  --output upscaled.jpg

image is an http(s) URL or base64. scale = 2 | 4 (default 4) — or pass target_long (px) to set the longest edge directly. Returns image/jpeg.

Convert / resize (Standard) — POST /v1/convert

curl -X POST https://api.wallpapers.com/v1/convert \
  -H "Authorization: Bearer wpk_your_key" -H "Content-Type: application/json" \
  -d '{"image":"https://you.com/pic.png","format":"webp","width":1920}' \
  --output out.webp

format = png | jpg | webp (required). Optional width/height (px; aspect preserved if you give just one) and quality (1–100, for jpg/webp). CPU processing — charges Standard credits, not AI.

Check credits — GET /v1/me

curl https://api.wallpapers.com/v1/me -H "Authorization: Bearer wpk_your_key"
# → {"label":"my-app","prefix":"wpk_1234","ai_credits":97,"standard_credits":10}

Poll an async job — GET /v1/jobs/<id>

# every image/edit/OCR/face-swap call returns a {"job_id":"abc"} (HTTP 202) — poll it:
curl https://api.wallpapers.com/v1/jobs/abc -H "Authorization: Bearer wpk_your_key"
# → {"status":"processing"}                                  (keep polling)
# → {"status":"done","output_url":"https://api.wallpapers.com/v1/file/…"}   (free — no charge)
# → {"status":"failed","error":"…"}                          (transient error — auto-refunded, safe to retry)
# → {"status":"rejected","reason":"content_policy",
#     "error":"input rejected: content not permitted"}       (blocked by moderation — auto-refunded, do NOT retry)

Terminal statuses. A job ends in exactly one of:

statusMeaningHow to handle
doneSuccessDownload output_url, or read result for OCR/text jobs.
failedTransient error (upstream/GPU)Charge auto-refunded. Safe to retry the same request.
rejectedInput blocked by content moderation (e.g. face swap's NSFW / non-consensual-content filter refused the source or target)Charge auto-refunded. Do NOT retry the same input — it will be rejected again. Surface error to your user and ask for different media. Check reason=="content_policy" to detect this case.

Webhooks

Get notified when a job finishes instead of waiting on the response. Set a default callback in the console, or pass one per request with "webhook" in the body (as shown in the generate example above). When the generation completes we POST:

POST your-webhook-url
{
  "event": "generation.completed",
  "gen_id": "…",
  "op": "text-to-image",
  "status": "completed",
  "prompt": "…",
  "output_url": "https://api.wallpapers.com/v1/file/… (link valid 30d)",
  "input_url": null
}

You are also called back when a job ends without a result, so you never have to guess whether one is still running. Both of these are terminal and both are auto-refunded — check status to tell them apart:

POST your-webhook-url
{
  "event": "generation.rejected",
  "job_id": "…",
  "op": "face-swap-video",
  "status": "rejected",
  "reason": "content_policy",
  "error": "input rejected: content not permitted",
  "refunded": 8
}
POST your-webhook-url
{
  "event": "generation.failed",
  "job_id": "…",
  "op": "face-swap-video",
  "status": "failed",
  "error": "…",
  "refunded": 8
}

rejected means our content filter declined that specific input — retrying the same file will be declined again, so treat it as final and surface it to your user. failed is a system-side fault and is safe to retry. The same status and reason values are returned by GET /v1/jobs/<id>, so polling and webhooks agree.

The per-request webhook takes precedence over your account default. All URLs are Wallpapers.com links — never third-party storage URLs. Your images are stored long-term; the link above just expires after 30 days — fetch a fresh one anytime via GET /v1/generations.

Retrieve your generations

We keep your inputs + outputs in your own private storage long-term — fetch them anytime as Wallpapers.com links (each call returns fresh 30-day links):

curl https://api.wallpapers.com/v1/generations?limit=50 \
  -H "Authorization: Bearer wpk_your_key"
# → {"total":N,"generations":[{"op":"text-to-image","prompt":"...",
#      "output_url":"https://api.wallpapers.com/v1/file/...","input_url":null,"at":"..."}, ...]}

Errors

CodeMeaning
401Missing / invalid / revoked key
402Insufficient credits — top up in the console
400Bad input (e.g. missing prompt)
502/503Upstream error — safe to retry

See pricing & plans or manage everything in the Developer Console.