NAV
cURL Python

Quick Start

Welcome to the Imatag documentation ! This page will give you an introduction to 80% of the Imatag platform, enabling you to seamlessly integrate our API and efficiently watermark your files.

You will discover:
- How to authenticate with our system
- How to watermark a file
- How to register a watermarked file
- How to search a watermarked file

Authentication - OAuth2

OAuth 2.0 is an authorization protocol that allows an application (client) to access a user's resources hosted on a server without sharing their login credentials. It operates by granting access tokens that provide precise control over permissions and the duration of access.

How it works ?

Understanding OAuth 2.0: A Step-by-Step Diagram: OAuth2 architecture

Why use OAuth2 ?

Advantage Description
Granular access control If a client has multiple applications with different purposes, you can grant or revoke access per app individually without affecting the others.
Temporary access for third parties You can give a contractor or external partner limited-time access, and easily revoke it once they’re no longer involved.
Better security than permanent tokens OAuth2 uses short-lived access tokens and refresh tokens, reducing the risk in case a token is compromised.

How to use OAuth2 ?

Now that we have a solid understanding of OAuth2 and its advantages, let's dive into the practical side and implement it step-by-step.

Step 1 : Obtain client information

Create an application to get your client_id and client_secret.

On the platform UI, go to Account Settings by clicking on the ⚙️ icon.
There, you’ll find a "Create OAuth Application" button.
Clicking it will generate your Client ID and Client Secret.

Step 2 : Obtain an Access Token

Use your client_id and client_secret to request a token

Get access token

import base64
import requests

client_id = "your_client_id"
client_secret = "your_client_secret"
credentials = f"{client_id}:{client_secret}"
encoded_credentials = base64.b64encode(credentials.encode("utf-8")).decode("utf-8")
headers = {
    "Content-Type": "application/x-www-form-urlencoded",
    "Authorization": f"Basic {encoded_credentials}"
}
url = "https://imatag.com/o/token/"

response = requests.post(url, headers=headers, params={"grant_type": "client_credentials"})
curl -X POST "https://imatag.com/o/token/" \
    -H "Authorization: Basic your_encoded_credentials" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "grant_type=client_credentials"

You'll get a response like this :

{
  "access_token": "your_token",
  "expires_in": 3600,
  "token_type": "Bearer",
  "scope": "openid"
}

To get a token you need to encode client_id and client_secret separated by a colon as HTTP base authentication encoded in base64.

HTTP Request

POSThttps://imatag.com/o/token/

Request content

Attribute Required Value
grant_type True client_credentials

Response description

Attribute Description
access_token Your access token
expires_in Time of validity in seconds
token_type The type of token
scope The scope of the access token

Step 3: Use the token to access resources

The access token should be used as follows:

import requests

headers = {"Authorization": "Bearer your_access_token"}
response = requests.get("https://imatag.com/api/v4/account/", headers=headers)
curl "https://imatag.com/api/v4/account/" \
  -H "Authorization: Bearer your_access_token"

The above command returns a JSON response with various details about your account.
For now, here’s a glimpse of the most relevant part

{
    ...
    "home": "api-demo",
    ...
}

Now that you have your access_token, you need to use it as your credential. To do so, simply use it as a Bearer token.
For example, you can retrieve your user home directory. it's helpful you may use it after, so good to know. to view more details about your account check your account details here.

HTTP Request

GEThttps://imatag.com/api/v4/account/

Response description

Attribute Description
home The home directory of the user

Watermarking Workflow

After completing the authentication step through OAuth 2.0, you can easily watermark your files by following the process outlined below. This step-by-step guide will help you apply this functionality efficiently.

Workflow watermark

Watermarking a file

Watermarking an image by URL

import requests

headers = {
    "Authorization": "Token <your api token>",
}
data = {
    "url": "https://imatag.com/api/doc/images/tour-eiffel.jpeg",
    "sync": True, # False (default true)
    "timeout" : 120 # number of seconds (default 120)
}
response = requests.post("https://imatag.com/api/v4/watermarking/",
                         json=data, headers=headers)    
curl -X POST \
  https://imatag.com/api/v4/watermarking/ \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/json" \
  --data '{"url": "https://imatag.com/api/doc/images/tour-eiffel.jpeg", "sync": true}'

The above command returns JSON structured like this:

{
    "expiry": "2018-12-06T17:26:22Z",
    "original": "http://static1.imatag.com/208141,240d162ab9716c41",
    "watermarked": "http://static2.imatag.com/208141,240d164028af21c7",
    "registration": "http://static4.imatag.com/208145,240d163d6fdc2249"
}

HTTP Request

POSThttps://imatag.com/api/v4/watermarking/

Request content

The content of the request must be either:

