PapermarkDocs

Watermark every page with the viewer's details

Add a dynamic per-view watermark with email, date, and IP address so a screenshot of a leaked page identifies who leaked it.

Dynamic watermarks render the viewer's identity onto every page at view time — email, date, time, link, IP address — so a screenshot that leaks out of the deal carries the audit trail with it.

What's in a watermark config

FieldTypeNotes
textstringSupports {{email}}, {{date}}, {{time}}, {{link}}, {{ipAddress}} tokens. Interpolated per view.
is_tiledbooleanWhen true, tile across the page instead of anchoring at position.
positionenumtop-left, top-center, top-right, middle-left, middle-center, middle-right, bottom-left, bottom-center, bottom-right.
rotation0 | 30 | 45 | 90 | 180Degrees.
colorstringHex, #RGB or #RRGGBB.
font_sizeinteger1–96.
opacitynumber0 (invisible) to 1 (fully opaque).

The watermark renders only when enable_watermark is true. With enable_watermark: true and no config, the viewer falls back to sensible defaults (Confidential at middle-center, 45°, black, 24pt, 0.5 opacity).

Recipes

Create a link with a tiled watermark stamping every page with the viewer's email, the date, and the document URL:

papermark links create \
  --document doc_KlmN456 \
  --name "Acme — Q3 board pack" \
  --email-protected \
  --watermark-text "Confidential — {{email}} — {{date}} — {{link}}" \
  --watermark-tiled on \
  --watermark-position middle-center \
  --watermark-rotation 45 \
  --watermark-color "#9CA3AF" \
  --watermark-font-size 16 \
  --watermark-opacity 0.35

Passing any --watermark-* flag auto-enables the watermark; you do not need --watermark on top. All seven config flags must be passed together — the CLI validates the set before contacting the API.

Change just the text on an existing link (PATCH semantics — pass the full config to replace it):

papermark links update link_abcd1234 \
  --watermark-text "Internal preview — {{email}} — {{ipAddress}}" \
  --watermark-tiled off \
  --watermark-position bottom-right \
  --watermark-rotation 0 \
  --watermark-color "#DC2626" \
  --watermark-font-size 12 \
  --watermark-opacity 0.7

Drop the watermark config without disabling the toggle:

papermark links update link_abcd1234 --watermark-clear

POST /v1/links and PATCH /v1/links/{id} accept a structured watermark_config next to enable_watermark. On create, omit watermark_config to use viewer defaults. On update, pass null to clear an existing config.

curl -X POST https://api.papermark.com/v1/links \
  -H "Authorization: Bearer $PAPERMARK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "document_id": "doc_KlmN456",
    "name": "Acme — Q3 board pack",
    "email_protected": true,
    "enable_watermark": true,
    "watermark_config": {
      "text": "Confidential — {{email}} — {{date}} — {{link}}",
      "is_tiled": true,
      "position": "middle-center",
      "rotation": 45,
      "color": "#9CA3AF",
      "font_size": 16,
      "opacity": 0.35
    }
  }'
# Clear the watermark config without disabling the toggle:
curl -X PATCH https://api.papermark.com/v1/links/link_abcd1234 \
  -H "Authorization: Bearer $PAPERMARK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "watermark_config": null }'

The response always includes watermark_config (or null) so you can render the current settings back to the user.

Both the stdio and remote MCP servers expose enable_watermark and watermark_config on create_link and update_link. A typical prompt:

Find the latest Acme board pack, then create an email-gated link with a tiled watermark that shows the viewer's email and the date in light gray at 35% opacity.

The model can call search_documents to resolve the doc, then create_link with the full watermark_config object. On update it can pass watermark_config: null to clear an existing config without flipping enable_watermark.

Tokens

The text field is rendered literally except for these placeholders, which are substituted per view:

TokenValue at view time
{{email}}The viewer's email (requires email_protected).
{{date}}The view date in the team's locale.
{{time}}The view time in the team's locale.
{{link}}The link's public URL.
{{ipAddress}}The viewer's IP address.

Use {{email}} and {{ipAddress}} together to make leaks identifiable down to a single viewer.

Plan availability

enable_watermark: true requires a plan that includes the watermark feature. The API returns 403 forbidden_plan_feature on create/update when the team's plan does not cover it; existing links keep working after a downgrade and only re-trigger the gate when a request flips the toggle from off to on.

On this page