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

# Quickstart

> Get up and running with the Integrations API in minutes

## Prerequisites

* A MediaMagic workspace and API key
* curl, Python, or Node.js installed
* A media file to upload (video, audio, or document)

## Step 1: Generate an upload URL

First, generate a presigned URL for uploading your file:

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.northell.io/nhl/prod/mediamagic-verify-integrations/api/uploads/url \
    -H "X-API-Key: your-api-key-here" \
    -H "Content-Type: application/json" \
    -d '{
      "filename": "campaign-video.mp4",
      "contentType": "video/mp4"
    }'
  ```

  ```python requests theme={null}
  import requests

  API_BASE = "https://api.northell.io/nhl/prod/mediamagic-verify-integrations"

  response = requests.post(
      f"{API_BASE}/api/uploads/url",
      headers={"X-API-Key": "your-api-key-here"},
      json={
          "filename": "campaign-video.mp4",
          "contentType": "video/mp4",
      },
  )

  result = response.json()
  print(f"Upload URL: {result['uploadUrl']}")
  print(f"Blob path: {result['blobPath']}")
  ```

  ```javascript node theme={null}
  const fetch = require("node-fetch");

  const API_BASE = "https://api.northell.io/nhl/prod/mediamagic-verify-integrations";

  const response = await fetch(`${API_BASE}/api/uploads/url`, {
    method: "POST",
    headers: {
      "X-API-Key": "your-api-key-here",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      filename: "campaign-video.mp4",
      contentType: "video/mp4"
    })
  });

  const result = await response.json();
  console.log("Upload URL:", result.uploadUrl);
  console.log("Blob path:", result.blobPath);
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "uploadUrl": "https://<account>.blob.core.windows.net/assets/<path>?<sas>",
  "blobPath": "660e8400-e29b-41d4-a716-446655440000/campaign-video.mp4",
  "expiresAt": "2026-06-03T13:00:00Z"
}
```

<Note>
  The presigned URL expires after one hour. Request it shortly before you upload, then `PUT` the file straight to Azure Blob Storage.
</Note>

## Step 2: Upload your file

Use the presigned URL to upload your file directly to Azure Blob Storage:

<CodeGroup>
  ```bash curl theme={null}
  curl -X PUT "https://<account>.blob.core.windows.net/assets/<path>?<sas>" \
    -H "x-ms-blob-type: BlockBlob" \
    --data-binary @campaign-video.mp4
  ```

  ```python requests theme={null}
  upload_url = result["uploadUrl"]

  with open("campaign-video.mp4", "rb") as f:
      requests.put(
          upload_url,
          headers={"x-ms-blob-type": "BlockBlob"},
          data=f,
      )
  ```

  ```javascript node theme={null}
  const fs = require("fs");

  const uploadUrl = result.uploadUrl;
  const fileData = fs.readFileSync("campaign-video.mp4");

  await fetch(uploadUrl, {
    method: "PUT",
    headers: {
      "x-ms-blob-type": "BlockBlob",
      "Content-Length": fileData.length
    },
    body: fileData
  });
  ```
</CodeGroup>

## Step 3: Create a submission

Now create a submission with your uploaded asset. `sidekickIds` is required — at least one sidekick must run. Fetch the IDs available to your workspace from [List available sidekicks](/sidekicks/list-sidekicks).

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.northell.io/nhl/prod/mediamagic-verify-integrations/api/submissions \
    -H "X-API-Key: your-api-key-here" \
    -H "Content-Type: application/json" \
    -d '{
      "assets": [
        { "blobPath": "660e8400-e29b-41d4-a716-446655440000/campaign-video.mp4" }
      ],
      "sidekickIds": ["<sidekick-id>"]
    }'
  ```

  ```python requests theme={null}
  response = requests.post(
      f"{API_BASE}/api/submissions",
      headers={"X-API-Key": "your-api-key-here"},
      json={
          "assets": [
              {"blobPath": result["blobPath"]}
          ],
          "sidekickIds": ["<sidekick-id>"],
      },
  )

  submission = response.json()
  print(f"Submission ID: {submission['submissionId']}")
  ```

  ```javascript node theme={null}
  const response = await fetch(`${API_BASE}/api/submissions`, {
    method: "POST",
    headers: {
      "X-API-Key": "your-api-key-here",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      assets: [
        { blobPath: result.blobPath }
      ],
      sidekickIds: ["<sidekick-id>"]
    })
  });

  const submission = await response.json();
  console.log("Submission ID:", submission.submissionId);
  ```
</CodeGroup>

<Note>
  Asset objects only accept `blobPath` (and an optional `previousSubmissionId` for versioning). Do not send `filename` or `contentType` here — those come from the upload step.
</Note>

Response (`201 Created`):

