Scrub a file
Removes metadata from a PNG or JPEG and returns the rewritten file.
/api/v1/scrubRequest
Content type must be multipart/form-data. Maximum body size is 25 MB; larger uploads are rejected before being read into memory.
Modes
mode=all — strips EXIF, IPTC, XMP, PNG text chunks and C2PA manifests. Use this when publishing anywhere you do not control.
mode=ai — strips C2PA manifests, generator tags and SynthID-style markers, but preserves camera EXIF. Use this when provenance must go but shot data is worth keeping.selective is accepted as an alias.
Response
On success the body is the cleaned file bytes — not JSON. The report is in the headers. Every failure, by contrast, returns JSON, so branch on the response content type rather than assuming.
HTTP/1.1 200 OKContent-Type: image/pngContent-Disposition: attachment; filename="photo_scrubbed.png"Cache-Control: no-storeX-PurifyAI-Tags-Removed: 4X-PurifyAI-Format: pngX-PurifyAI-Bytes-Saved: 18244X-PurifyAI-Usage-Count: 12X-RateLimit-Remaining: 118<binary image data>
Content-Disposition is built from your upload filename with everything outside A–Z a–z 0–9 . _ - replaced. An uploaded name is attacker-controlled, and a newline or quote in a response header is header injection.Status codes
200OKX-PurifyAI-Tags-Removed for what changed.400bad_requestfile field was absent.401unauthorized403plan413payload_too_large415unsupported_formatformat and the tagsFound count, so you can still report what was in the file.429rate_limitedRetry-After; see Rate limits.503not_configuredDiscovery
A GET on the same path returns a small JSON description of the endpoint and needs no key — handy for confirming a deployment is wired up.
{"endpoint": "/api/v1/scrub","method": "POST","auth": "Authorization: Bearer pk_live_…","body": "multipart/form-data field \"file\"","maxFileSize": "25MB","modes": ["all", "ai"],"docs": "/docs"}