Skip to main content
This guide walks you through embedding an invisible watermark into an image — from creating an order to downloading the watermarked result. Every endpoint here is plain HTTPS and JSON, so the same calls work from a server or straight from the browser. Each step includes a React tab, and a full copy-paste component is at the bottom of the page.

Prerequisites

  • A BIZ MORI API key (get one here)
  • An image or PDF file to watermark (jpeg, jpg, png, webp, tiff, bmp, or pdf)
Use the automatically issued sk_test_ key to exercise the order lifecycle without running watermark processing or consuming credits. Test uploads discard file contents and do not produce a downloadable result. Use a live API key when you need an actual watermarked file.

Step 1: Create an order

Create a watermark embed order with your watermark text.
Response:

Step 2: Upload files

PUT your file to the presigned uploadUrl from Step 1. This is a direct S3 upload — no Authorization header needed.
No confirm step needed. Unlike Anti-AI and AI Detection, Watermark Embed processing starts automatically after your file upload completes. Proceed directly to checking the order status.
Live keys receive S3 presigned URLs. Test keys receive https://api.bizmori.com/api/v2/test-uploads/{signedToken}; both expire after 1 hour and accept the same unauthenticated PUT. Test uploads are streamed only, not stored or processed. Use Refresh URLs if a URL expires.

Step 3: Check order status & download result

Poll the order or use webhooks to receive a push notification when processing completes.
Once status is complete, fetch the download URL:
Response:
The url is a presigned S3 URL valid for 7 days.

Full React example

Everything above, wired into one component: single-file upload with progress, a watermark text list with add/remove and duplicate detection, backoff polling, and a download link. No dependencies beyond React.
WatermarkEmbedUploader.jsx
import.meta.env.VITE_MORI_API_TOKEN is Vite’s syntax. Use process.env.NEXT_PUBLIC_MORI_API_TOKEN on Next.js, or whatever your bundler exposes to client code. crypto.randomUUID() needs a secure context: HTTPS and localhost are fine, a plain-HTTP LAN address is not.
Test orders do not produce a result file: their downloadUrl is null, and the download endpoint can return PROCESSED_FILE_NOT_FOUND.

Error handling

For the complete error code reference, see Error Codes.

Next steps

Anti-AI

Protect images from AI training and generation.

Watermark Extract

Detect and extract watermarks from images.

AI Detection

Detect AI-generated images with probability scores.

Webhooks

Set up webhooks to get notified when processing completes.