```json theme={null}
{
  "submissionId": "550e8400-e29b-41d4-a716-446655440000",
  "workflowId": "asset-processing-...",
  "ablyChannel": "submission:550e8400-...",
  "status": "submitted",
  "assets": [
    { "assetId": "a1b2", "versionGroupId": "g1", "versionNumber": 1 }
  ]
}
```

## Step 4: Check the status

Poll the submission endpoint to see when processing completes. Note there is no `/status` suffix — you read the status from the submission resource itself:

<CodeGroup>
  ```bash curl theme={null}
  curl -H "X-API-Key: your-api-key-here" \
    https://api.northell.io/nhl/prod/mediamagic-verify-integrations/api/submissions/550e8400-e29b-41d4-a716-446655440000
  ```

  ```python requests theme={null}
  submission_id = submission["submissionId"]

  response = requests.get(
      f"{API_BASE}/api/submissions/{submission_id}",
      headers={"X-API-Key": "your-api-key-here"},
  )

  status = response.json()
  print(f"Status: {status['status']} ({status['progressPercent']}%)")
  for asset in status["assets"]:
      print(f"  {asset['assetId']}: issues={asset['issueCount']}")
  ```

  ```javascript node theme={null}
  const submissionId = submission.submissionId;

  const response = await fetch(
    `${API_BASE}/api/submissions/${submissionId}`,
    { headers: { "X-API-Key": "your-api-key-here" } }
  );

  const status = await response.json();
  console.log(`Status: ${status.status} (${status.progressPercent}%)`);
  status.assets.forEach(asset => {
    console.log(`  ${asset.assetId}: issues=${asset.issueCount}`);
  });
  ```
</CodeGroup>

Status response (`200 OK`):

```json theme={null}
{
  "submissionId": "550e8400-...",
  "workflowId": "asset-processing-...",
  "workspaceId": "660e8400-...",
  "status": "processing",
  "progressPercent": 40,
  "createdAt": "2026-06-03T12:00:00Z",
  "completedAt": null,
  "errorMessage": null,
  "assets": [
    {
      "assetId": "a1b2",
      "versionGroupId": "g1",
      "versionNumber": 1,
      "issueCount": null,
      "errorMessage": null,
      "errorType": null,
      "isRetryable": false,
      "retryCount": 0
    }
  ],
  "isRetryable": false
}
```

<Tip>
  `status` is one of `uploading`, `submitted`, `queued`, `processing`, `complete`, `partial`, or `failed`. Keep polling until it reaches a terminal `complete`, `partial`, or `failed` state, then stop (`queued` is non-terminal — it means the submission is waiting for a free processing slot). For production workloads, prefer [webhooks](/guides/webhook-subscriptions) over tight polling.
</Tip>

## Step 5: Get the results

Once the asset reaches `complete`, retrieve its result by fetching the asset directly (no `/results` suffix):

<CodeGroup>
  ```bash curl theme={null}
  curl -H "X-API-Key: your-api-key-here" \
    https://api.northell.io/nhl/prod/mediamagic-verify-integrations/api/submissions/550e8400-.../assets/a1b2
  ```

  ```python requests theme={null}
  asset_id = status["assets"][0]["assetId"]

  response = requests.get(
      f"{API_BASE}/api/submissions/{submission_id}/assets/{asset_id}",
      headers={"X-API-Key": "your-api-key-here"},
  )

  asset = response.json()
  print(f"Status: {asset['status']}, issues: {asset['issueCount']}")
  for issue in asset["issues"]:
      print(f"  [{issue['severity']}] {issue['ruleCode']}: {issue['summary']}")
  ```

  ```javascript node theme={null}
  const assetId = status.assets[0].assetId;

  const response = await fetch(
    `${API_BASE}/api/submissions/${submissionId}/assets/${assetId}`,
    { headers: { "X-API-Key": "your-api-key-here" } }
  );

  const asset = await response.json();
  console.log(`Status: ${asset.status}, issues: ${asset.issueCount}`);
  asset.issues.forEach(issue => {
    console.log(`  [${issue.severity}] ${issue.ruleCode}: ${issue.summary}`);
  });
  ```
</CodeGroup>

Asset result (`200 OK`):

```json theme={null}
{
  "assetId": "a1b2",
  "submissionId": "550e8400-...",
  "filename": "campaign-video.mp4",
  "mimeType": "video/mp4",
  "status": "complete",
  "issueCount": 2,
  "versionNumber": 1,
  "versionGroupId": "g1",
  "issues": [
    {
      "id": "i1",
      "referenceNumber": 1,
      "ruleCode": "CAP_8.4",
      "summary": "Unsubstantiated pricing claim",
      "severity": "MAJOR",
      "status": "OPEN"
    }
  ]
}
```

## What's next?

* Read about [Core Concepts](/concepts/submissions) to understand the data model
* Check out [File Upload Guide](/guides/file-upload) for handling large files
* Learn about [Webhooks](/guides/webhook-subscriptions) for real-time updates
* See [Error Handling](/guides/error-handling) for common issues