Attribute Required Description
url true The URL of the asset "http://..."`
sync false The sync call of the api (true or false, default = true)
timeout false The timeout call of the api

Response description

The response indicates where to download the generated assets and their expiration.

Attribute Description
original The URL of the original full-size image
watermarked The URL of the watermarked full-size image
expiry Expiration date of the watermarked assets on our servers (approximate)
registration The URL of the registration data that should be sent on the media endpoint

Register a watermarked file

HTTP Request

This endpoint registers a previously watermarked file using the registration (LMK) file generated by the previous endpoint watermarking endpoint. It also allows to add metadata to the media.

First example with the lmk file
You can download this watermark file to run the example.

import requests

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/lmk",
}
lmk = open("./registration.lmk", "rb").read()
response = requests.put("https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
                        data=lmk, headers=headers)

curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/lmk" \
  --data-binary @- < ./registration.lmk

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
    "path": "api.demo/uploads/2018/my-image.jpg",
    "created": "2019-01-02T15:09:17.145580Z",
    "disk_usage": 97358,
    "type": "image",
    "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad",
    "metadata": {},
    "image": {
        "type": "registered",
        "url": "https://static4.imatag.com/20985,28c25e65d3e1baad",
        "width": 800,
        "height": 500,
        "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad"
    }
}

Second example with the JSON file

import requests
import json

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/json",
}
data = {
    "url": "https://static3.imatag.com/49785,25dcc2978a4b5bad",
    "metadata": {
        "user.isDemo": "True",
        "user.campaign": "Visit Paris 2020"
    }
}
response = requests.put("https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
                        data=json.dumps(data), headers=headers)

curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://static3.imatag.com/49785,25dcc2978a4b5bad", "metadata": { "user.isDemo": "True", "user.campaign": "Visit Paris 2020"}}'

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
    "path": "api.demo/uploads/2018/my-image.jpg",
    "created": "2019-01-02T15:09:17.145580Z",
    "disk_usage": 97358,
    "type": "image",
    "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad",
    "metadata": {
        "user.isDemo": "True",
        "user.campaign": "Visit Paris 2020"
    },
    "image": {
        "type": "registered",
        "url": "https://static4.imatag.com/20985,28c25e65d3e1baad",
        "width": 800,
        "height": 500,
        "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad"
    }
}

An additional example data-URI example is given in the Uploads section

PUThttps://imatag.com/api/v4/media/<homedir>/<path>/<filename>

URL Parameters

Parameter Required Description
homedir true The home directory where to upload the media. This is generally your own username or another client folder for which you're granted permission (e.g. jdoe)
path false The optional subfolder path, within your home directory, where to store the media (e.g. images/2018)
filename true The file name & extension of the image to register. It will be its name on our servers & in your account.

Request content

The content of the request must be either:

Attribute Required Description
url true URL of the lmk file, for example the one provided by the watermarking endpoint.
metadata false A metadata object

Response description

If the request is successful, the response is the newly created Media object

Search a watermarked file

Now that our file has been watermarked and registered, we can perform a search on it.

Search with a binary file, by direct upload. (See example)
You can download the registered tour-eiffel.jpeg file from the media example to run the example.

import requests

headers = {
    "Authorization": "Token <your api token>"
}
files = {'file': open('tour-eiffel.jpeg', 'rb')}
response = requests.post("https://imatag.com/api/v4/searches/",
                        files=files, headers=headers)

curl -X POST \
  https://imatag.com/api/v4/searches/ \
  -H "Authorization: Token <your api token>" \
  -F "file=@tour-eiffel.jpeg"

The above commands returns JSON structured like this:

{
    "status": "complete",
    "matches": [
        {
            "id": null,
            "created": "2019-11-18T16:40:11.133727Z",
            "type": "user",
            "watermarked": true,
            "image": {
                "type": "registered",
                "url": "https://static4.imatag.com/54578,15ec5ca69f80719a",
                "width": 1280,
                "height": 1706,
                "thumbnail": "https://static4.imatag.com/211701,81c386bd3eb68eba",
                "credit": null,
                "media_path": "/api.demo/images/paris/tour-eiffel.jpeg",
                "media_url": "https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg"
            }
        }
    ]
}

Search with a remote image, by providing its public URL. (See example)
alternatively you can perform a request by url

import requests
import json

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/json",
}
data = {'file': 'https://imatag.com/api/doc/images/tour-eiffel.jpeg'}
response = requests.post("https://imatag.com/api/v4/searches/",
                        data=json.dumps(data), headers=headers)

curl -X POST \
  https://imatag.com/api/v4/searches/ \
  -H "Authorization: Token <your api token>" \
  -F "file=https://imatag.com/api/doc/images/tour-eiffel.jpeg"

The above commands returns JSON structured like this:

{
    "status": "complete",
    "matches": [
        {
            "id": null,
            "created": "2019-11-18T16:39:02.263262Z",
            "type": "user",
            "watermarked": true,
            "image": {
                "type": "registered",
                "url": "https://static1.imatag.com/54578,15ec5ca69f80719a",
                "width": 1280,
                "height": 1706,
                "thumbnail": "https://static3.imatag.com/211701,81c386bd3eb68eba",
                "credit": null,
                "media_path": "/api.demo/images/paris/tour-eiffel.jpeg",
                "media_url": "https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg"
            }
        }
    ]
}

You can perform a text search

import requests
import json

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/json",
}
data = {
    "metadata": {
        "user.subject": "Eiffel Tower"   
    },
    "filename" : "tour-eiffel.jpeg",
    "type": "image"
}
response = requests.post("https://imatag.com/api/v4/searches/",
                        data=json.dumps(data), headers=headers)

The above commands returns JSON structured like this:

{
    "status": "complete",
    "matches": [
        {
            "id": null,
            "created": "2020-10-23T13:41:21.743541Z",
            "type": "text",
            "query": {
                "filename": "tour-eiffel.jpeg",
                "type": [
                    "image"
                ],
                "sync": true,
                "metadata": {
                    "user.subject": "Eiffel Tower"
                }
            },
            "media": {
                "metadata": {
                    "user.subject": "Eiffel Tower",
                    "user.campaign": "Paris by night"
                },
                "media_path": "api.demo/images/paris/tour-eiffel.jpeg",
                "media_url": "https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg"
            }
        }
    ]
}

HTTP Request

POSThttps://imatag.com/api/v4/searches/

Request content

For a search by image, the following parameters are available

Parameter Default Description
file null Query file (image or document) if the request is multipart/form-data, or the URL of the query image or document (Data URIs are supported)
name null If set, name for the search. If unset, the filename of the uploaded "file" will be used.
sync Run the search in synchronous mode if set; default is true for images, false otherwise; synchronous searches are allowed only on images
search_path <homedir> Restrict the search to a specific media path (<homedir>/<path>). Ignored for category web.
mode "near_duplicate" Can be near_duplicate to attempt to find the original image(s) the query is derived from or vice-versa, if the matched original is watermarked, detection will be performed. Alternatively can be set to similar to do a faster search in order to find visually similar images which are not necessarily derived from one another or 'leaks'.
categories ["default"] A list to where to search; for image search only; authorized users only. The default may be changed to one of recent (recent images, faster), archive (all images, slower).
transforms ["scale"] Geometric transform validation model for images; default is scale (crop/resize no rotation), other allowed values are affine (crop/resize/rotation) or perspective. If mode=leaks, default is ["scale", "perspective"].
filter_marked false If set, filter the results to only show watermarked results (true) or non-watermarked (false)

For a search by text, the following parameters are available

Parameter Default Description
metadata null Dict that represent metadata to search
type null String to search only specific media type ("image", "video", "folder")
filename null String that represent the exact filename to search (case sensitive)
filename__startswith null String that represent the begining of the filename to search (case sensitive). Minimum length required = 3
sync true Run the search in synchronous mode if set

Response content

The response is one of the following, depending on the sync query parameter:


API Endpoints

Below is the list of all available endpoints & their full description: this is API (ツ) time!

Account

Account information

This endpoint allows you to check your account information and status.

import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.get(
    "https://imatag.com/api/v4/account/",
    headers=headers)
curl -X GET \
  https://imatag.com/api/v4/account/ \
  -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

{
    "username": "api.demo",
    "email": "support@imatag.com",
    "full_name": "api demo",
    "incidents": null,
    "image_count": 9,
    "image_quota": 50,
    "disk_quota": 13030726,
    "disk_usage": 2544966,
    "home": "api-demo", 
    "permissions":[],
    "quotas": {
        "uploaded_marks": 7,
        "uploaded_marks_limit": 50,
        "uploaded_images": 9,
        "uploaded_images_limit": 100,
        "active_paths_in_home": 12,
        "active_paths_in_home_limit": null,
        "paths_in_home": 12,
        "paths_in_home_limit": null,
        "user_paths": 12,
        "user_paths_limit": null
    }
}

HTTP Request

GEThttps://imatag.com/api/v4/account/

Response description

Attribute Description
username Name of the account (cannot be modified)
full_name Company name or first name & last name
email The email address used for login & contact
incidents Current incidents on the account (null if none). See below for incidents description.
image_count Current number of images owned by the user
image_quota Maximum number of images based (null if no maximum)
disk_usage Current disk usage of the user (in bytes)
disk_quota Maximum disk usage (null if no maximum)
expires Only in case of certain incidents, the date at which the account will be deleted
home The home directory of the user
quota Detailed quota
permissions List of allowed permissions for the current account

incidents

Description of the incidents

Value Description
null No incident
free trial expired The user subscribed to a free trial and it has expired ("expires" will be set)
payment overdue The last payment of the user has not come through ("expires" will be set)
quota exceeded The current number of images owned by the user exceeds their quota or their disk usage exceed their disk quota

Account settings

This endpoint allows you to check your account settings.

import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.get(
    "https://imatag.com/api/v4/account/settings/",
    headers=headers)
curl -X GET \
  https://imatag.com/api/v4/account/settings/ \
  -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

{
    "lang": "en",
    "notifications": {
        "notify_upload": true,
        "notify_pdf": false,
        "notify_web": false,
        "notify_download": false,
        "notify_favorite": false,
        "notify_newsletter": true,
        "notify_offers": false,
        "notify_pdf_daily": false,
        "notify_pdf_weekly": false,
        "notify_match_url_daily": false,
        "notify_match_url_weekly": false,
        "notify_match_site_daily": false,
        "notify_match_site_weekly": false
    },
    "notif_site_countries": [
        "fr"
    ]
}

HTTP Request

GET|POSThttps://imatag.com/api/v4/account/settings/

Response description

Attribute Description
lang Language (fr, en)
notifications Dictionary of key:value
notif_site_countries List of countries for which the website matches notifications will be sent. Countries must be specified as ISO 3166-1 alpha-2 codes (ie 2-letter codes; cf https://fr.wikipedia.org/wiki/ISO_3166-1_alpha-2)

Download software and key

There is an endpoint that allows you to list the latest software version's binaries available.

import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.get(
    "https://imatag.com/api/v4/account/download/",
    headers=headers)
curl -X GET \
  https://imatag.com/api/v4/account/download/ \
  -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:


{
    "version": "X.Y.Z",
    "key": {
        "public_key.der": "/api/v4/account/download/key/"
    },
    "software": {
        "lamark": "/api/v4/account/download/software/X.Y.Z/lamark",
        "lamark.exe": "/api/v4/account/download/software/X.Y.Z/lamark.exe"
    }
}

HTTP Request

GEThttps://imatag.com/api/v4/account/download/

Response description

Attribute Description
version The name of the current version
key A dict of each key you can have
key.<name> The url to call (GET) to get your encryption key (ie: public_key.der)
software A dict where each key represent a software available
software.<name> The url to call (GET) to download this specific software

Domains

Domain object

The representation of a domain is fairly simple

Attribute Description
url Domain name with extension (eg imatag.com); protocol is not necessary.

Domains blacklist

This endpoint /api/v4/domains/blacklist/ allows to manage a blacklist of web domains.

Matches recorded on blacklisted domains will be ignored (filtered out).

Add a domain to the blacklist

Add a domain to the blacklist:

import requests

headers = {
    "Authorization": "Token <your api token>",
}
data = {
    "url": "imatag.com"
}
response = requests.post(
    "https://imatag.com/api/v4/domains/blacklist/",
    json=data, headers=headers)

curl -X POST \
https://imatag.com/api/v4/domains/blacklist/ \
-H "Authorization: Token <your api token>" \
-H "Content-Type: application/json" \
--data '{"url": "imatag.com"}'

This endpoint allows to add a new domain to the blacklist

HTTP Request

POSThttps://imatag.com/api/v4/domains/blacklist/

Request content

The content of the request must be a valid domain description:

Attribute Required Description
url true Domain name with extension

Response description

If the request is successful, the response is the newly blacklisted domain

Get all domains from the blacklist

Get all domains from the blacklist:

import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.get(
    "https://imatag.com/api/v4/domains/blacklist/",
    headers=headers)
curl -X GET \
https://imatag.com/api/v4/domains/blacklist/ \
-H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

{
    "next": null,
    "previous": null,
    "results": [
        {
            "url": "imatag.com"
        }
    ]
}

This endpoint allows to retrieve all domains that are registered in the blacklist

HTTP Request

GEThttps://imatag.com/api/v4/domains/blacklist/

Response description

Attribute Description
next Not used yet; pagination is not enabled on this endpoint
previous Not used yet; pagination is not enabled on this endpoint
results List of blacklisted domain objects

Removes a domain from the blacklist

Removes a domain from the blacklist:

import json
import requests

headers = {
    "Authorization": "Token <your api token>",
    'Content-Type': 'application/json',
}
data = {
    "url": "imatag.com"
}
response = requests.delete(
    "https://imatag.com/api/v4/domains/blacklist/",
    data=json.dumps(data), headers=headers)
curl -X DELETE \
https://imatag.com/api/v4/domains/blacklist/ \
-H "Authorization: Token <your api token>" \
-H "Content-Type: application/json" \
--data '{"url": "imatag.com"}'

This endpoint allows to remove a domain from the blacklist

HTTP Request

DELETEhttps://imatag.com/api/v4/domains/blacklist/

Request content

The content of the request must be a valid domain description:

Attribute Required Description
url true Domain name with extension

Matches

This endpoint lists all web matches found (similar and watermarked) on the Internet by our crawlers.

Get all web matches

Use this endpoint to retrieve the list of web matches.

import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.get("https://imatag.com/api/v4/matches/", headers=headers)

curl 'https://imatag.com/api/v4/matches/' \
 -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

{
  "count": 1126515812,
  "next": "https://internal.imatag.com/api/v4/matches/?cursor=cD0xNzQzNjg0NTg5OTc2JmM9MTEyNjUxNTgxMg%3D%3D",
  "previous": null,
  "results": [
    {
      "id": "-1309647177151738849",
      "date_created": "2025-04-03T12:49:55.313776Z",
      "date_updated": "2025-04-03T12:49:55.313776Z",
      "export": true,
      "watermarked": false,
      "tags": [],
      "sessions": [
        5
      ],
      "media": {
        "id": -5249833301997058969,
        "type": "image",
        "thumbnail": "https://static6.imatag.com/304162,01e32371b0c3de16d9",
        "image": "https://static6.imatag.com/304162,01e32371b0c3de16d9",
        "path": "maxppp/agencesonline/11718303.jpg.jpg",
        "date_registered": "2024-11-13T13:56:44.375258Z",
        "credit": "EPA/MAXPPP",
        "user_metadata": {
          "reference": "11718303"
        }
      },
      "site": {
        "id": -315702766390685278,
        "name": "fbcnews.com.fj",
        "domain": "fbcnews",
        "suffix": "com.fj",
        "country": "fj"
      },
      "page": {
        "url": "https://www.fbcnews.com.fj/entertainment/vicky-kaushal-starrer-the-great-indian-family-certified-ua-advance-booking-begins/",
        "type": "web",
        "image": {
          "url": "https://www.fbcnews.com.fj/wp-content/uploads/2024/11/world-8-640x360.jpg"
        }
      }
    },
    ...
  ]
}

HTTP Request

GEThttps://imatag.com/api/v4/matches/

What's in a Match?

Each match object contains metadata grouped in three sections:

Match Fields Breakdown

Field Description
watermarked Whether watermark was detected (true/false)
sessions Related crawling session ID(s)
tags Optional tags you’ve applied
export Whether the result is exportable
date_created Date of match creation
payload Payload used for the watermark (payload mode only)

Nested objects:

Field Description
id Unique media id
type Type of media: image, video, or other
thumbnail URL of the thumbnail preview of the media
image URL of the original image
path File path or location where the media is stored
date_registered Date of registration
user_metadata.reference Metadata pushed to the path
Field Description
domain Main domain of the website (e.g., example.com)
name Name of the website
country Country of the site where the image was detected
Field Description
url Url of the page containing the image
type Type of page (e.g., article, web)
headline Main headline or title of the page
description Brief summary or meta description of the page
author Name of the author or publisher of the page
date_modified Date when the page was last updated (available only for article pages)
date_published Publication date of the page (available only for article pages)

Filtering Matches

Here's an example of how to filter matches

import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.get("https://imatag.com/api/v4/matches/?watermarked=true&date_created__gte=2025-06-26T07:03:17.550062Z", headers=headers)

curl 'https://imatag.com/api/v4/matches/?watermarked=true&date_created__gte=2025-06-26T07:03:17.550062Z' \
 -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

  "next": "https://imatag.com/api/v4/matches/?cursor=cD0xNzUwOTIxNDI3MTg5JmM9MTgz&date_created__gte=2025-06-26T07%3A03%3A17.550062Z&watermarked=true",
  "previous": null,
  "results":
    {
      "id": "-5838135365226425586",
      "date_created": "2025-06-26T07:04:09.139659Z",
      "date_updated": "2025-06-26T07:04:09.143115Z",
      "export": true,
      "watermarked": true,
      "tags": [],
      "sessions": [
        7211
      ],
      "media": {
        "id": 8367688270167670191,
        "type": "image",
        "thumbnail": "https://static30.imatag.com/310396,01f3bed1574b1b8181",
        "image": "https://static30.imatag.com/310396,01f3bed1574b1b8181",
        "path": "AFP_36N88JP",
        "date_registered": "2025-05-12T07:19:44.594685Z",
        "credit": "AFP",
        "user_metadata": {
          "reference": "AFP_36N88JP"
        }
      },
      "site": {
        "id": -484839104856309443,
        "name": "wionews.com",
        "domain": "wionews",
        "suffix": "com",
        "country": "in"
      },
      "page": {
        "url": "https://www.wionews.com/tags/devdutt-padikkal",
        "type": "web",
        "image": {
          "url": "https://cdn1.wionews.com/dev/wion/images/2025/20250505/virat-kohli-test-gallery-5-623434.png?im=FitAndFill=(700,400)?im=FitAndFill=(910,512)"
        }
      }
    }

You can filter matches using query parameters.

Examples:

HTTP Request

GEThttps://imatag.com/api/v4/matches/?watermarked=true

HTTP Request

GEThttps://imatag.com/api/v4/matches/?site.domain=example.com

HTTP Request

GEThttps://imatag.com/api/v4/matches/?watermarked=true&media.id=123456

Available Filters

Parameter Description
id The unique id of the match
date_created / __gte / __lte / __gt / __lt Date filters
watermarked Filter by watermark presence
site.id Match a specific site
site.name Filter results by the name of the site
site.suffix Filter matches by the domain suffix (e.g., .com, .fr)
media.id Match a specific media
media.path Filter results by the path of the media
blacklist Exclude blacklisted domains
export If true, this match is eligible for CSV export
tags Custom tags that can be attached to the match for categorization or filtering
sessions If set, only results originating from these Crawling Session ids will be shown (supports one or multiple IDs).
page.url Url of the page containing the image
page.date_published Publication date of the page (available only for article pages)

Media

The media endpoint allows you to register and manage your media on IMATAG. The management part is quite standard: you PUT your media somewhere, and you can afterward GET it or DELETE it. What sets us apart is that all media you have added IMATAG is registered which means two things:

The flipside is that any media which has been marked but not registered on IMATAG or which has been deleted won't be searched for anywhere and we won't be able to find its watermark even from a manual query.

Media are organized in a folder tree structure. There are few constraints on the folder structure/naming:

Models

The generic media model is composed of a list of common properties, listed below, and specific sub properties

Media object

This model defines the list of attributes for all objects accessible along the path i.e. folder, image, document, etc.

Argument Description
url The URL of the media
path The path of the media
created The date of creation of the media
type The type of object: folder, image, video, document
children For folder, the list of objects contained in that folder (paginated)
metadata For any type of object, the list of the associated metadata.
image If it exists, details the Image object.
video If it exists, details the Video object.
exclusive For image, indicates whether an image is exclusive or not. If not specified, exclusivity is unknown.

Metadata Object

Example of a metadata object:

{
  "user.campaign": "my new campaign",
  "user.hasBeenValidated": true,
  "user.credited": null, # This field is not saved on media registration, but is deleted on media update
  "customer": "another customer" # This field is not valid
}

metadata is a dictionary containing fields composed of keys and values:

Image Object

Attribute Description
url URL of the actual image file
type Type of image, either registered for images registered via the Media API, or web for images found on the Web
width Width of the image in pixels
height Height of the image in pixels
format Format of the image (e.g. jpeg or png)
thumbnail URL of the image thumbnail, null if unavailable
credit Credit line of this image, null if empty

Additionally, depending on the type, images have extra fields:

Type registered:

Attribute Description
media_path Path of the Media object where the image is registered
media_url URL of the Media object where the image is registered

Type web:

Attribute Description
crawl_date Date at which the image was found the first time by our crawlers
page_url URL of the page containing the image
md5 MD5 hash of the image content (optional)
last_modified_date Date at which the image file was put on the server from which it was downloaded, if available (optional)

Video Object

Attribute Description
url URL of the actual video file (not always available)
type Type of video, set to registered or watermarked respectively for non-watermarked or watermarked videos registered via the Media API
width Width of the video in pixels
height Height of the video in pixels
thumbnail Url of the video thumbnail
duration Duration of the video
format Format of the video, among the followings: mov, mp4, m4a, 3gp, 3g2, mj2

Additionally, depending on the type, images have extra fields:

Type registered:

Attribute Description
streaming_url URL of a video file optimized for streaming (if available)

Type watermarked:

Attribute Description
secret Secret used for the watermark
max_payload Max_payload used for the watermark (payload mode only)
payload Payload used for the watermark (payload mode only)
original_path Path of the Media object where the original video is registered (if available)
original_url URL of the original video file

List a folder

import requests

headers = {
    'Authorization': 'Token <your api token>',
}
response = requests.get('https://imatag.com/api/v4/media/api.demo/images', headers=headers)
curl https://imatag.com/api/v4/media/api.demo/images \
 -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/media/api.demo/images",
    "path": "api.demo/images",
    "created": "2018-07-20T15:04:33.221902Z",
    "disk_usage": 242602,
    "type": "folder",
    "thumbnail": null,
    "metadata": {},
    "children_count": 2,
    "subfolders_count": 2,
    "media_count": 0,
    "next": null,
    "previous": null,
    "children": [
        {
            "url": "https://imatag.com/api/v4/media/api.demo/images/paris",
            "path": "api.demo/images/paris",
            "created": "2018-07-20T15:13:06.259863Z",
            "disk_usage": 0,
            "type": "folder",
            "thumbnail": null,
            "metadata": {},
            "children_count": 1,
            "subfolders_count": 0,
            "media_count": 2
        },
        {
            "url": "https://imatag.com/api/v4/media/api.demo/images/new-york",
            "path": "api.demo/images/new-york",
            "created": "2018-07-20T15:16:07.777535Z",
            "disk_usage": 0,
            "type": "folder",
            "thumbnail": null,
            "metadata": {},
            "children_count": 1,
            "subfolders_count": 0,
            "media_count": 4
        }
  ]
}

This endpoint lists the content of a folder at the given path. Note that the children list is paginated so you might have to iterate to get all children. The children attribute is only returned for the current folder and not for any subfolders. If you need the full hierarchy, you will need to recursively GET the url attribute of each subfolder.

HTTP Request

GEThttps://imatag.com/api/v4/media/<homedir>/<path>

URL Parameters

Parameter Required Description
homedir false The user home directory where to list media from (e.g. jdoe).
path false The path of the subfolder(s) to list media from (e.g. images/2018) within a home directory.

Query Parameters

Parameter Default Description
hidden 0 Show hidden folders & media (name starting with '.')

Response description

See Media object

Get a media

import requests

headers = {
    'Authorization': 'Token <your api token>',
}
response = requests.get('https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg',
                        headers=headers)
curl https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg \
 -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg",
    "path": "api.demo/images/paris/tour-eiffel.jpeg",
    "created": "2018-07-20T15:15:49.548216Z",
    "disk_usage": 97358,
    "type": "image",
    "thumbnail": "https://static1.imatag.com/54578,15ec5ca69f80719a",
    "metadata": {
        "user.subject":"Eiffel Tower",
        "user.campaign":"Paris by night"
    },
    "image": {
        "type": "registered",
        "url": "https://static1.imatag.com/59713,10a05da70fc4",
        "width": 800,
        "height": 500,
        "thumbnail": "https://static1.imatag.com/54578,15ec5ca69f80719a",
        "credit": "© 2012 Cameron Rutt"
    }
}

This endpoint retrieves information about the media at a given path.

HTTP Request

GEThttps://imatag.com/api/v4/media/<homedir>/<path>/<filename>

URL Parameters

Parameter Required Description
homedir true The user home directory where to list media from (e.g. jdoe).
path false The folder(s) path where to store the media within your home directory (e.g. images/2018)
filename true The file name of the file that will be used on our servers (e.g. new-york.jpg)

Response description

See Media object

Register a new media

This endpoint registers a previously watermarked media using the registration (LMK) file generated by the watermarking software or the API's watermarking endpoint. It also allows to add metadata to the media.

First example with the lmk file You can download this watermark file to run the example.

import requests

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/lmk",
}
lmk = open("./registration.lmk", "rb").read()
response = requests.put("https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
                        data=lmk, headers=headers)

curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/lmk" \
  --data-binary @- < ./registration.lmk

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
    "path": "api.demo/uploads/2018/my-image.jpg",
    "created": "2019-01-02T15:09:17.145580Z",
    "disk_usage": 97358,
    "type": "image",
    "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad",
    "metadata": {},
    "image": {
        "type": "registered",
        "url": "https://static4.imatag.com/20985,28c25e65d3e1baad",
        "width": 800,
        "height": 500,
        "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad"
    }
}

Second example with the JSON file

import requests
import json

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/json",
}
data = {
    "url": "https://static3.imatag.com/49785,25dcc2978a4b5bad",
    "metadata": {
        "user.isDemo": "True",
        "user.campaign": "Visit Paris 2020"
    }
}
response = requests.put("https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
                        data=json.dumps(data), headers=headers)

curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://static3.imatag.com/49785,25dcc2978a4b5bad", "metadata": { "user.isDemo": "True", "user.campaign": "Visit Paris 2020"}}'

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
    "path": "api.demo/uploads/2018/my-image.jpg",
    "created": "2019-01-02T15:09:17.145580Z",
    "disk_usage": 97358,
    "type": "image",
    "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad",
    "metadata": {
        "user.isDemo": "True",
        "user.campaign": "Visit Paris 2020"
    },
    "image": {
        "type": "registered",
        "url": "https://static4.imatag.com/20985,28c25e65d3e1baad",
        "width": 800,
        "height": 500,
        "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad"
    }
}

An additional example data-URI example is given in the Uploads section

PUThttps://imatag.com/api/v4/media/<homedir>/<path>/<filename>

URL Parameters

Parameter Required Description
homedir true The home directory where to upload the media. This is generally your own username or another client folder for which you're granted permission (e.g. jdoe)
path false The optional subfolder path, within your home directory, where to store the media (e.g. images/2018)
filename true The file name & extension of the image to register. It will be its name on our servers & in your account.

Request content

The content of the request must be either:

Attribute Required Description
url true URL of the lmk file, for example the one provided by the watermarking endpoint. A data URI can also be used to upload a local LMK file (an example is given in the Uploads section).
metadata false A metadata object

Response description

If the request is successful, the response is the newly created Media object

Modify a media metadata

This example is based on the previous example

import requests
import json

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/json",
}
data = '''{
    "metadata": {
        "user.isDemo": null,
        "user.campaign": "Visit Ulaanbaatar 2020"
    }
}'''

response = requests.patch("https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
                           data=json.dumps(data), headers=headers)

curl -X PATCH \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/json" \
  -d '{"metadata": { "user.isDemo": null, "user.campaign": "Visit Ulaanbaatar 2020"}}'

The above command returns JSON structured like this:

{}

This endpoint can be used to update metadata after the media creation.

HTTP Request

PATCHhttps://imatag.com/api/v4/media/<homedir>/<path>/<filename>

URL Parameters

Parameter Required Description
homedir true The home directory that contains the media. This is generally your own username or another client folder for which you're granted permission (e.g. jdoe)
path false The optional subfolder path, within your home directory, where the media is stored (e.g. images/2018)
filename true The file name & extension of the image.

Request content

Attribute Required Description
metadata false A metadata object

Response description

If the request is successful, a status code 200 is returned, along with an empty JSON.

Register a non-watermarked file for similar tracking only

import requests

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "image/jpeg",
}
image = open("./tour-eiffel.jpeg", "rb").read()
response = requests.put("https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
                        data=image, headers=headers)
curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: image/jpeg" \
  --data-binary @- < ./tour-eiffel.jpeg
curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/json" \
  --data '{"url" : "https://some.website.com/media/my-image.jpg"}'

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
    "path": "api.demo/uploads/2018/my-image.jpg",
    "created": "2019-01-02T15:09:17.145580Z",
    "disk_usage": 97358,
    "type": "image",
    "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad",
    "metadata": {},
    "image": {
        "type": "registered",
        "url": "https://static4.imatag.com/20985,28c25e65d3e1baad",
        "width": 800,
        "height": 500,
        "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad"
    }
}

This endpoint allows to register a non-watermarked file as a new media. The request is similar to the default media creation, except the content shall be an image or video directly.

This allows limited features with uploaded images or video, compared to watermarked media. Files can only be searched for other file with similar visual content:

For example, similar visual content images can produce matches for the same-looking but different photos, as shown below:

eiffel tower A eiffel tower B

The exception to this is when you register a non-watermarked original video for subsequent watermarked video registration.

Request content

The content of the request must be either:

Supported format

file type content type content
image application/json {"url": "url/of/file.jpg"}
image image/jpg Binary file
video application/json {"url": "url/of/file.mp4"}
video video/mp4 Binary file
zip application/zip Binary file

Response description

If the request is successful, the response is the newly created Media object

Register an exclusive image

import requests

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "image/jpeg",
    "X-Lamark-Exclusive": True,
}
image = open("./tour-eiffel.jpeg", "rb").read()
response = requests.put("https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
                        data=image, headers=headers)
curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: image/jpeg" \
  -H "X-Lamark-Exclusive: True" \
  --data-binary @- < ./tour-eiffel.jpeg

The above command returns JSON structured like this:

{   
    "type": "image",
    "exclusive": true,
    ...
}

When registering an image, you can flag it as exclusive,

Register a watermarked video

This example is for a watermarked video with payload

import requests
import json

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/json",
}
data = {
    "type": "video",
    "url": "https://imatag.com/api/v4/media/api.demo/uploads/original_video.mp4",
    "secret": "my secret video",
    "payload": 5,
    "max_payload": 20,    
}
response = requests.put("https://imatag.com/api/v4/media/api.demo/uploads/watermarked_video.mp4",
                        data=json.dumps(data), headers=headers)

curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/watermarked_video.mp4 \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/json" \
  -d '{"type": "video", "url": "https://imatag.com/api/v4/media/api.demo/uploads/original_video.mp4",\
    "secret": "my secret video", "payload": 5, "max_payload": 20}'

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/media/api.demo/uploads/watermarked_video.mp4",
    "path": "api.demo/uploads/watermarked_video.mp4",
    "created": "2019-01-02T15:09:17.145580Z",
    "disk_usage": 31380,
    "type": "video",
    "thumbnail": "http://static4.imatag.com/71,02f024f4def5ac",
    "metadata": {},
    "video": {
        "type": "watermarked",
        "secret": "my secret video",
        "max_payload": 20,
        "payload": 5,
        "url": null,
        "width": 960,
        "height": 540,
        "duration": 18.234883,
        "format": "mov,mp4,m4a,3gp,3g2,mj2",
        "original_path": "api.demo/uploads/original_video.mp4",
        "original_url": "http://static4.imatag.com/270,02f0231374f9b5",
        "thumbnail": "http://static4.imatag.com/71,02f024f4def5ac"
    }
}

There are no "registration file" for video like there are for images. As a consequence registering a watermarked video file requires manually sending several pieces of information including the original (un-watermarked) video file that must be provided as an url.

additional URL Parameters

Parameter Required Description
secret true Secret used for the watermark
payload false Payload used for the watermark (integer), must be betweend 0 and max_payload
max_payload false Max_payload used for the watermark (integer, required if payload is used, must be constant for a given secret and original video).

Register multiple medias from a ZIP

This endpoint allows uploading multiple medias from a ZIP file into a folder at once. The ZIP file can contain mixed medias, such as images, videos or registration files.

import requests

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/zip",
}
lmk = open("./my-archive.zip", "rb").read()
response = requests.put("https://imatag.com/api/v4/media/api.demo/uploads/2018",
                        data=lmk, headers=headers)

curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018 \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/zip" \
  --data-binary @- < ./my-archive.zip

HTTP Request

PUThttps://imatag.com/api/v4/media/<homedir>/<path>

URL Parameters

Parameter Required Description
homedir true The user home directory where the subfolder will be created (e.g. jdoe).
path true The path of the subfolder to upload the zip to (e.g. images/2017).

Delete an existing media

import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.delete("https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
                           headers=headers)
curl -X DELETE \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
 -H "Authorization: Token <your api token>"

This endpoint deletes and unregisters an existing media.

HTTP Request

DELETEhttps://imatag.com/api/v4/media/<homedir>/<path>/<filename>

URL Parameters

Parameter Required Description
homedir true The home directory that contains the media. This is generally your own username or another client folder for which you're granted permission (e.g. jdoe)
path false The optional subfolder(s) where the media is stored (e.g. images/2018)
filename true The file name and extension of the media to delete

Create a folder

import requests

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/x-directory",
}

response = requests.put(
    "https://imatag.com/api/v4/media/api.demo/uploads/2018",
    headers=headers,
    )

curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018 \
 -H "Authorization: Token <your api token>" \
 -H "Content-Type: application/x-directory"

This endpoint creates an empty folder.

HTTP Request

PUThttps://imatag.com/api/v4/media/<homedir>/<path>

URL Parameters

Parameter Required Description
homedir true The user home directory where the subfolder will be created (e.g. jdoe).
path true The path of the subfolder to create (e.g. images/2017).

Delete an existing folder

import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.delete("https://imatag.com/api/v4/media/api.demo/uploads/2018",
                           headers=headers)
curl -X DELETE \
  https://imatag.com/api/v4/media/api.demo/uploads/2018 \
 -H "Authorization: Token <your api token>"

This endpoint deletes a folder and all of its content (subfolders, images, documents, etc.) recursively. All media contained within will be unregistered.

HTTP Request

DELETEhttps://imatag.com/api/v4/media/<homedir>/<path>

URL Parameters

Parameter Required Description
homedir true The user home directory that contains the subfolder to delete (e.g. jdoe).
path true The path of the subfolder to delete (e.g. images/2017).

Move a folder or a media

import requests

headers = {
    "Authorization": "Token <your api token>",
}
data = {
    "url": "<homedir>/<path>",
    "to" : "<homedir>/<other path>",
}
response = requests.post("https://imatag.com/api/v4/media/_move/",
                         json=data, headers=headers)    
curl -L -X POST 'https://imatag.com/api/v4/media/_move/' \
  -H 'Authorization: Token <your api token>' \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "url": "{{home}}/{{path}}",
    "to": "{{home}}/{{new_path}}"
  }'

The above command returns JSON structured like this:

{
    "path": "<homedir>/<path>"
}

This endpoint moves a resource to another location

HTTP Request

POSThttps://imatag.com/api/v4/media/_move/

Request content

Attribute Required Description
url true Path of the media to move or rename.
to true New path of the media destination. The path will be created if needed.
If to ends with a /, it will be considered as a folder where to move the media to.
In any other cases, the original url will be moved/renamed to to.

Response description

If the request is successful, the response contains the path of the moved/renamed resource.

Argument Description
path The new path of the media, once moved.

Searches

The searches endpoint allows you to schedule searches on images and, depending on your pricing plan, PDF documents. It also allows you to monitor the status of these searches and once complete, to access their results. Searches scheduled via the API, like automated web and press search will find watermarked and similar matches.

Search object

Searches may be done synchronously or asynchronously depending on the input media type and the expected time required to perform the search.

Synchronous searches are ephemeral and never recorded, but are faster than asynchronous searches.

For synchronous searches, the search object contains the following fields:

Field Description
status The status of the search. Can be: complete or failed
matches When status is complete, the matches list is inlined

For asynchronous searches, the search object contains the following fields:

Field Description
status The status of the search. Can be: complete, failed, pending, in progress, or cancelled,
matches When status is complete, the URL of the list of matches (see Match object) found in this search.
progress When status is in progress, an integer representing advancement (in percent).
url The URL of the search
name The name of the search
created The date of creation of the search
type The type of object: image or document
image For image, the static URL of the image.
document For document, the static URL of the document.

This endpoint performs a new search from an image, either by uploading it or by providing a publicly accessible url. Depending on your pricing plan, you might be allowed to upload pdf files to search all images in the document. You might also be limited in speed and number of searches.

HTTP Request

POSThttps://imatag.com/api/v4/searches/

Request content

For a search by image, the following parameters are available

Parameter Default Description
file null Query file (image or document) if the request is multipart/form-data, or the URL of the query image or document (Data URIs are supported)
name null If set, name for the search. If unset, the filename of the uploaded "file" will be used.
sync Run the search in synchronous mode if set; default is true for images, false otherwise; synchronous searches are allowed only on images
search_path <homedir> Restrict the search to a specific media path (<homedir>/<path>).
mode "near_duplicate" Can be near_duplicate to attempt to find the original image(s) the query is derived from or vice-versa, if the matched original is watermarked, detection will be performed. Alternatively can be set to similar to do a faster search in order to find visually similar images which are not necessarily derived from one another or 'leaks'.
categories ["default"] A list to where to search; for image search only; authorized users only. The default may be changed to one of recent (recent images, faster), all (all images, slower).
transforms ["scale"] Geometric transform validation model for images; default is scale (crop/resize no rotation), other allowed values are affine (crop/resize/rotation) or perspective. If mode=leaks, default is ["scale", "perspective"].
filter_marked false If set, filter the results to only show watermarked results (true) or non-watermarked (false)

For a search by text, the following parameters are available

Parameter Default Description
metadata null Dict that represent metadata to search
type null String to search only specific media type ("image", "video", "folder")
filename null String that represent the exact filename to search (case sensitive)
filename__startswith null String that represent the begining of the filename to search (case sensitive). Minimum length required = 3
sync true Run the search in synchronous mode if set

Response content

The response is one of the following, depending on the sync query parameter:

Multiple search use cases:

Search by binary file

Search with a binary file, by direct upload. (See example)

You can download the registered tour-eiffel.jpeg file from the media example to run the example.

import requests

headers = {
    "Authorization": "Token <your api token>"
}
files = {'file': open('tour-eiffel.jpeg', 'rb')}
response = requests.post("https://imatag.com/api/v4/searches/",
                        files=files, headers=headers)

curl -X POST \
  https://imatag.com/api/v4/searches/ \
  -H "Authorization: Token <your api token>" \
  -F "file=@tour-eiffel.jpeg"

The above commands returns JSON structured like this:

{
    "status": "complete",
    "matches": [
        {
            "id": null,
            "created": "2019-11-18T16:40:11.133727Z",
            "type": "user",
            "watermarked": true,
            "image": {
                "type": "registered",
                "url": "https://static4.imatag.com/54578,15ec5ca69f80719a",
                "width": 1280,
                "height": 1706,
                "thumbnail": "https://static4.imatag.com/211701,81c386bd3eb68eba",
                "credit": null,
                "media_path": "/api.demo/images/paris/tour-eiffel.jpeg",
                "media_url": "https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg"
            }
        }
    ]
}

Search by file url

Search with a remote image, by providing its public URL. (See example)

Alternatively you can perform a request by url

import requests
import json

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/json",
}
data = {'file': 'https://imatag.com/api/doc/images/tour-eiffel.jpeg'}
response = requests.post("https://imatag.com/api/v4/searches/",
                        data=json.dumps(data), headers=headers)

curl -X POST \
  https://imatag.com/api/v4/searches/ \
  -H "Authorization: Token <your api token>" \
  -F "file=https://imatag.com/api/doc/images/tour-eiffel.jpeg"

The above commands returns JSON structured like this:

{
    "status": "complete",
    "matches": [
        {
            "id": null,
            "created": "2019-11-18T16:39:02.263262Z",
            "type": "user",
            "watermarked": true,
            "image": {
                "type": "registered",
                "url": "https://static1.imatag.com/54578,15ec5ca69f80719a",
                "width": 1280,
                "height": 1706,
                "thumbnail": "https://static3.imatag.com/211701,81c386bd3eb68eba",
                "credit": null,
                "media_path": "/api.demo/images/paris/tour-eiffel.jpeg",
                "media_url": "https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg"
            }
        }
    ]
}

Search by text

You can search by text. (See example)

You can perform a text search

import requests
import json

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/json",
}
data = {
    "metadata": {
        "user.subject": "Eiffel Tower"   
    },
    "filename" : "tour-eiffel.jpeg",
    "type": "image"
}
response = requests.post("https://imatag.com/api/v4/searches/",
                        data=json.dumps(data), headers=headers)

The above commands returns JSON structured like this:

{
    "status": "complete",
    "matches": [
        {
            "id": null,
            "created": "2020-10-23T13:41:21.743541Z",
            "type": "text",
            "query": {
                "filename": "tour-eiffel.jpeg",
                "type": [
                    "image"
                ],
                "sync": true,
                "metadata": {
                    "user.subject": "Eiffel Tower"
                }
            },
            "media": {
                "metadata": {
                    "user.subject": "Eiffel Tower",
                    "user.campaign": "Paris by night"
                },
                "media_path": "api.demo/images/paris/tour-eiffel.jpeg",
                "media_url": "https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg"
            }
        }
    ]
}

The search endpoint has a "sync" parameter that can be used to turn on the search asynchronously.

By default, the search is synchronous. An explicit sync disabling to False is required to run in async mode.

(See example)

You can also perform an asynchronous search:

import requests

headers = {
    "Authorization": "Token <your api token>"
}
files = {'file': open('tour-eiffel.jpeg', 'rb'), 'sync': 0}
response = requests.post("https://imatag.com/api/v4/searches/",
                        files=files, headers=headers)

curl -X POST \
  https://imatag.com/api/v4/searches/ \
  -H "Authorization: Token <your api token>" \
  -F "file=@tour-eiffel.jpeg" \
  -F "sync=0"

The above commands returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/searches/HTnqefQkb7jq/",
    "type": "image",
    "image": "https://static2.imatag.com/176044,20b70be705dcf657",
    "name": "tour-eiffel.jpg",
    "created": "2018-11-07T13:25:52.277479Z",
    "status": "pending"
}

This endpoint retrieves a specific search.

import requests

headers = {
    'Authorization': 'Token <your api token>',
}
response = requests.get('https://imatag.com/api/v4/searches/HTnqefQkb7jq/',
                        headers=headers)
curl hhttps://imatag.com/api/v4/searches/HTnqefQkb7jq/ \
 -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/searches/HTnqefQkb7jq/",
    "type": "image",
    "image": "https://static2.imatag.com/176044,20b70be705dcf657",
    "name": "tour-eiffel.jpg",
    "created": "2018-11-07T13:25:52.277479Z",
    "status": "complete",
    "matches": "https://imatag.com/api/v4/searches/HTnqefQkb7jq/matches/"
}

HTTP Request

GEThttps://imatag.com/api/v4/searches/<search_id>/

URL Parameters

Parameter Required Description
search_id true The unique id of the search to retrieve.

Response description

See Search object

List all previous searches

This endpoint lists the asynchronous searches submitted by the user.

import requests

headers = {
    'Authorization': 'Token <your api token>',
}
response = requests.get('https://imatag.com/api/v4/searches/', headers=headers)
curl https://imatag.com/api/v4/searches/ \
 -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

{
    "next": null,
    "previous": null,
    "results": [
        {
            "url": "https://imatag.com/api/v4/searches/qYh98JhK3mUa/",
            "type": "image",
            "image": "https://static1.imatag.com/172987,20d82c6c92e0ff2a",
            "name": "https://imatag.com/api/doc/images/tour-eiffel.jpeg",
            "created": "2018-11-08T16:48:11.619025Z",
            "status": "complete",
            "matches": "https://imatag.com/api/v4/searches/qYh98JhK3mUa/matches/"
        },
        {
            "url": "https://imatag.com/api/v4/searches/HTnqefQkb7jq/",
            "type": "image",
            "image": "https://static2.imatag.com/176044,20b70be705dcf657",
            "name": "tour-eiffel.jpg",
            "created": "2018-11-07T13:25:52.277479Z",
            "status": "complete",
            "matches": "https://imatag.com/api/v4/searches/HTnqefQkb7jq/matches/"
        }
    ]
}

HTTP Request

GEThttps://imatag.com/api/v4/searches/

Query Parameters

Parameter Default Description
date null If set, only searches started on that exact date on the date field (or exact date & time) will be shown. This cannot be combined with other date lookups on the same field (gt, lt, etc.)
date_lte null If set, only searches started on that date or earlier on the date field will be shown
date_gte null If set, only searches started on that date or later on the date field will be shown
date_lt null If set, only searches started earlier than that date on the date field will be shown
date_gt null If set, only searches started later than that date on the date field will be shown

Response description

Attribute Description
next Url of the next searches in the sequence (null if end is reached)
previous Url of the previous searches in the sequence (null at the start)
results List of Search objects (see Search object)
import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.delete("https://imatag.com/api/v4/searches/trhPnufS7NxJ/",
                           headers=headers)
curl -X DELETE \
  https://imatag.com/api/v4/media/api.demo/searches/trhPnufS7NxJ/ \
 -H "Authorization: Token <your api token>"

This endpoint deletes an existing search and associated matches.

HTTP Request

DELETEhttps://imatag.com/api/v4/searches/<search_id>/

URL Parameters

Parameter Required Description
search_id true The unique id of the search to retrieve.

Uploads

Data-URI example for the media endpoint

import requests
import base64
import json

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "application/json",
}
lmk = open("./registration.lmk", "rb").read()
lmk_base64 = base64.b64encode(lmk)
data = {
    "url": "data:application/lmk;base64,{}".format(lmk_base64),
    "metadata": {
        "user.isDemo": "True",
        "user.campaign": "Visit Paris 2020"
    }
}
response = requests.put("https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
                        data=json.dumps(data), headers=headers)
echo "{ \
   \"url\": \"data:application/lmk;base64,$(base64 -w 0 registration.lmk)\", \
   \"metadata\": { \
        \"user.isDemo\": \"True\", \
        \"user.campaign\": \"Visit Paris 2020\" \
   } \
}" | curl -X PUT \
  https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/json" \
  -T -

The above command returns JSON structured like this:

{
    "url": "https://imatag.com/api/v4/media/api.demo/uploads/2018/my-image.jpg",
    "path": "api.demo/uploads/2018/my-image.jpg",
    "created": "2019-01-02T15:09:17.145580Z",
    "disk_usage": 97358,
    "type": "image",
    "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad",
    "metadata": {
        "user.isDemo": "True",
        "user.campaign": "Visit Paris 2020"
    },
    "image": {
        "type": "registered",
        "url": "https://static4.imatag.com/20985,28c25e65d3e1baad",
        "width": 800,
        "height": 500,
        "thumbnail": "https://static4.imatag.com/208368,28c25e65d3e1baad"
    }
}

Some of our endpoints support direct binary upload when no additional information is required, however others have optional or mandatory additional fields. In this case the file is provided via URL. If the file is not already accessible on a publicly available URL, we offer two options:

The first one is to use a data URI. This requires you to base64 encode your file but limits the number of consecutive API calls. Data-URIs can be used anywhere that require a URL. An example is provided here for a call to the media endpoint.

Alternatively, the uploads endpoint allows you to store temporarily your images on our servers and get URL which can be used on subsequent API calls. This is particularly useful if you need to use the same file in multiple API calls or when you can't do base-64 encoding on your side.

Upload a media

To perform a simple media (image or video) upload, use the endpoint with upload_type=media (default, can be omitted)

import requests

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "image/jpeg",
}
img = open("./original.jpeg", "rb").read()
response = requests.post(
    "https://imatag.com/api/v4/uploads/?upload_type=media",
    data=img, headers=headers)
curl -X POST \
  https://imatag.com/api/v4/uploads/?upload_type=media \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: image/jpeg" \
  --data-binary @- < ./original.jpeg

The above command returns JSON structured like this:

{
    "expiry": "2018-12-28T14:10:24Z",
    "url": "http://static2.imatag.com/208562,27981f5f5ad9e3de"
}

This endpoints stores the image or video on our servers in a temporary collection.

HTTP Request

POSThttps://imatag.com/api/v4/uploads/

POSThttps://imatag.com/api/v4/uploads/?upload_type=media

By default, without explicit upload_type query parameter, the simple upload (ie full media file upload) method will be considered.

Add these HTTP headers:

Header Description
Content-Type Set to the MIME media type of the object being uploaded.
Content-Length Set to the number of bytes you upload.

Response description

The response indicates the temporary location of the uploaded asset and its expiration.

Attribute Description
url The URL of the uploaded media on our servers
expiry Expiration date of the uploaded media on our servers (approximate)

Upload a large media in chunks

For large file, up to 1Gb, you must use this method to upload a file in several chunks; by sending multiple successive requests.

Initiate a resumable upload session

To allow a file upload in multiple fragments, you first have to initiate a session for a resumable upload, using the upload_type=resumable query parameter on the uploads endpoint

import requests

headers = {
    "Authorization": "Token <your api token>",
    "X-Upload-Content-Disposition": f'name="my-image.jpg"; filename="my-image.jpg"',
    "X-Upload-Content-Type": "image/jpeg",
    "X-Upload-Content-Length": "5833680",
}

response = requests.post(
    "https://imatag.com/api/v4/uploads/?upload_type=resumable",
    headers=headers)

upload_session_url = response.headers.get("Location")


curl -i -X POST \
  https://imatag.com/api/v4/uploads/?upload_type=resumable \
  -H "Authorization: Token <your api token>" \
  -H "X-Upload-Content-Disposition: name='my-image.jpg'; filename='my-image.jpg'" \
  -H "X-Upload-Content-Type: image/jpeg" \
  -H "X-Upload-Content-Length: 5833680"

POSThttps://imatag.com/api/v4/uploads/?upload_type=resumable

The following headers are highly recommended to be filled in, so that we have enough information about the file to be uploaded later

Header Description
X-Upload-Content-Type Set to the MIME media type of the file to be uploaded.
X-Upload-Content-Length Set the total number of bytes of the file to be uploaded.
X-Upload-Content-Disposition Set the name of the file to be uploaded.

Response description

If successful, the response includes a 200 status code, with the Location header containing the resumable session URI

Upload the data in multiple chunks

Once you have initiated the resumable upload session, you will be able to upload the file date in multiple chunks.

The chunk size cannot exceed 256Mb.

Use the upload URI saved from previous step, to upload the data:

import requests

headers = {
    "Authorization": "Token <your api token>",
    "Content-Disposition": f'name="my-image.jpg"; filename="my-image.jpg"',
    "Content-Type": "image/jpeg",
    "Content-Length": "2097152",
    "Content-Range": "0-2097151/5833680",
}

chunk = open("./original.jpeg", "rb").read(2*1024*1024)

response = requests.put(
    "https://imatag.com/api/v4/uploads/?upload_id=<uuid>",
    headers=headers)
curl -i -X PUT \
  https://imatag.com/api/v4/uploads/?upload_id=resumable \
  -H "Authorization: Token <your api token>" \
  -H "Content-Disposition: name='my-image.jpg'; filename='my-image.jpg'" \
  -H "Content-Type: image/jpeg" \
  -H "Content-Length: 2097152" \
  -H "Content-Range: 0-2097151/5833680" \
  --data-binary @- < ./chunk_file_location

PUThttps://imatag.com/api/v4/uploads/?upload_id=<uuid>

providing the headers:

Header Description
Content-Type Set to the MIME media type of the full media file.
Content-Length Set the number of bytes you're uploading in the current request.
Content-Range Set the range of bytes in the overall media of the current chunk being uploaded,
as bytes <chunk fist byte>-<chunk last byte>/<total file size>.
An example Content-Range is Content-Range: bytes 0-8388607/20000000.
Content-Disposition Set the name of the full file.

The Content-Range header is providing the information about the begin & end of the current chunk as well as the total file size.

You have to repeat this step until last chunk is uploaded.

Response description

An example Range is Range: bytes=0-4194304

Attribute Description
url The URL of the uploaded media on our servers
expiry Expiration date of the uploaded media on our servers (approximate)

Watermarking

The watermarking endpoint allows you to apply an invisible watermark on a provided image file.

The watermarked file can then be:

Watermarking a file

Watermarking an image by URL

import requests

headers = {
    "Authorization": "Token <your api token>",
}
data = {
    "url": "https://imatag.com/api/doc/images/tour-eiffel.jpeg",
    "sync": True, # False (default true)
    "timeout" : 120 # number of seconds (default 120)
}
response = requests.post("https://imatag.com/api/v4/watermarking/",
                         json=data, headers=headers)    
curl -X POST \
  https://imatag.com/api/v4/watermarking/ \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/json" \
  --data '{"url": "https://imatag.com/api/doc/images/tour-eiffel.jpeg", "sync": true}'

The above command returns JSON structured like this:

{
    "expiry": "2018-12-06T17:26:22Z",
    "original": "http://static1.imatag.com/208141,240d162ab9716c41",
    "watermarked": "http://static2.imatag.com/208141,240d164028af21c7",
    "registration": "http://static4.imatag.com/208145,240d163d6fdc2249"
}

HTTP Request

POSThttps://imatag.com/api/v4/watermarking/

Request content

The content of the request must be either:

Attribute Required Description
url true The URL of the asset "http://..."`
sync false The sync call of the api (true or false, default = true)
timeout false The timeout call of the api

