Skip to main content
This walks the full happy path: authenticate, fetch reference IDs, upload a file, create a promotion, trigger an evaluation, and read the result. Each step links to the page with the full detail.
You need an API key (provided during onboarding) and a file to test with. Run against staging first by swapping the hosts below for their -staging equivalents (see Authentication).
1

Set your credentials

Every request needs your API key and a stable identifier for the acting user in your system.
export ADCLEAR_API_KEY="your-api-key"
export API_BASE="https://public-api.adclear.ai"
export FILES_BASE="https://files.adclear.ai"
export USER_ID="your-internal-user-id"
const API_KEY = process.env.ADCLEAR_API_KEY!;
const API_BASE = "https://public-api.adclear.ai";
const FILES_BASE = "https://files.adclear.ai";
const headers = {
  Authorization: `Bearer ${API_KEY}`,
  "X-External-User-ID": "your-internal-user-id",
  "Content-Type": "application/json",
};
import os
API_KEY = os.environ["ADCLEAR_API_KEY"]
API_BASE = "https://public-api.adclear.ai"
FILES_BASE = "https://files.adclear.ai"
headers = {
    "Authorization": f"Bearer {API_KEY}",
    "X-External-User-ID": "your-internal-user-id",
    "Content-Type": "application/json",
}
2

Fetch reference IDs

Classification drives which rules apply. Fetch the IDs for one product, channel, and jurisdiction. See Reference data for all four endpoints.
curl -s "$API_BASE/v1/products" \
  -H "Authorization: Bearer $ADCLEAR_API_KEY" \
  -H "X-External-User-ID: $USER_ID"
# → { "products": [ { "id": "...", "name": "..." } ], "correlationId": "..." }
const res = await fetch(`${API_BASE}/v1/products`, { headers });
const { products } = await res.json();
const productId = products[0].id;
res = requests.get(f"{API_BASE}/v1/products", headers=headers)
product_id = res.json()["products"][0]["id"]
3

Upload a file

Initiate the upload, then send the file in a single PUT (small files) or several chunks. See File upload for chunking and resume.
# Initiate
curl -s -X POST "$FILES_BASE/v1/uploads" \
  -H "Authorization: Bearer $ADCLEAR_API_KEY" \
  -H "X-External-User-ID: $USER_ID" \
  -H "Content-Type: application/json" \
  -d '{ "fileName": "ad.pdf", "fileSize": 2048576, "contentType": "application/pdf" }'
# → { "uploadId": "...", "uploadUrl": "/v1/uploads/...", "maxChunkSize": 52428800 }

# Send the bytes
curl -s -X PUT "$FILES_BASE/v1/uploads/<uploadId>" \
  -H "Authorization: Bearer $ADCLEAR_API_KEY" \
  -H "Content-Type: application/pdf" \
  -H "Content-Range: bytes 0-2048575/2048576" \
  --data-binary @ad.pdf
const init = await fetch(`${FILES_BASE}/v1/uploads`, {
  method: "POST",
  headers,
  body: JSON.stringify({ fileName: "ad.pdf", fileSize: bytes.length, contentType: "application/pdf" }),
});
const { uploadId } = await init.json();

await fetch(`${FILES_BASE}/v1/uploads/${uploadId}`, {
  method: "PUT",
  headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/pdf",
             "Content-Range": `bytes 0-${bytes.length - 1}/${bytes.length}` },
  body: bytes,
});
data = open("ad.pdf", "rb").read()
init = requests.post(f"{FILES_BASE}/v1/uploads", headers=headers,
    json={"fileName": "ad.pdf", "fileSize": len(data), "contentType": "application/pdf"})
upload_id = init.json()["uploadId"]

requests.put(f"{FILES_BASE}/v1/uploads/{upload_id}",
    headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/pdf",
             "Content-Range": f"bytes 0-{len(data)-1}/{len(data)}"},
    data=data)
4

Create a promotion

Combine the upload with your classification. See Creating promotions for every field and for text promotions.
curl -s -X POST "$API_BASE/v1/promotions" \
  -H "Authorization: Bearer $ADCLEAR_API_KEY" \
  -H "X-External-User-ID: $USER_ID" \
  -H "Content-Type: application/json" \
  -d '{ "uploadIds": ["<uploadId>"], "fileFormat": "pdf", "promotionName": "Summer Campaign",
        "channelIds": ["<channelId>"], "productIds": ["<productId>"], "jurisdictionId": "<jurisdictionId>" }'
# → 201 { "promotionId": "...", "versionId": "...", "version": 1, "correlationId": "..." }
const res = await fetch(`${API_BASE}/v1/promotions`, {
  method: "POST", headers,
  body: JSON.stringify({ uploadIds: [uploadId], fileFormat: "pdf", promotionName: "Summer Campaign",
    channelIds: [channelId], productIds: [productId], jurisdictionId }),
});
const { promotionId, versionId } = await res.json();
res = requests.post(f"{API_BASE}/v1/promotions", headers=headers, json={
    "uploadIds": [upload_id], "fileFormat": "pdf", "promotionName": "Summer Campaign",
    "channelIds": [channel_id], "productIds": [product_id], "jurisdictionId": jurisdiction_id})
promotion_id, version_id = res.json()["promotionId"], res.json()["versionId"]
A 409 means an upload is still processing. Retry with back-off. See Creating promotions.
5

Trigger the evaluation

Evaluation runs asynchronously and returns immediately with 202 Accepted.
curl -s -X POST "$API_BASE/v1/promotions/<promotionId>/versions/<versionId>/evaluate" \
  -H "Authorization: Bearer $ADCLEAR_API_KEY" \
  -H "X-External-User-ID: $USER_ID"
# → 202 { "evaluationId": "...", "status": "processing", "correlationId": "..." }
await fetch(`${API_BASE}/v1/promotions/${promotionId}/versions/${versionId}/evaluate`,
  { method: "POST", headers });
requests.post(f"{API_BASE}/v1/promotions/{promotion_id}/versions/{version_id}/evaluate", headers=headers)
6

Get the result

Poll until the aggregate status is succeeded or failed. Each result carries the findings for one file. See Evaluation for the full response shape.
curl -s "$API_BASE/v1/promotions/<promotionId>/versions/<versionId>/evaluation" \
  -H "Authorization: Bearer $ADCLEAR_API_KEY" \
  -H "X-External-User-ID: $USER_ID"
# → { "status": "succeeded", "results": [ { "result": { "issues": [ ... ] } } ], "correlationId": "..." }
const poll = await fetch(
  `${API_BASE}/v1/promotions/${promotionId}/versions/${versionId}/evaluation`, { headers });
const data = await poll.json();
if (data.status === "succeeded")
  for (const r of data.results) console.log(r.fileName, r.result.issues.length, "issue(s)");
poll = requests.get(
    f"{API_BASE}/v1/promotions/{promotion_id}/versions/{version_id}/evaluation", headers=headers)
data = poll.json()
if data["status"] == "succeeded":
    for r in data["results"]:
        print(r["fileName"], len(r["result"]["issues"]), "issue(s)")

Next steps

Webhooks

Receive results automatically instead of polling, and verify signatures.

Errors & rate limits

Handle the error envelope, status codes, and rate limits.