Welcome to the documentation for the Steg AI API. The Steg AI API conforms to the design principals of the representational state transfer (REST) architectural style. Our API has resource-oriented URLs, accepts form-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.
https://api.steg.ai
The Steg AI API uses API keys to authenticate requests. All API requests expect an API key to be included in the header. Requests sent without an API key will fail. Moreover, all API requests must be made over HTTPS. Requests made over HTTP will fail.
Use your API key by assigning it to x-api-key in the request header.
Your API keys hold many privileges, and it is imperative that you keep them secure. Do not share your API keys publicly; for example, in client-side code or code repositories like Github.
To register a new API key, contact us.
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
requests.get("https://api.steg.ai/<ENDPOINT>", headers=headers)
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
fetch("https://api.steg.ai/<ENDPOINT>",
method: "GET",
headers: headers
)
curl --request GET "https://api.steg.ai/<ENDPOINT>" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here"
When you make a request to the Steg AI API, a response status code and JSON object are returned. The response status code indicates success or failure of the API request. The JSON object provides additional information in the event of a failure.
The Steg AI API uses standard HTTP response status codes. Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error from the client (for example, because an invalid parameter was provided). Codes in the 5xx range indicate an error with Steg’s servers.
The response JSON object is populated in the event of an error; specifically, a status code in the 4xx or 5xx range.
200 | OK | Everything worked as expected. |
400 | Bad Request | The request was not accepted. This is usually because a required parameter was missing. |
401 | Unauthorized | No valid API key provided. |
403 | Forbidden | The API key does not have permissions to perform the request. |
404 | Not Found | The requested endpoint does not exist. |
405 | Method Not Allowed | The requested endpoint does not allow this method. |
500 | Server Error | Something went wrong on Steg’s end. |
{
"error": {
"message": "'asset_id' is missing.",
"type": "invalid_parameter"
}
}
api_error | A catch-all for API errors not covered by the other error types. |
authenication_error | The API key included in the request isinvalid or not set. |
invalid_request | The request does not support this method. |
invalid_params | At least one parameter in the request is missing or invalid. |
Pagination is a technique used in APIs to manage large datasets returned by queries. When an API resource has an extensive list of objects, pagination helps break down the results into smaller, more manageable chunks. The Steg AI API implements pagination through the use of query string parameters in the request URL. Clients can control the pagination of results by specifying the next and limit parameters.
For example, calling the GET /usage endpoint will only return the 25 most recent usage of the Steg AI API. But if you have made 100 calls to the API, you would need to use pagination to retrieve all the results.
import json
import requests
BASE_URL = "https://api.steg.ai"
APIKEY = "api_key_here"
headers = {
"Content-Type": "application/json",
"x-api-key": APIKEY
}
usage = []
params = {}
while True:
response = requests.get(f"{BASE_URL}/usage", headers=headers, params=params)
reponse_data = response.json()
next_key = reponse_data.get("next_key")
# No more data to retrieve if "next_key" is null
if not next_key:
break
# Use the "next" to retrieve the next set of items
params["next"] = next_key
usage += reponse_data.get("data")
print(len(usage)) # Will have all the results
const BASE_URL = "https://api.steg.ai";
const APIKEY = "api_key_here";
const headers = {
"Content-Type": "application/json",
"x-api-key": APIKEY
};
let usage = [];
let params = {};
(async () => {
while (true) {
const queryString = new URLSearchParams(params).toString();
const response = await fetch(BASE_URL + "/usage?" + queryString, { headers });
const responseData = await response.json();
const nextKey = responseData.next_key;
// No more data to retrieve if "next_key" is null
if (!nextKey) {
break;
}
// Use the "next" to retrieve the next set of items
params.next = nextKey;
usage = [...usage, ...responseData.data];
}
console.log(usage.length); // Will have all the results
})();
#!/bin/bash
# Set your API key
APIKEY="your_api_key_here"
# Set your base URL
BASE_URL="https://api.example.com"
# Set your initial headers
headers=(
"Content-Type: application/json"
"x-api-key: $APIKEY"
)
# Initialize the list for storing usage data
usage=()
# Initialize an empty params dictionary
declare -A params
# Loop until there is no more data to retrieve
while true; do
# Make a GET request to retrieve usage data
response=$(curl -X GET "${BASE_URL}/usage" -H "${headers[@]}" --data-urlencode "$(declare -p params)")
# Parse the JSON response
response_data=$(echo "$response" | jq -r '.')
next_key=$(echo "$response_data" | jq -r '.next_key')
# Exit the loop if there is no more data to retrieve
if [ "$next_key" = "null" ]; then
break
fi
# Use the "next" key to retrieve the next set of items
params["next"]=$next_key
# Append the usage data to the usage list
usage+=($(echo "$response_data" | jq -r '.data[]'))
done
# Print the length of the usage list
echo "${#usage[@]}"
This endpoint decodes any and all supported asset types. You can either decode an asset uploaded through the Steg AI upload endpoint or by using a URL. You can also specify whether the request should be synchronous or asynchronous using the async property. This endpoint also supports batch decoding with a limit of 50 assets per request. For batch decodes, all requests will be handled asynchronously.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID"
},
{
"url": "www.path_to_png_image.com",
"mime_type": "image/png"
}
],
"async": False
}
requests.post("https://api.steg.ai/decode", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID"
},
{
"url": "www.path_to_png_image.com",
"mime_type": "image/png"
}
],
"async": false
};
fetch("https://api.steg.ai/decode",
method: "POST",
headers: headers ,
body: JSON.stringify(body)
)
curl --request POST "https://api.steg.ai/decode" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"assets":[{"asset_id":"EXAMPLE_ASSET_ID"},{"url":"www.path_to_png_image.com","mime_type":"image/png"}],"async":false}'
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [
{
"original_asset": "EXAMPLE_ASSET_ID",
"source": "STEG",
"asset_id_found": "c20007c5-fe03-4db8-b394-c874d570cdab",
"data_found": {
"key": "value"
}
},
{
"original_asset": "www.path_to_png_image.com",
"source": "EXTERNAL",
"asset_id_found": "9d4f2190-a10b-4c82-b939-77649b9ef7b5",
"data_found": {
"key": "value"
}
}
]
}
If more than one asset is provided for a batch request or the async flag is set to true, we will handle the request asynchronously. To handle asynchronous requests, we recommend using our webhooks API. To setup webhooks for handling batch decode requests, you should subscribe to the decode.success event.
If you are unable to use the webhooks, we provide an alternative approach based on polling. When we receive a batch decode request, we return a request_id. The request_id can be used with the status endpoint to check on the status of the batch decode. See the status endpoint for more information.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID"
},
{
"url": "www.path_to_png_image.com",
"mime_type": "image/png"
},
"..."
]
}
requests.post("https://api.steg.ai/decode", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID"
},
{
"url": "www.path_to_png_image.com",
"mime_type": "image/png"
},
"..."
]
};
fetch("https://api.steg.ai/decode",
method: "POST",
headers: headers ,
body: JSON.stringify(body)
)
curl --request POST "https://api.steg.ai/decode" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"assets":[{"asset_id":"EXAMPLE_ASSET_ID"},{"url":"www.path_to_png_image.com","mime_type":"image/png"},"..."]}'
{
"request_id": "EXAMPLE_REQUEST_ID"
}
This endpoint encodes any and all supported asset types. You can either encode an asset uploaded through the Steg AI upload endpoint or by using a URL. This endpoint also supports batch encoding with a limit of 50 assets per request.
Each encoded asset can have some combination of multiple visible watermarks applied and one forensic watermark applied. To apply visible watermarks, VisibleOptions objects should be added to the visible array attribute of the InternalAsset or ExternalAsset objects. These watermarks will be applied from first to last.
For forensic watermarks, only one forensic watermark can be applied to each asset. To apply a forensic watermark, a ForensicOptions object should be added to the forensic array attribute of the InternalAsset or ExternalAsset objects. The forensic watermark will be applied after any visible watermarks.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID",
"forensic": [
{
"data": {
"vendor": "Vendor A",
"use": "graphics only"
}
}
]
},
{
"url": "www.path_to_png_image.com",
"mime_type": "image/png",
"visible": [
{
"type": "repeat",
"text": "Do not share",
"direction": "horizontal"
}
]
}
],
"async": False
}
requests.post("https://api.steg.ai/encode", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID",
"forensic": [
{
"data": {
"vendor": "Vendor A",
"use": "graphics only"
}
}
]
},
{
"url": "www.path_to_png_image.com",
"mime_type": "image/png",
"visible": [
{
"type": "repeat",
"text": "Do not share",
"direction": "horizontal"
}
]
}
],
"async": false
};
fetch("https://api.steg.ai/encode",
method: "POST",
headers: headers ,
body: JSON.stringify(body)
)
curl --request POST "https://api.steg.ai/encode" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"assets":[{"asset_id":"EXAMPLE_ASSET_ID","forensic":[{"data":{"vendor":"Vendor A","use":"graphics only"}}]},{"url":"www.path_to_png_image.com","mime_type":"image/png","visible":[{"type":"repeat","text":"Do not share","direction":"horizontal"}]}],"async":false}'
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [
{
"original_asset": "EXAMPLE_ASSET_ID",
"source": "STEG",
"watermarked_asset_id": "c20007c5-fe03-4db8-b394-c874d570cdab",
"watermarked_path": "URL_TO_WATERMARKED_ASSET"
},
{
"original_asset": "www.path_to_png_image.com",
"source": "EXTERNAL",
"watermarked_asset_id": "9d4f2190-a10b-4c82-b939-77649b9ef7b5",
"watermarked_path": "URL_TO_WATERMARKED_ASSET"
}
]
}
Forensic watermarking is a technique used to embed hidden information into digital assets. These watermarks are unique to each piece of content and are designed to be robust against various forms of manipulation or alteration.
Steg AI provides the forensic attribute in the InternalAsset or ExternalAsset objects of our encode endpoint to allow you to add forensic watermarks to your assets. The forensic attribute should contain one ForensicOptions object in the array to create a forensic watermark on the asset. At this time, Steg AI only supports adding one forensic watermark per asset; so, if multiple ForensicOptions objects are in the array, only the first one is used.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID",
"forensic": [
{
"data": {
"vendor": "Vendor A",
"use": "graphics only"
}
}
]
}
]
}
requests.post("https://api.steg.ai/encode", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID",
"forensic": [
{
"data": {
"vendor": "Vendor A",
"use": "graphics only"
}
}
]
}
]
};
fetch("https://api.steg.ai/encode",
method: "POST",
headers: headers ,
body: JSON.stringify(body)
)
curl --request POST "https://api.steg.ai/encode" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"assets":[{"asset_id":"EXAMPLE_ASSET_ID","forensic":[{"data":{"vendor":"Vendor A","use":"graphics only"}}]}]}'
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": {
"assets": [
{
"original_asset": "EXAMPLE_ASSET_ID",
"source": "STEG",
"watermarked_asset_id": "c20007c5-fe03-4db8-b394-c874d570cdab",
"watermarked_path": "URL_TO_WATERMARKED_ASSET"
}
]
}
}
Visible watermarking applies a visible mask on top of the content of the asset. These watermarks intentionally spoil the content of the asset and are often used to deter unauthorized use or distribution.
Steg AI provides the visible attribute in the InternalAsset or ExternalAsset objects of our encode endpoint to allow the creation of a visible watermark on the encoded asset. The visible attribute must contain at least one VisibleOptions object in the array to create a visible watermark on the asset. The visible watermarks are applied in the order of the VisibleOptions objects in the array, with the first option in the array applied first and then the next item applied on top and so on.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID",
"visible": [
{
"type": "repeat",
"text": "Do not share",
"direction": "horizontal"
}
]
}
]
}
requests.post("https://api.steg.ai/encode", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID",
"visible": [
{
"type": "repeat",
"text": "Do not share",
"direction": "horizontal"
}
]
}
]
};
fetch("https://api.steg.ai/encode",
method: "POST",
headers: headers ,
body: JSON.stringify(body)
)
curl --request POST "https://api.steg.ai/encode" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"assets":[{"asset_id":"EXAMPLE_ASSET_ID","visible":[{"type":"repeat","text":"Do not share","direction":"horizontal"}]}]}'
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [
{
"original_asset": "EXAMPLE_ASSET_ID",
"source": "STEG",
"watermarked_asset_id": "c20007c5-fe03-4db8-b394-c874d570cdab",
"watermarked_path": "URL_TO_WATERMARKED_ASSET"
}
]
}
If more than one asset is provided for a batch request or the async flag is set to true, we will handle the request asynchronously. To handle asynchronous requests, we recommend using our webhooks API. To setup webhooks for handling batch encode requests, you should subscribe to the encode.success event.
If you are unable to use the webhooks, we provide an alternative approach based on polling. When we receive a batch encode request, we return a request_id. This request_id can be used with the status endpoint to check on the status of the batch encode. See the status endpoint for more information.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID",
"forensic": [
{
"data": {
"vendor": "Vendor A",
"use": "graphics only"
}
}
]
},
{
"url": "www.path_to_png_image.com",
"mime_type": "image/png",
"visible": [
{
"type": "repeat",
"text": "Do not share",
"direction": "horizontal"
}
]
},
"..."
]
}
requests.post("https://api.steg.ai/encode", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"assets": [
{
"asset_id": "EXAMPLE_ASSET_ID",
"forensic": [
{
"data": {
"vendor": "Vendor A",
"use": "graphics only"
}
}
]
},
{
"url": "www.path_to_png_image.com",
"mime_type": "image/png",
"visible": [
{
"type": "repeat",
"text": "Do not share",
"direction": "horizontal"
}
]
},
"..."
]
};
fetch("https://api.steg.ai/encode",
method: "POST",
headers: headers ,
body: JSON.stringify(body)
)
curl --request POST "https://api.steg.ai/encode" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"assets":[{"asset_id":"EXAMPLE_ASSET_ID","forensic":[{"data":{"vendor":"Vendor A","use":"graphics only"}}]},{"url":"www.path_to_png_image.com","mime_type":"image/png","visible":[{"type":"repeat","text":"Do not share","direction":"horizontal"}]},"..."]}'
{
"request_id": "EXAMPLE_REQUEST_ID"
}
This endpoint generates a presigned URL for you to upload your asset.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"name": "name_of_file",
"content_type": "image/png"
}
requests.post("https://api.steg.ai/upload", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"name": "name_of_file",
"content_type": "image/png"
};
fetch("https://api.steg.ai/upload",
method: "POST",
headers: headers ,
body: JSON.stringify(body)
)
curl --request POST "https://api.steg.ai/upload" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"name":"name_of_file","content_type":"image/png"}'
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [
{
"asset_id": "EXAMPLE_ASSET_ID",
"timestamp_created": "2024-03-10T17:06:48.823040",
"timestamp_expires": "2024-03-10T17:11:48.823040",
"post_to": {
"url": "PRESIGNED_URL_HERE",
"fields": "PRESIGNED_FORM_FIELDS_HERE"
}
}
]
}
After generating a presigned url, use the post_to attribute from the PresignedURL object to make a POST request to upload your file. Only one file can be uploaded per presigned URL.
import requests
with open("file_path", "rb") as file:
files = {
"file": file
}
requests.post(url=PRESIGNED_URL_HERE, files=files, data=PRESIGNED_FORM_FIELDS_HERE)
const uploadFormData = new FormData();
for (const [key, value] of PRESIGNED_FORM_FIELDS_HERE) {
uploadFormData.append(key, value);
}
// Note: Append the file object
uploadFormData.append("file", file);
fetch("PRESIGNED_URL_HERE", {
method: "POST",
body: uploadFormData
})
curl --request POST "PRESIGNED_URL_HERE" \
--form 'PRESIGNED_FORM_FIELDS_HERE' \
--form 'file=@"/path/to/image"'
This endpoint returns your history of usage of each Steg AI API endpoint. The order of returned items is chronologically from most recent to oldest. By default, each request will return a max of 25 items, but can be increased to up to 100. For requests where the response returns more than the max, we implement a pagination strategy. See our pagination section for details.
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
requests.get("https://api.steg.ai/usage", headers=headers)
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
fetch("https://api.steg.ai/usage",
method: "GET",
headers: headers
)
curl --request GET "https://api.steg.ai/usage" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here"
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [
{
"asset_id": "d051f164-b066-4702-8343-c61ba098ba63",
"timestamp": "2024-03-10T16:54:24",
"endpoint": "encode",
"status_code": 200
},
{
"asset_id": "e5c57510-d2e2-4cc8-afb4-b3ce1fa77b71",
"timestamp": "2024-03-10T17:12:15",
"endpoint": "encode",
"status_code": 200
},
{
"asset_id": null,
"ts": "2024-03-10T117:27:58",
"endpoint": "encode",
"status_code": 400
},
. . .
],
"next_key": "EXAMPLE_PAGE_KEY"
}
Webhooks are a way for one application to notify another about specific events or updates automatically. Instead of actively checking for changes, your application subscribes to certain events, and when those events occur, a notification (HTTP POST request) is sent to a predefined URL.
A webhook event refers to a specific occurrence that triggers the delivery of a notification to a designated URL.
encode.success | Triggers after an encoding is finished. |
encode.failure | Triggers after an encoding fails. |
decode.success | Triggers after a decoding is finished. |
decode.failure | Triggers after a decoding fails. |
All webhook events received by your URL from Steg AI will have a timestamp and signature in the header: X-StegAI-Signature. This is used to verify that the request came from Steg AI. Check out our how-to guide on how to verify the signature. The signature is generated by concatenating the timestamp, a dot (’.’), and the JSON-encoded payload into a string. This string is then hashed with the secret key using HMAC SHA256.
The secret key for a webhook is generated when you first create the webhook subscription using POST /webhook. The designated URL will receive the secret key, and it is recommended that you save this secret key into your system. Your URL must return a status code: 200; otherwise, we will retry sending the event.
POST /webhook-endpoint HTTP/1.1
Host: example.com
Content-Type: application/json
X-StegAI-Signature: t=1611144604,s=6b7f9dc426e59fbc186502ea33f272fbca14a0d169f237d3575c2ae0befb2704
{
"event_type": "encode.success",
"asset_id": "eabb1b2c-e380-409b-a29b-62608aa695a8"
}
If your URL does not return a 200 status code, we will retry sending the event using an exponential backoff policy. This policy increases the delay between each attempt we make to send the webhook event to your URL. After the initial failure, we will retry after 2, 4, 8, and 16 hours. If after the 4th retry attempt your URL still returns a non-200 status code, we will delete the webhook message and mark it as a failure.
This endpoint returns a list of event types that you can subscribe to. The values are used in creating a webhook subscription.
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
requests.get("https://api.steg.ai/webhook/events", headers=headers)
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
fetch("https://api.steg.ai/webhook/events",
method: "GET",
headers: headers
)
curl --request GET "https://api.steg.ai/webhook/events" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here"
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": {
"events": ["encode.success", "encode.failure", "decode.success", "decode.failure"]
}
}
This endpoint returns all the webhooks you have subscribed to.
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
requests.get("https://api.steg.ai/webhook", headers=headers)
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
fetch("https://api.steg.ai/webhook",
method: "GET",
headers: headers
)
curl --request GET "https://api.steg.ai/webhook" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here"
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": {
"webhooks": [
{
"id": "54244b6a-87c2-4de5-87c6-ccf77ca390c2",
"event_type": "encode.success",
"url": "https://yourdomain.com/custom_endpoint"
}
]
}
}
This endpoint creates a webhook subscription. Webhook subscriptions support the creation of one event
at a time in the body.
This endpoint sends a POST request to your URL with the following header: X-Hook-Secret: secret_key. We recommend you save the secret key into your database. Your URL will need to return the same header value and a status code: 200 to successfully create the webhook subscription.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"event": "encode.success",
"url": "https://yourdomain.com/custom_endpoint"
}
requests.post("https://api.steg.ai/webhook", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"event": "encode.success",
"url": "https://yourdomain.com/custom_endpoint"
};
fetch("https://api.steg.ai/webhook",
method: "POST",
headers: headers ,
body: JSON.stringify(body)
)
curl --request POST "https://api.steg.ai/webhook" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"event":"encode.success","url":"https://yourdomain.com/custom_endpoint"}'
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": {
"id": "54244b6a-87c2-4de5-87c6-ccf77ca390c2",
"event_type": "encode.success",
"url": "https://yourdomain.com/custom_endpoint"
}
}
This endpoint deletes a webhook subscription.
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
requests.delete("https://api.steg.ai/webhook/:id", headers=headers)
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
fetch("https://api.steg.ai/webhook/:id",
method: "DELETE",
headers: headers
)
curl --request DELETE "https://api.steg.ai/webhook/:id" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here"
{
"request_id": "EXAMPLE_REQUEST_ID",
}
This endpoint returns all the assets and associated data that you have uploaded. The order of returned assets is based on their id. By default, each request will return a max of 25 items, but can be increased to up to 100. For requests where the response returns more than the max, we implement a pagination strategy. See our pagination section for details.
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
requests.get("https://api.steg.ai/asset", headers=headers)
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
fetch("https://api.steg.ai/asset",
method: "GET",
headers: headers
)
curl --request GET "https://api.steg.ai/asset" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here"
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [
{
"asset_id": "3c9927b9-e7f0-446a-8be1-db607a372b0c",
"asset_type": "image",
"content_type": "image/png",
"c2pa_path": "URL_TO_C2PA_MANIFEST",
"file_path": "URL_TO_ASSET",
"file_size": 55391,
"is_watermarked": true,
"name": "3c9927b9-e7f0-446a-8be1-db607a372b0c.png",
"original_asset": null,
"source": "steg",
"thumbnail": "URL_TO_ASSET_THUMBNAIL",
"version": 1,
"watermark_data": {
"key": "value"
}
},
{
"asset_id": "fdb0de3c-a70b-4ea1-97e0-39d07ff2e925",
"asset_type": "image",
"content_type": "image/png",
"c2pa_path": null,
"file_path": "URL_TO_ASSET",
"file_size": 55391,
"is_watermarked": false,
"name": "example.png",
"original_asset": null,
"source": "steg",
"thumbnail": "URL_TO_ASSET_THUMBNAIL",
"version": 1,
"watermark_data": null
}
. . .
],
"next_key": "EXAMPLE_PAGE_KEY"
}
This endpoint returns the data of a specific asset.
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
requests.get("https://api.steg.ai/asset/:asset_id", headers=headers)
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
fetch("https://api.steg.ai/asset/:asset_id",
method: "GET",
headers: headers
)
curl --request GET "https://api.steg.ai/asset/:asset_id" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here"
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [
{
"asset_id": "3c9927b9-e7f0-446a-8be1-db607a372b0c",
"asset_type": "image",
"content_type": "image/png",
"c2pa_path": "URL_TO_C2PA_MANIFEST",
"file_path": "URL_TO_ASSET",
"file_size": 55391,
"is_watermarked": true,
"name": "3c9927b9-e7f0-446a-8be1-db607a372b0c.png",
"original_asset": null,
"source": "steg",
"thumbnail": "URL_TO_ASSET_THUMBNAIL",
"version": 1,
"watermark_data": {
"key": "value"
}
}
]
}
This endpoint deletes a list of assets.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"assets": [
"EXAMPLE_MEDIA_ID"
]
}
requests.delete("https://api.steg.ai/asset", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"assets": [
"EXAMPLE_MEDIA_ID"
]
};
fetch("https://api.steg.ai/asset",
method: "DELETE",
headers: headers ,
body: JSON.stringify(body)
)
curl --request DELETE "https://api.steg.ai/asset" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"assets":["EXAMPLE_MEDIA_ID"]}'
{
"request_id": "EXAMPLE_REQUEST_ID",
}
This endpoint delete an asset.
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
requests.delete("https://api.steg.ai/asset/:asset_id", headers=headers)
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
fetch("https://api.steg.ai/asset/:asset_id",
method: "DELETE",
headers: headers
)
curl --request DELETE "https://api.steg.ai/asset/:asset_id" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here"
{
"request_id": "EXAMPLE_REQUEST_ID",
}
This endpoint updates a specific asset. Any parameter in Request Body listed below can be updated.
import json
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
body = {
"name": "new_name.png",
"data": {
"new_key": "new_value"
}
}
requests.patch("https://api.steg.ai/asset/:asset_id", headers=headers, body=json.dumps(body))
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
const body = {
"name": "new_name.png",
"data": {
"new_key": "new_value"
}
};
fetch("https://api.steg.ai/asset/:asset_id",
method: "PATCH",
headers: headers ,
body: JSON.stringify(body)
)
curl --request PATCH "https://api.steg.ai/asset/:asset_id" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here" \
--data '{"name":"new_name.png","data":{"new_key":"new_value"}}'
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [
{
"asset_id": "3c9927b9-e7f0-446a-8be1-db607a372b0c",
"asset_type": "image",
"content_type": "image/png",
"c2pa_path": "URL_TO_C2PA_MANIFEST",
"file_path": "URL_TO_ASSET",
"file_size": 55391,
"is_watermarked": true,
"name": "new_name.png",
"original_asset": null,
"source": "steg",
"thumbnail": "URL_TO_ASSET_THUMBNAIL",
"version": 2,
"watermark_data": {
"new_key": "new_value"
}
}
]
}
This endpoint allows a user to get the status of a request.
import requests
headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
}
requests.get("https://api.steg.ai/status/:request_id", headers=headers)
const headers = {
"Content-Type": "application/json",
"x-api-key": "api_key_here"
};
fetch("https://api.steg.ai/status/:request_id",
method: "GET",
headers: headers
)
curl --request GET "https://api.steg.ai/status/:request_id" \
--header "Content-Type: application/json" \
--header "x-api-key: api_key_here"
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [{
"status": "in progress",
"request_type": "encode",
"request_data": null
}]
}
{
"request_id": "EXAMPLE_REQUEST_ID",
"data": [{
"status": "completed",
"request_type": "encode",
"request_data": [
{
"original_asset": "EXAMPLE_ASSET_ID",
"source": "STEG",
"watermarked_asset_id": "c20007c5-fe03-4db8-b394-c874d570cdab",
"watermarked_path": "URL_TO_WATERMARKED_ASSET"
},
". . ."
]
}]
}
To generate a presigned url, the content_type parameter needs to be set to one of the following values:
This section describes the most common flows to support developers getting started with the Steg AI API.
In this guide, we will show you how to apply a forensic watermark to an image of your choosing using python and the Steg AI API.
import json
import requests
BASE_URL = "https://api.steg.ai"
APIKEY = "api_key_here"
headers = {
"Content-Type": "application/json",
"x-api-key": APIKEY
}
# Step 1: Generate presigned URL
payload = {
"name": "unencoded_logo.png",
"content_type": "image/png"
}
response = requests.post(f"{BASE_URL}/upload", headers=headers, data=json.dumps(payload))
post_to_fields = response.json().get("data")[0].get("post_to")
asset_id = response.json().get("data")[0].get("asset_id")
# Step 2: Upload the image to the presigned URL
with open("unencoded_logo.png", "rb") as file:
url = post_to_fields.get("url")
form_data = post_to_fields.get("fields")
files = {
"file": file
}
requests.post(url=url, files=files, data=form_data)
# Step 3: Start the process to encode the image
payload = {
"assets": [{
"asset_id": asset_id,
"forensic": [{
"data": {
"message": "this is an example image that's been watermarked"
"location": "New York, NY",
"ip_address": "192.158.1.38"
}
}]
}]
}
response = requests.post(f"{BASE_URL}/encode", headers=headers, data=json.dumps(payload))
watermarked_path = response.json().get("data")[0].get("watermarked_path")
# Step 4: Download the watermarked image
response = requests.get(url=watermarked_path)
with open("encoded_logo.png", 'wb') as f:
f.write(response.content)
In this guide, we will show you how to apply a visible watermark to an image of your choosing using python and the Steg AI API. The visible watermark will say “Do not share” repeatedly across the image in the horizontal direction.
import json
import requests
BASE_URL = "https://api.steg.ai"
APIKEY = "api_key_here"
headers = {
"Content-Type": "application/json",
"x-api-key": APIKEY
}
# Step 1: Generate presigned URL
payload = {
"name": "unencoded_logo.png",
"content_type": "image/png"
}
response = requests.post(f"{BASE_URL}/upload", headers=headers, data=json.dumps(payload))
post_to_fields = response.json().get("data")[0].get("post_to")
asset_id = response.json().get("data")[0].get("asset_id")
# Step 2: Upload the image to the presigned URL
with open("unencoded_logo.png", "rb") as file:
url = post_to_fields.get("url")
form_data = post_to_fields.get("fields")
files = {
"file": file
}
requests.post(url=url, files=files, data=form_data)
# Step 3: Start the process to encode the image with a visible watermark
payload = {
"assets": [{
"asset_id": asset_id,
"visible": [{
"type": "repeat",
"text": "Do not share",
"direction": "horizontal"
}]
}]
}
response = requests.post(f"{BASE_URL}/encode", headers=headers, data=json.dumps(payload))
watermarked_path = response.json().get("data")[0].get("watermarked_path")
# Step 4: Download the watermarked image
response = requests.get(url=watermarked_path)
with open("encoded_logo.png", 'wb') as f:
f.write(response.content)
In this guide, we will show how to decode the watermarked image from How to Forensic Watermark an Image using python and the Steg AI API. When successfully decoded, the image will contain data with the following message: “this is an example image that’s been watermarked”.
import json
import requests
BASE_URL = "https://api.steg.ai"
APIKEY = "api_key_here"
headers = {
"Content-Type": "application/json",
"x-api-key": APIKEY
}
# Step 1: Generate presigned URL
payload = {
"name": "encoded_logo.png",
"content_type": "image/png"
}
response = requests.post(f"{BASE_URL}/upload", headers=headers, data=json.dumps(payload))
post_to_fields = response.json().get("data")[0].get("post_to")
asset_id = response.json().get("data")[0].get("asset_id")
# Step 2: Upload the image to the presigned URL
# Using the watermarked image from "How to Forensic Watermark an Image"
with open("encoded_logo.png", "rb") as file:
url = post_to_fields.get("url")
form_data = post_to_fields.get("fields")
files = {
"file": file
}
requests.post(url=url, files=files, data=form_data)
# Step 3: Start the process to decode the image
payload = {
"assets": [{
"asset_id": asset_id
}]
}
response = requests.post(f"{BASE_URL}/decode", headers=headers, data=json.dumps(payload))
# Step 4: Retrieve the data of the decoded image
data_found = response.json().get("data")[0].get("data_found")
print(data_found.get("message"))
In this guide, we will show how to subscribe to Steg AI webhooks using python and the Steg AI API.
import json
import requests
BASE_URL = "https://api.steg.ai"
APIKEY = "api_key_here"
headers = {
"Content-Type": "application/json",
"x-api-key": APIKEY
}
payload = {
"event": "encode.success",
"url": "https://yourdomain.com/custom_endpoint"
}
requests.post(f"{BASE_URL}/webhook", headers=headers, data=json.dumps(payload))
# If you want your URL to handle "decode.success" events too, then another request needs to be made:
payload = {
"event": "decode.success",
"url": "https://yourdomain.com/custom_endpoint"
}
requests.post(f"{BASE_URL}/webhook", headers=headers, data=json.dumps(payload))
We are using Flask as an example server to handle the defined URL from the previous step. Be sure to save the secret key in your system. You must return the same header: X-Hook-Secret and status code: 200 in the response.
import base64
import hashlib
import hmac
import json
import os
from flask import Flask, request, jsonify
secret_key = os.getenv("stegai_secret_key")
api_key = os.getenv("stegai_api_key")
app = Flask(__name__)
@app.route('/custom_endpoint', methods=['POST'])
def handle_webhook():
try:
# Handle creating the subscription for the first time
if request.headers.get("X-Hook-Secret"):
# Save the secret key value in systtem
# Creating a JSON response with status code 200 and custom header 'X-Hook-Secret'
response = jsonify()
response.status_code = 200
# X-Hook-Secret must return the same value as the request
response.headers['X-Hook-Secret'] = request.headers.get("X-Hook-Secret")
return response
# Handle incoming webhook events
elif request.headers.get("X-StegAI-Signature"):
# Verify the signature
timestamp_prefixed, signature_hash_prefixed = request.headers.get("X-StegAI-Signature").split(",")
# Remove `=` from the string
timestamp = timestamp_prefixed.split('=')[0]
expected_signature = signature_hash_prefixed.split('=')[0]
request_data = request.json
# Calculate the signature
signature_str = f"{timestamp}.{request_data}".encode('utf-8')
# This is the actual signature generated using HMAC-SHA256. It uses the secret key to hash the signature_str
calculated_signature = hmac.new(secret_key.encode('utf-8'), signature_str, hashlib.sha256).hexdigest()
# Verify the incoming the signature and the signature calculated
if calculated_signature == expected_signature:
# Do some action
# for example downloading the encoded version of the asset
asset_id = request_data.get("asset_id")
headers = {
"Content-Type" : "application/json",
"x-api-key" : api_key
}
response = requests.get(f"https://api.steg.ai/asset/{asset_id}", headers=headers)
return jsonify(), 200
return jsonify(), 500
except Exception as e:
return jsonify(), 500
if __name__ == '__main__':
app.run(debug=False, port=5000)