Response description

The response indicates where to download the generated assets and their expiration.

Attribute Description
original The URL of the original full-size image
watermarked The URL of the watermarked full-size image
expiry Expiration date of the watermarked assets on our servers (approximate)
registration The URL of the registration data that should be sent on the media endpoint

Limited number of watermarking per day

This endpoint has extra rate limits, to allow a maximum number of the watermarking endpoint calls per day i.e. per 24-hours period. The limit & remaining counts are indicated as response headers:

Watermark an image

Watermarking an image by direct upload

import requests

headers = {
    "Authorization": "Token <your api token>",
    "Content-Type": "image/jpeg",
}
img = open("./original.jpeg", "rb").read() # file to watermark
response = requests.post("https://imatag.com/api/v4/watermarking/",
                         data=img, headers=headers)
curl -X POST \
  https://imatag.com/api/v4/watermarking/ \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: image/jpeg" \
  --data-binary @- < ./original.jpeg

The endpoint apply the watermarking on any image, provided in a supported format. See the list of supported formats

The above command returns JSON structured like this:

{
    "expiry": "2018-12-06T17:26:22Z",
    "original": "http://static1.imatag.com/208141,240d162ab9716c41",
    "watermarked": "http://static2.imatag.com/208141,240d164028af21c7",
    "registration": "http://static4.imatag.com/208145,240d163d6fdc2249"
}

