> ## 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.

# Poll status guide

> Check submission progress and retrieve results

## Status polling pattern

The typical polling flow looks like this:

<Steps>
  <Step title="Create submission">
    POST to create a submission and read the `submissionId`.
  </Step>

  <Step title="Poll status">
    GET the submission at regular intervals.
  </Step>

  <Step title="Check completion">
    When the submission is `complete` or `failed`, stop polling.
  </Step>

  <Step title="Retrieve results">
    Fetch each asset's result and its issues or clustered topics.
  </Step>
</Steps>

## Getting submission status

Use `GET /api/integrations/submissions/{submission_id}` — there is no `/status` suffix.

<CodeGroup>
  ```bash curl theme={null}
  curl -H "X-API-Key: your-api-key-here" \
    https://mm-midmarket-integrations-api-preview.azurewebsites.net/api/integrations/submissions/550e8400-e29b-41d4-a716-446655440000
  ```

  ```python theme={null}
  import requests

  API_BASE = "https://mm-midmarket-integrations-api-preview.azurewebsites.net"
  submission_id = "550e8400-e29b-41d4-a716-446655440000"

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

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

  ```javascript theme={null}
  const API_BASE = "https://mm-midmarket-integrations-api-preview.azurewebsites.net";
  const submissionId = "550e8400-e29b-41d4-a716-446655440000";

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

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

Response:

```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
}
```

Per-asset failures are reported as flat fields — `errorMessage`, `errorType`, `isRetryable`, `retryCount` — not a nested error object. The terminal submission statuses are `complete` and `failed`.

## Polling strategy

### Basic polling loop

<CodeGroup>
  ```python theme={null}
  import time
  import requests

  API_BASE = "https://mm-midmarket-integrations-api-preview.azurewebsites.net"

  def wait_for_completion(
      submission_id: str,
      api_key: str,
      max_wait_seconds: int = 300,
      poll_interval: int = 5,
  ) -> dict:
      """Poll until the submission reaches a terminal state."""

      start_time = time.time()

      while time.time() - start_time < max_wait_seconds:
          response = requests.get(
              f"{API_BASE}/api/integrations/submissions/{submission_id}",
              headers={"X-API-Key": api_key},
          )
          status = response.json()

          if status["status"] in ("complete", "failed"):
              return status

          print(f"Status: {status['status']}, waiting {poll_interval}s...")
          time.sleep(poll_interval)

      raise TimeoutError(
          f"Submission did not finish within {max_wait_seconds} seconds"
      )

  # Usage
  status = wait_for_completion(
      "550e8400-e29b-41d4-a716-446655440000", "your-api-key-here"
  )
  print(f"Final status: {status['status']}")
  ```

  ```javascript theme={null}
  const API_BASE = "https://mm-midmarket-integrations-api-preview.azurewebsites.net";

  async function waitForCompletion(
    submissionId,
    apiKey,
    maxWaitSeconds = 300,
    pollInterval = 5000
  ) {
    const startTime = Date.now();

    while (Date.now() - startTime < maxWaitSeconds * 1000) {
      const response = await fetch(
        `${API_BASE}/api/integrations/submissions/${submissionId}`,
        { headers: { "X-API-Key": apiKey } }
      );
      const status = await response.json();

      if (status.status === "complete" || status.status === "failed") {
        return status;
      }

      console.log(`Status: ${status.status}, waiting ${pollInterval}ms...`);
      await new Promise((resolve) => setTimeout(resolve, pollInterval));
    }

    throw new Error(
      `Submission did not finish within ${maxWaitSeconds} seconds`
    );
  }

  // Usage
  const status = await waitForCompletion(
    "550e8400-e29b-41d4-a716-446655440000",
    "your-api-key-here"
  );
  console.log("Final status:", status.status);
  ```
</CodeGroup>

### Exponential backoff

For long-running submissions, start with short intervals and back off over time:

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

API_BASE = "https://mm-midmarket-integrations-api-preview.azurewebsites.net"

def wait_with_backoff(
    submission_id: str,
    api_key: str,
    initial_interval: float = 2,
    max_interval: float = 30,
    max_wait_seconds: int = 600,
) -> dict:
    """Poll with exponential backoff until terminal."""

    start_time = time.time()
    current_interval = initial_interval

    while time.time() - start_time < max_wait_seconds:
        response = requests.get(
            f"{API_BASE}/api/integrations/submissions/{submission_id}",
            headers={"X-API-Key": api_key},
        )
        status = response.json()

        if status["status"] in ("complete", "failed"):
            return status

        time.sleep(current_interval)
        current_interval = min(current_interval * 1.5, max_interval)

    raise TimeoutError(
        f"Submission did not finish within {max_wait_seconds} seconds"
    )
