> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adclear.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Upload a file, create a promotion, and get your first compliance evaluation back in under 10 minutes.

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.

<Note>
  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](/developer/authentication)).
</Note>

<Steps>
  <Step title="Set your credentials">
    Every request needs your API key and a stable identifier for the acting user in your system.

    <CodeGroup>
      ```bash curl theme={null}
      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"
      ```

      ```typescript TypeScript theme={null}
      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",
      };
      ```

      ```python Python theme={null}
      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",
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Fetch reference IDs">
    Classification drives which rules apply. Fetch the IDs for one product, channel, and jurisdiction. See [Reference data](/developer/reference-data) for all four endpoints.

    <CodeGroup>
      ```bash curl theme={null}
      curl -s "$API_BASE/v1/products" \
        -H "Authorization: Bearer $ADCLEAR_API_KEY" \
        -H "X-External-User-ID: $USER_ID"
      # → { "products": [ { "id": "...", "name": "..." } ], "correlationId": "..." }
      ```

      ```typescript TypeScript theme={null}
      const res = await fetch(`${API_BASE}/v1/products`, { headers });
      const { products } = await res.json();
      const productId = products[0].id;
      ```

      ```python Python theme={null}
      res = requests.get(f"{API_BASE}/v1/products", headers=headers)
      product_id = res.json()["products"][0]["id"]
      ```
    </CodeGroup>
  </Step>

  <Step title="Upload a file">
    Initiate the upload, then send the file in a single `PUT` (small files) or several chunks. See [File upload](/developer/file-upload) for chunking and resume.

    <CodeGroup>
      ```bash curl theme={null}
      # 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
      ```

      ```typescript TypeScript theme={null}
      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,
      });
      ```

      ```python Python theme={null}
      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)
      ```
    </CodeGroup>
  </Step>

  <Step title="Create a promotion">
    Combine the upload with your classification. See [Creating promotions](/developer/promotions) for every field and for text promotions.

    <CodeGroup>
      ```bash curl theme={null}
      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": "..." }
      ```

      ```typescript TypeScript theme={null}
      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();
      ```

      ```python Python theme={null}
      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"]
      ```
    </CodeGroup>

    <Note>A `409` means an upload is still processing. Retry with back-off. See [Creating promotions](/developer/promotions#handling-upload-conflicts).</Note>
  </Step>

  <Step title="Trigger the evaluation">
    Evaluation runs asynchronously and returns immediately with `202 Accepted`.

    <CodeGroup>
      ```bash curl theme={null}
      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": "..." }
      ```

      ```typescript TypeScript theme={null}
      await fetch(`${API_BASE}/v1/promotions/${promotionId}/versions/${versionId}/evaluate`,
        { method: "POST", headers });
      ```

      ```python Python theme={null}
      requests.post(f"{API_BASE}/v1/promotions/{promotion_id}/versions/{version_id}/evaluate", headers=headers)
      ```
    </CodeGroup>
  </Step>

  <Step title="Get the result">
    Poll until the aggregate `status` is `succeeded` or `failed`. Each result carries the findings for one file. See [Evaluation](/developer/evaluation) for the full response shape.

    <CodeGroup>
      ```bash curl theme={null}
      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": "..." }
      ```

      ```typescript TypeScript theme={null}
      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)");
      ```

      ```python Python theme={null}
      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)")
      ```
    </CodeGroup>
  </Step>
</Steps>

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="bolt" href="/developer/webhooks">
    Receive results automatically instead of polling, and verify signatures.
  </Card>

  <Card title="Errors & rate limits" icon="triangle-exclamation" href="/developer/errors">
    Handle the error envelope, status codes, and rate limits.
  </Card>
</CardGroup>
