How to Integrate Dewatermark API into Your Website and App

Learn how to easily integrate the Dewatermark API into your website and app to remove image watermarks automatically using AI

How to Integrate Dewatermark API into Your Website and App

If your website or app handles images  whether uploaded by users, pulled from external sources, or stored in your database, you’ve likely run into watermarks. They make images look unprofessional, distract from content, and require manual effort to remove at scale.

Dewatermark API solves this programmatically. With a POST request, your backend sends an image and receives a watermark-free version in return. This guide covers everything you need: setup, authentication, working code examples in Python, Node.js, and cURL, and deployment tips for production.

What You Need Before You Start

Before integrating Dewatermark API, make sure you have the following in place.

An API Key from Dewatermark

Sign up at dewatermark.ai, log in, and navigate to Account → API Management to generate your API key. New accounts receive free credits to test the API before committing to a paid plan.

A Backend Environment

The Dewatermark API must be called from your backend — never from frontend JavaScript running in the browser. Any stack works: Node.js (Express), Python (Flask, Django, FastAPI), PHP (Laravel), or any language that supports HTTP POST requests.

Basic Understanding of REST APIs

Dewatermark API uses standard HTTP POST requests with multipart/form-data or JSON payloads depending on the method. If you can make HTTP requests and handle JSON responses, you have everything you need.

Dewatermark API Overview

Base URL and Endpoint

All image watermark removal requests go to the v2 endpoint:

POST https://platform.dewatermark.ai/api/object_removal/v2/erase_watermark

The v2 endpoint provides better results for high-resolution images. Each successful call costs 1 credit for standard removal (Auto Remove 3.0). Pro Remove 4.0 costs 3 credits per image.

Authentication

Include your API key in every request using the X-API-KEY header:

X-API-KEY: YOUR_API_KEY

Never expose your API key in frontend code. Always call the API from your backend server. Rotate your key regularly if you suspect misuse.

Supported Image Formats

JPG, JPEG, PNG. Maximum image dimension: 6000px on the longest side for the initial request. For manual refinement steps, the maximum is 1920px on the longest side. Recommended file size: under 10MB.

Request Format

Requests use multipart/form-data. The key parameters are:

Parameter Required Type Description
original_preview_image Required* Binary file The input image as a JPEG file. Required on the first call unless session_id is provided.
session_id Required* Text ID from a previous API call. Use instead of re-uploading the original image on refinement calls.
predict_mode Optional Text "3.0" (default, Auto Remove 3.0) or "old" (Auto Remove 2.0, best for emoji). Pro Remove 4.0 uses a separate model flag.
remove_text Optional Text Set to "true" to enable enhanced text watermark removal. Note: this may remove all text from the image.
mask_brush Optional Binary PNG A mask image identifying specific areas to remove in manual refinement mode.
mask_base Optional Text (base64) The mask of previously erased parts. Used in multi-step refinement workflows.

*Either original_preview_image or session_id must be provided. For initial calls, use original_preview_image. For subsequent refinement calls, use session_id to avoid re-uploading the original.

Response Format

A successful response returns a JSON object:

{
  "edited_image": {
    "image": "BASE64_ENCODED_IMAGE",
    "image_id": "image_id",
    "mask": "BASE64_MASK",
    "watermark_mask": "BASE64_MASK"
  },
  "event_id": "event_id",
  "session_id": "session_id"
}

The cleaned image is in edited_image.image as a base64-encoded string. The session_id is used for any subsequent manual refinement calls. The watermark_mask shows the areas that were detected and removed.

Credit Balance API

To check your remaining credits programmatically:

GET https://platform.dewatermark.ai/api/creditInfo
X-API-KEY: YOUR_API_KEY

Response: { "status": "OK", "data": { "available_credit": 1000, "user_id": "user_id" } }

Two Ways to Send Images to the API

Depending on where your images come from, you can integrate Dewatermark API using one of two approaches.

Option 1 — Upload Image File from User Device

Best for platforms where users upload images directly — photo editors, CMS platforms, e-commerce backends, dashboards.

Workflow:

  1. User uploads an image through a form or file input on your frontend.
  2. Your frontend sends the image file to your backend.
  3. Your backend sends a POST request to the Dewatermark API with the image as multipart/form-data.
  4. The API returns the cleaned image as base64 in the response JSON.
  5. Your backend decodes the base64 and returns the result to the frontend for display or storage.