Detect a watermarked file

Watermark detection

import requests

headers = {
    "Authorization": "Token <your api token>",
}
data = {
    "query": "http://static2.imatag.com/208141,240d164028af21c7",
    "registration": "http://static4.imatag.com/208145,240d163d6fdc2249"
    # or "registration": "https://imatag.com/api/v4/media/api.demo/images/paris/tour-eiffel.jpeg"
}
response = requests.post(
    "https://imatag.com/api/v4/watermarking/detect/",
    json=data, headers=headers)
curl -X POST \
  https://imatag.com/api/v4/watermarking/detect/ \
  -H "Authorization: Token <your api token>" \
  -H "Content-Type: application/json" \
  --data '{"query": "https://imatag.com/api/doc/images/query.jpeg", "registration": "http://static4.imatag.com/208145,240d163d6fdc2249"}'

The above command returns JSON structured like this:

{
    "marked": true
}

HTTP Request

POSThttps://imatag.com/api/v4/watermarking/detect/

The endpoint allows verifying if an image, aka query, is a watermarked copy of the image from the registration file.

This is for when you want to do exactly one detection, know exactly which watermark you want to detect and expect a boolean answer. If you want to find out which watermark, if any, is present in the image (either because you have several watermarked versions of the same image or because you are not sure what was the original image), you should use the searches endpoint instead.

