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
| Field | Type | Notes |
|---|---|---|
text | string | Supports {{email}}, {{date}}, {{time}}, {{link}}, {{ipAddress}} tokens. Interpolated per view. |
is_tiled | boolean | When true, tile across the page instead of anchoring at position. |
position | enum | top-left, top-center, top-right, middle-left, middle-center, middle-right, bottom-left, bottom-center, bottom-right. |
rotation | 0 | 30 | 45 | 90 | 180 | Degrees. |
color | string | Hex, #RGB or #RRGGBB. |
font_size | integer | 1–96. |
opacity | number | 0 (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.35Passing 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.7Drop the watermark config without disabling the toggle:
papermark links update link_abcd1234 --watermark-clearPOST /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:
| Token | Value 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.