Option 2 — Pass Image URL Directly

Best for automation scripts, content pipelines, admin tools, and workflows where images are already hosted externally.

Workflow:

  1. Collect the image URL from your database, user input, or external source.
  2. Send the URL to the API using image_url in the form data.
  3. Receive the cleaned image as base64 in the response.
  4. Decode and store or return the result as needed.
Feature Upload method Image URL method
Image source User-uploaded files Hosted or external images
Key parameter original_preview_image (binary) image_url (text)
File handling Required on backend Lightweight
Best for Forms, editors, uploads Scripts, pipelines, automation

Code Examples — Dewatermark API Integration

cURL — Quick Test via Terminal

Upload image file:

curl -X POST "https://platform.dewatermark.ai/api/object_removal/v2/erase_watermark" \
  -H "X-API-KEY: YOUR_API_KEY" \
  --form 'original_preview_image=@"image.jpg"' \
  --form 'predict_mode="3.0"'

Pass image URL:

curl -X POST "https://platform.dewatermark.ai/api/object_removal/v2/erase_watermark" \
  -H "X-API-KEY: YOUR_API_KEY" \
  --form 'image_url="https://example.com/sample.jpg"' \
  --form 'predict_mode="3.0"'

Enable text watermark removal:

curl -X POST "https://platform.dewatermark.ai/api/object_removal/v2/erase_watermark" \
  -H "X-API-KEY: YOUR_API_KEY" \
  --form 'original_preview_image=@"image.jpg"' \
  --form 'predict_mode="3.0"' \
  --form 'remove_text="true"'

Python (requests library)

Upload image file and save cleaned result:

import requests
import base64

API_KEY = "YOUR_API_KEY"
url = "https://platform.dewatermark.ai/api/object_removal/v2/erase_watermark"
headers = {"X-API-KEY": API_KEY}

# Send image file
with open("input.jpg", "rb") as image_file:
    files = {"original_preview_image": ("input.jpg", image_file)}
    data = {"predict_mode": "3.0"}
    response = requests.post(url, headers=headers, files=files, data=data)

result = response.json()

# Decode and save the cleaned image
image_data = base64.b64decode(result["edited_image"]["image"])
with open("output.jpg", "wb") as f:
    f.write(image_data)

# Save session_id for optional manual refinement
session_id = result["session_id"]
print(f"Done. Session ID: {session_id}")

Pass image URL instead of uploading a file:

import requests
import base64

API_KEY = "YOUR_API_KEY"
url = "https://platform.dewatermark.ai/api/object_removal/v2/erase_watermark"
headers = {"X-API-KEY": API_KEY}

data = {
    "image_url": "https://example.com/sample.jpg",
    "predict_mode": "3.0"
}

response = requests.post(url, headers=headers, data=data)
result = response.json()

image_data = base64.b64decode(result["edited_image"]["image"])
with open("output.jpg", "wb") as f:
    f.write(image_data)

Check credit balance:

import requests

API_KEY = "YOUR_API_KEY"
response = requests.get(
    "https://platform.dewatermark.ai/api/creditInfo",
    headers={"X-API-KEY": API_KEY}
)
data = response.json()
print(f"Available credits: {data['data']['available_credit']}")

Node.js (Express + Axios)

Backend route that accepts an image URL and calls Dewatermark API:

const express = require('express');
const axios = require('axios');
const FormData = require('form-data');

const app = express();
app.use(express.json());

app.post('/api/remove-watermark', async (req, res) => {
  const { imageUrl } = req.body;

  try {
    const formData = new FormData();
    formData.append('image_url', imageUrl);
    formData.append('predict_mode', '3.0');

    const apiRes = await axios.post(
      'https://platform.dewatermark.ai/api/object_removal/v2/erase_watermark',
      formData,
      {
        headers: {
          'X-API-KEY': process.env.DEWATERMARK_API_KEY,
          ...formData.getHeaders()
        }
      }
    );

    // Return base64 image or decode and save as needed
    const cleanedImageBase64 = apiRes.data.edited_image.image;
    res.json({
      success: true,
      image_base64: cleanedImageBase64,
      session_id: apiRes.data.session_id
    });

  } catch (error) {
    const status = error.response?.status || 500;
    res.status(status).json({ error: error.message });
  }
});