Request content

The content of the request must be JSON with following attributes:

Attribute Required Description
query true The URL of the image to check
registration false The URL of the registration file (containing the watermark data) for comparison against the query. Data URIs are supported as well as urls of registered images in media.
sync false The sync call of the api (true or false, default = true)
timeout false The timeout call of the api (0 <= integer <= 120, default = 120)
transform false Geometric transform validation model for images; default is scale (crop/resize no rotation), other allowed values are affine (crop/resize/rotation), perspective or none.

Response description

The response indicates whether the query image is a watermarked copy of the compared registration/original asset(s).

Attribute Description
marked If True, the query is watermarked*.
If False, the query is either too much altered or a different image.
payload Payload value for images watermarked with payload mode. Omitted if not applicable.

Get the encryption key

Get the encryption key

import requests

headers = {
    "Authorization": "Token <your api token>",
}
response = requests.get(
    "https://imatag.com/api/v4/watermarking/key/",
    headers=headers)
curl https://imatag.com/api/v4/watermarking/key/
 -H "Authorization: Token <your api token>"

The above command returns JSON structured like this:

{
    "key": "-----BEGIN RSA PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DIDAQAB\n-----END RSA PUBLIC KEY-----"
}

HTTP Request

GEThttps://imatag.com/api/v4/watermarking/key/