```

## Retrieving results

Once an asset is done, fetch its result with `GET /api/integrations/submissions/{submission_id}/assets/{asset_id}`. The result includes the asset's `status`, `issueCount`, and an `issues` array. For the flat enriched issue list call `.../assets/{asset_id}/issues`; for AI-clustered topics call `.../assets/{asset_id}/topics`.

<CodeGroup>
  ```bash curl theme={null}
  curl -H "X-API-Key: your-api-key-here" \
    https://mm-midmarket-integrations-api-preview.azurewebsites.net/api/integrations/submissions/550e8400-.../assets/a1b2.../issues
  ```

  ```python theme={null}
  import requests

  API_BASE = "https://mm-midmarket-integrations-api-preview.azurewebsites.net"
  submission_id = "550e8400-e29b-41d4-a716-446655440000"
  asset_id = "a1b2..."

  # Asset result (includes status, issueCount, and inline issues)
  result = requests.get(
      f"{API_BASE}/api/integrations/submissions/{submission_id}/assets/{asset_id}",
      headers={"X-API-Key": "your-api-key-here"},
  ).json()
  print(f"Status: {result['status']}, issues: {result['issueCount']}")
  for issue in result["issues"]:
      print(f"  [{issue['severity']}] {issue['ruleCode']}: {issue['summary']}")

  # Or the flat enriched issue list
  issues = requests.get(
      f"{API_BASE}/api/integrations/submissions/{submission_id}/assets/{asset_id}/issues",
      headers={"X-API-Key": "your-api-key-here"},
  ).json()
  print(f"Total issues: {issues['total']}")
  ```
</CodeGroup>

Asset result shape:

```json theme={null}
{
  "assetId": "a1...",
  "submissionId": "s1...",
  "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"
    }
  ]
}
```

Issue `severity` is one of `CRITICAL | MAJOR | MINOR | INFO`, and issue `status` is one of `OPEN | ACKNOWLEDGED | AWAITING_HUMAN_INPUT | RESOLVED | DISMISSED`.

The clustered topics endpoint returns `{ "assetId", "topics", "orphanIssues", "metadata" }`. Topics group two or more related issues; `orphanIssues` are unclustered singletons and are normal. The issues and topics endpoints return `404` if the asset has not finished processing yet.

## Complete polling example

A full end-to-end example:

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

API_KEY = "your-api-key-here"
API_BASE = "https://mm-midmarket-integrations-api-preview.azurewebsites.net"

def submit_and_wait(file_paths: list[str]) -> list[dict]:
    """Upload files, submit, wait for completion, and return results."""

    # Step 1: Upload files via presigned URLs and collect assets
    assets = []
    for file_path in file_paths:
        # Request a presigned URL, then PUT the bytes straight to Azure
        url_resp = requests.post(
            f"{API_BASE}/api/integrations/uploads/url",
            headers={"X-API-Key": API_KEY},
            json={"filename": file_path.split("/")[-1], "contentType": "video/mp4"},
        )
        url_resp.raise_for_status()
        data = url_resp.json()
        with open(file_path, "rb") as f:
            requests.put(
                data["uploadUrl"],
                headers={"x-ms-blob-type": "BlockBlob"},
                data=f,
            ).raise_for_status()
        assets.append({"blobPath": data["blobPath"]})

    # Create the submission
    submission = requests.post(
        f"{API_BASE}/api/integrations/submissions",
        headers={"X-API-Key": API_KEY},
        json={"assets": assets, "sidekickIds": ["<sidekick-id>"]},
    ).json()
    submission_id = submission["submissionId"]
    print(f"Created submission: {submission_id}")

    # Step 2: Poll until terminal
    status = {}
    start_time = time.time()
    while time.time() - start_time < 600:
        status = requests.get(
            f"{API_BASE}/api/integrations/submissions/{submission_id}",
            headers={"X-API-Key": API_KEY},
        ).json()
        print(f"  status={status['status']} progress={status['progressPercent']}%")
        if status["status"] in ("complete", "failed"):
            break
        time.sleep(5)

    # Step 3: Retrieve each asset's result
    results = []
    for asset in status["assets"]:
        result = requests.get(
            f"{API_BASE}/api/integrations/submissions/{submission_id}"
            f"/assets/{asset['assetId']}",
            headers={"X-API-Key": API_KEY},
        ).json()
        if result["status"] == "complete":
            results.append(result)

    print(f"Completed processing {len(results)} assets")
    return results

# Usage
results = submit_and_wait(["video1.mp4", "video2.mp4"])
for result in results:
    print(f"\n{result['filename']}: {result['issueCount']} issues")
    for issue in result["issues"]:
        print(f"  [{issue['severity']}] {issue['summary']}")
```

## Polling recommendations

<Tip>
  * Start with a poll interval of a few seconds for fast feedback.
  * Back off over time to avoid hammering the API.
  * Use `progressPercent` to surface progress to your users.
  * Set a reasonable timeout to prevent infinite waits.
  * Prefer webhooks over tight polling for production volume.
</Tip>

## Polling vs webhooks

| Factor     | Polling                    | Webhooks             |
| ---------- | -------------------------- | -------------------- |
| Latency    | Delayed by poll interval   | Real-time            |
| Complexity | Simpler to implement       | Requires an endpoint |
| Throughput | Better for few submissions | Better for many      |
| Load       | Higher on the API          | Lower on the API     |

For production systems with high volume, webhooks are recommended. See [Webhook subscriptions](/guides/webhook-subscriptions).

## Handling timeouts

If a submission does not finish within your timeout:

1. Re-fetch the submission later — it may simply still be processing.
2. Check the per-asset `errorMessage`, `errorType`, and `isRetryable` fields.
3. Retry a failed, retryable asset with `POST .../assets/{asset_id}/retry`.
4. Switch to webhooks for more reliable completion detection.
