API Reference

EraseWatermark API

Remove watermarks from images, PDFs, and videos via REST API. Authenticate with an API key and pay per request using your API credit balance.

Overview

Base URL

https://erasewatermark.io

Protocol

HTTPS only

Format

multipart/form-data

Authentication

Pass your API key as a Bearer token in the Authorization header of every request. API keys start with wm_. You can create and revoke keys in the API Keys dashboard.

bash
Authorization: Bearer wm_your_api_key_here
Keep your key secret. If compromised, revoke it immediately from the dashboard and create a new one.

Endpoints

All endpoints are under https://erasewatermark.io/api/v1/watermark.

Image — Auto

POST/api/v1/watermark/image

Remove watermark from an image. AI auto-detects the watermark.

Cost: 1 credit

Request body (multipart/form-data)

filerequiredfileImage file. Supported: JPG, PNG, WEBP, AVIF. Max 10 MB, 6000×6000 px.
bash
curl -X POST https://erasewatermark.io/api/v1/watermark/image \
  -H "Authorization: Bearer wm_your_key" \
  -F "[email protected]"

Image — Manual (brush mask)

POST/api/v1/watermark/image

Remove watermark guided by a brush mask you draw over the watermark area.

Cost: 1 credit

Request body (multipart/form-data)

filerequiredfileImage file (same formats as auto).
maskrequiredfileRGBA PNG mask at the same dimensions as the image. Drawn pixels must be (0,0,0,255) opaque black; undrawn pixels transparent (alpha=0).
mask_brushrequiredfileIdentical to mask — send the same PNG file for both fields.

Headers

x-api-moderequiredstringSet to "MANUAL" to activate brush-guided removal.
bash
curl -X POST https://erasewatermark.io/api/v1/watermark/image \
  -H "Authorization: Bearer wm_your_key" \
  -H "x-api-mode: MANUAL" \
  -F "[email protected]" \
  -F "[email protected]" \
  -F "[email protected]"

PDF

POST/api/v1/watermark/pdfasync

Remove watermarks from a PDF. Processing is asynchronous — poll task status.

Cost: 1 credit per page

Request body

filerequiredfilePDF file. Max 50 MB.

Video

POST/api/v1/watermark/videoasync

Remove watermarks from a video. Processing is asynchronous.

Cost: 1 credit

Request body

filerequiredfileVideo file. Supported: MP4, MOV, WEBM, AVI, MKV. Max 500 MB.

Task status

All three endpoints return a task_id. Poll this endpoint until status is completed or failed. Image jobs complete synchronously (no polling needed in most cases).

GET/api/v1/watermark/tasks/{task_id}

Poll processing status. Returns progress and download URL on completion.

Cost: free

Response fields

statusstring"pending" | "processing" | "completed" | "failed"
progressnumber0–100 percentage (video only).
download_urlstringPresent when status = completed. Relative path — prepend base URL.
file_idstringStable ID for the processed file.
errorstringError message when status = failed.
bash
curl https://erasewatermark.io/api/v1/watermark/tasks/abc123 \
  -H "Authorization: Bearer wm_your_key"

Download result

GET/api/v1/watermark/download/{file_id}

Stream the processed file. Add ?inline=true to serve inline instead of as attachment.

Cost: free
bash
curl -O -J https://erasewatermark.io/api/v1/watermark/download/abc123 \
  -H "Authorization: Bearer wm_your_key"

Credits & limits

OperationCredits consumed
Image (auto or manual)1
PDF1 per page
Video1
Task status poll0
Download0

Credits are deducted when processing begins. Credits for failed jobs are returned to your balance automatically.

Error codes

HTTP statusMeaning
200Success
400Bad request — invalid file, unsupported format, or missing field
401Unauthorized — missing or invalid API key
402Insufficient API credits
403Forbidden — you do not own this task
404Task or file not found
429Rate limited (anonymous users only)
500Internal server error — please retry

All error responses include a detail field with a human-readable message.

Code examples

Python

python
import requests, time

API_KEY = "wm_your_api_key"
BASE    = "https://erasewatermark.io"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# Remove watermark from an image (auto)
with open("photo.jpg", "rb") as f:
    r = requests.post(f"{BASE}/api/v1/watermark/image",
                      headers=HEADERS, files={"file": f})
r.raise_for_status()
task_id = r.json()["task_id"]

# Poll until done
while True:
    status = requests.get(f"{BASE}/api/v1/watermark/tasks/{task_id}",
                          headers=HEADERS).json()
    if status["status"] == "completed":
        break
    if status["status"] == "failed":
        raise Exception(status["error"])
    time.sleep(2)

# Download result
dl = requests.get(f"{BASE}{status['download_url']}", headers=HEADERS)
with open("result.jpg", "wb") as f:
    f.write(dl.content)
print("Done! Saved result.jpg")

Node.js

javascript
import fs from 'fs';
import FormData from 'form-data';
import fetch from 'node-fetch';

const API_KEY = 'wm_your_api_key';
const BASE    = 'https://erasewatermark.io';
const headers = { Authorization: `Bearer ${API_KEY}` };

// Submit image
const form = new FormData();
form.append('file', fs.createReadStream('photo.jpg'));
const { task_id } = await fetch(`${BASE}/api/v1/watermark/image`,
  { method: 'POST', headers: { ...headers, ...form.getHeaders() }, body: form }
).then(r => r.json());

// Poll
let status;
do {
  await new Promise(r => setTimeout(r, 2000));
  status = await fetch(`${BASE}/api/v1/watermark/tasks/${task_id}`,
    { headers }).then(r => r.json());
} while (!['completed','failed'].includes(status.status));

if (status.status === 'failed') throw new Error(status.error);

// Download
const buf = await fetch(`${BASE}${status.download_url}`, { headers })
  .then(r => r.arrayBuffer());
fs.writeFileSync('result.jpg', Buffer.from(buf));
console.log('Done!');