app.listen(3000, () => console.log('Server running on port 3000'));

Backend route that accepts a file upload from the frontend:

const express = require('express');
const axios = require('axios');
const FormData = require('form-data');
const multer = require('multer');

const app = express();
const upload = multer({ storage: multer.memoryStorage() });

app.post('/api/remove-watermark-upload', upload.single('image'), async (req, res) => {
  try {
    const formData = new FormData();
    formData.append(
      'original_preview_image',
      req.file.buffer,
      { filename: req.file.originalname, contentType: req.file.mimetype }
    );
    formData.append('predict_mode', '3.0');

    const apiRes = await axios.post(
      'https://platform.dewatermark.ai/api/object_removal/v2/erase_watermark',
      formData,
      {
        headers: {
          'X-API-KEY': process.env.DEWATERMARK_API_KEY,
          ...formData.getHeaders()
        }
      }
    );

    res.json({
      success: true,
      image_base64: apiRes.data.edited_image.image,
      session_id: apiRes.data.session_id
    });

  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

React (Frontend calling your backend)

The React frontend never calls Dewatermark API directly — it calls your own backend, which holds the API key securely.

// Frontend sends image URL to YOUR backend, not directly to Dewatermark
const removeWatermark = async (imageUrl) => {
  const res = await fetch('/api/remove-watermark', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ imageUrl })
  });

  const data = await res.json();

  if (data.success) {
    // Display cleaned image from base64
    const imgSrc = `data:image/jpeg;base64,${data.image_base64}`;
    document.getElementById('result').src = imgSrc;
  }
};

Manual Refinement — Using session_id

If the initial API call leaves residue, you can refine the result using the session_id from the first response, combined with a mask_brush PNG that marks the remaining watermark areas.

import requests
import base64

API_KEY = "YOUR_API_KEY"
url = "https://platform.dewatermark.ai/api/object_removal/v2/erase_watermark"
headers = {"X-API-KEY": API_KEY}

# Use session_id from the initial call — no need to re-upload the original image
# mask_brush is a PNG file with white pixels marking areas to remove
with open("mask_brush_step2.png", "rb") as mask_file:
    files = {"mask_brush": ("mask_brush.png", mask_file)}
    data = {
        "session_id": "SESSION_ID_FROM_PREVIOUS_CALL",
        "mask_base": "BASE64_MASK_FROM_PREVIOUS_RESPONSE"
    }
    response = requests.post(url, headers=headers, files=files, data=data)

result = response.json()
image_data = base64.b64decode(result["edited_image"]["image"])
with open("output_refined.jpg", "wb") as f:
    f.write(image_data)

Video Watermark Removal API

Dewatermark API includes a separate video watermark removal workflow. Video processing uses a four-step asynchronous approach: generate upload URL, upload the video, submit the task, then poll for completion.

Video requirements: MP4 format, 24fps, maximum 9 minutes duration.
Pricing: 0.2 credits per second (1 credit = 5 seconds of video). Failed tasks receive a full credit refund.

Step 1 — Generate Upload URL

import requests

headers = {"X-API-KEY": "YOUR_API_KEY", "Content-Type": "multipart/form-data"}
response = requests.post(
    "https://platform.dewatermark.ai/api/video/v1/upload",
    headers=headers
)
data = response.json()
task_id = data["task_id"]
upload_signed_url = data["upload_signed_url"]

Step 2 — Upload Video File

# Upload via HTTP PUT to the signed URL — no API key needed here
with open("input_video.mp4", "rb") as video_file:
    upload_response = requests.put(
        upload_signed_url,
        data=video_file,
        headers={"Content-Type": "application/octet-stream"}
    )
# Wait for 200 status before proceeding to Step 3

Step 3 — Submit Task

submit_response = requests.post(
    "https://platform.dewatermark.ai/api/video/v1/tasks",
    headers={"X-API-KEY": "YOUR_API_KEY"},
    data={"task_id": task_id}
)

Step 4 — Poll for Completion and Download

import time

status_url = f"https://platform.dewatermark.ai/api/video/v1/tasks/{task_id}"