This endpoint returns the encryption key that can be used by the watermarking software to encrypt the registration file.

Response description

The response contains the key.

Attribute Description
key The RSA public key in PEM format

Helpful Resources

This section provides additional resources and practical tips to enhance your experience with our API. From pagination and error handling to image formats and watermark details, you'll find useful explanations and clarifications. A glossary is also included to help you navigate technical terms with ease.

Watermark detection information

Statistical significance

Throughout this API and IMATAG in general, images are said to be "watermarked" if the detection test result has a P-value lower than a fixed probability of error threshold (IMATAG communicates this threshold upon request to clients).

For security reasons, IMATAG does not normally provide the actual P-value of any given match and it is therefore not accessible via the API. If you have a legal reason that requires this p-value for a given query, please contact IMATAG and we will provide you the information.

Pagination

All endpoints which return collections of objects use pagination. All those endpoints return the following attributes in their response:

Attribute Description
count Total number of objects
next Url of the next objects in the sequence (null if end is reached)
previous Url of the previous objects in the sequence (null at the start)
<attr_name> List of paginated objects (current chunk)

To navigate the collection, you need to iteratively do GET requests at the url provided in the next attribute for each chunk of the collection.

By default, a page will contain 100 objects at most. You can change that number by specifying page_size=X as query parameter in any url. The maximum number of objects per page allowed is 100.

Image formats

Our API is currently limited to some images format only:

To use images directly on endpoints that support simple upload, use the corresponding media type (content-type header) for each image format:

Image Format Media Type
JPEG image/jpeg
PNG image/png
GIF image/gif
TIFF image/tiff

Output formats

By default, responses data are returned as json. You can choose to specify the output format as query parameter ?format=<format>.

We currently support json format.

Error handling recommendations

4XX errors

5XX errors and network errors

Retry after 1h (or more)

Versioning

The versioning of the API is specified as part of the URI. For instance, in order to use v4 of the API the request URI should begin with /api/v4 followed by a specific endpoint.

https://imatag.com/api/v4/<endpoint>

Supported versions are:

API Version Documentation link
v1 (deprecated) v1
v2 (stable) v2
v3 (stable) v3
v4 (current) v4