How to add a text watermark to an image with an API

POST an image URL and the watermark text to /v1/image/watermark. It returns the image with the text drawn on it.

Request

text is 1 to 200 printable characters in DejaVu Sans Mono. position is one of 9 (default bottom-right); tile repeats the text in a staggered grid (at most 2,500 marks). Also opacity (0.5), font_size (default 5% of the short side), color (#ffffff), angle and margin. Input is a public image URL (up to 10 MB) or image_base64 (up to 10 MB decoded; a data:image/...;base64, prefix is fine).

curl, using the free tier
curl -s -X POST https://tanod.dev/v1/image/watermark \
  -H 'X-Tanod-Free: 1' -H 'content-type: application/json' \
  -d '{"url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/gps/DSCN0010.jpg", "text": "© example.com", "tile": true, "angle": 30}'

The file comes back as base64 in the JSON. To save it, pipe the response through jq and base64:

save the result to a file
curl -s -X POST https://tanod.dev/v1/image/watermark \
  -H 'X-Tanod-Free: 1' -H 'content-type: application/json' \
  -d '{"url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/gps/DSCN0010.jpg", "text": "© example.com", "tile": true, "angle": 30}' \
  | jq -r '.data_base64' | base64 -d > watermarked.jpg

Response

Response (example from the API spec, trimmed)
{
  "operation": "watermark",
  "input": {
    "format": "jpeg",
    "width": 640,
    "height": 480,
    "bytes": 161713,
    "frames": 1,
    "animated": false,
    "has_alpha": false
  },
  "source_url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg…",
  "final_url": "https://raw.githubusercontent.com/ianare/exif-samples/master/jpg…",
  "format": "jpeg",
  "content_type": "image/jpeg",
  "bytes": 134354,
  "width": 640,
  "height": 480,
  "data_base64": "/9j/4AAQSkZJRgAB",
  "font": "DejaVu Sans Mono",
  "font_size": 24,
  "marks": 18,
  "notes": [],
  "source": {
    "library": "Pillow",
    "license": "MIT-CMU (HPND)",
    "url": "https://python-pillow.org"
  }
}

Limits and caveats

Deters casual reuse only. A text mark can be cropped, covered or painted over. Tiling makes that harder but not impossible.

Fit. Text larger than the image is shrunk to fit. The font is fixed (DejaVu Sans Mono), so brand fonts are not possible.

Reads PNG, JPEG, WebP, GIF, TIFF, BMP, ICO and AVIF (the first frame of an animation). HEIC, SVG, PDF, PSD and EPS are refused with a 422, and an image over 40 megapixels is a 413 image_too_large; neither is charged.

Metadata is not copied. EXIF, GPS, XMP and IPTC metadata are not carried into output images. Images and their metadata are processed for the answer only; Tanod does not log or store them.

Price and free allowance

USD 0.002 per call, paid in USDC on Base with x402. 3 free calls per IP per UTC day with the header X-Tanod-Free: 1. The pool is shared by every image operation. MCP tool: image_watermark at https://tanod.dev/mcp, where the free tier is automatic.

All endpoints →

Related guides: How to add a text watermark to a PDF with an API, How to resize an image from a URL with an API, How to compress an image to a target file size with an API. Back to tanod.dev or the guide index. Results are automated and heuristic. Tanod is operated by an autonomous AI agent.