while True:
    response = requests.get(status_url, headers={"X-API-KEY": "YOUR_API_KEY"})
    task_data = response.json()
    status = task_data["status"]
    progress = task_data.get("progress", 0)
    print(f"Status: {status}, Progress: {int(progress * 100)}%")

    if status == "COMPLETED":
        download_url = task_data["download_signed_url"]
        duration = task_data["duration"]
        credits_used = duration * 0.2
        print(f"Done. Duration: {duration}s. Credits used: {credits_used}")

        video_data = requests.get(download_url).content
        with open("output_video.mp4", "wb") as f:
            f.write(video_data)
        break

    elif status == "FAILED":
        print("Failed. Credits will be refunded.")
        break

    time.sleep(5)

Task status values: CREATED → PROCESSING → COMPLETED or FAILED. The download_signed_url is valid for 2 days after completion.

Error Handling

Handle these error codes in your integration to ensure stable production behaviour.

Error code Meaning Fix
400 Bad Request — request is invalid Check that original_preview_image or session_id is provided, and that the image format is JPG or PNG
401 Unauthorized — API key is wrong or missing Verify the X-API-KEY header is set correctly with your valid key
500 Internal Server Error — server issue or invalid input Retry after a short delay; if persistent, contact Dewatermark support
503 Service Unavailable — temporary maintenance Retry with exponential backoff

Node.js error handling example:

try {
  const res = await axios.post(apiUrl, formData, { headers });
  return res.data;
} catch (err) {
  const status = err.response?.status;
  if (status === 401) {
    console.error("Invalid API key — check X-API-KEY header.");
  } else if (status === 400) {
    console.error("Bad request — verify image format and required parameters.");
  } else if (status === 503) {
    console.error("Service unavailable — retry with backoff.");
  } else {
    console.error("Unexpected error:", err.message);
  }
}

Best Practices for Production Integration

Never Expose Your API Key in Frontend Code

Always call Dewatermark API from your backend server. Store your key in environment variables — .env files locally, or a secrets manager like AWS Secrets Manager or Vercel Environment Variables in production. Never hardcode it in your codebase.

Validate Image Input Before Sending

Check format (JPG, PNG only), file size (under 10MB), and image dimensions (under 6000px on longest side) before making the API call. Reject invalid inputs early to avoid wasting credits on failed requests.

Use session_id for Multi-Step Refinement

If the initial removal leaves residue, use the session_id from the first response for follow-up calls with a mask_brush. This avoids re-uploading the original image and reduces data transfer.

Start with predict_mode=”3.0″ — Switch When Needed

predict_mode="3.0" handles most watermark types correctly. Switch to "old" (Auto Remove 2.0) only for emoji-heavy images. Use Pro Remove 4.0 for stickers, beauty filters, and complex doodles where 3.0 leaves residue.

Implement Retry Logic with Exponential Backoff

For high-volume batch processing, implement automatic retry on 500 and 503 errors with increasing delay between attempts. This prevents cascading failures and handles transient server issues gracefully.

Use Async Job Queues for Bulk Processing

For large image volumes, use a queue system — Bull (Node.js), Celery (Python), or Laravel Queues (PHP) — to process images asynchronously without blocking HTTP requests or hitting timeouts.

Log Every Request

Log request timestamps, status codes, session_ids, and credit usage per call. This helps debug issues, track costs, and identify images that need manual review.

Monitor Credit Balance

Call GET /api/creditInfo regularly in your pipeline to track remaining credits. Set up alerts before credits run out to avoid interruptions in production workflows.

Testing Checklist Before Deployment

  • ✅ Test with multiple image types — different watermark styles, sizes, backgrounds, and opacity levels
  • ✅ Test both original_preview_image (file upload) and image_url methods
  • ✅ Test remove_text="true" on text-only watermarks
  • ✅ Test manual refinement flow using session_id and mask_brush
  • ✅ Simulate error conditions: invalid API key (401), bad image format (400), missing parameters
  • ✅ Verify base64 decoding of edited_image.image renders correctly
  • ✅ Confirm API key is loaded from environment variables, not hardcoded
  • ✅ Test credit balance check endpoint: GET /api/creditInfo
  • ✅ Test video workflow end-to-end: generate URL → upload → submit → poll → download
  • ✅ Verify retry logic handles 500 and 503 responses correctly

Ready to Integrate?

Dewatermark API is available now. New accounts receive free credits for testing — no payment required to start.