Video Compliance Check — Full Guide
ZebraTruth runs compliance analysis on video ads through a server-side async pipeline. Your client uploads the video to managed blob storage, submits a job, then either polls or receives a webhook when the report is ready.Primary endpoint
POST
https://api.zebratruth.ai/v1/compliance/check-videoNo client-side ffmpeg. ZebraTruth handles video probing, audio transcription, frame extraction, OCR, visual signals, and Stage A→C compliance analysis server-side.
Supported inputs
| Limit | Value |
|---|---|
| Content types | video/mp4, video/webm, video/quicktime |
| Duration | 3 to 180 seconds |
| File size | Up to 200 MB |
| Execution | Async only |
| Client preprocessing | None required |
The 3-step flow
POST /v1/compliance/media/upload-url— get a 15-min signed Azure Blob upload URLPUT <uploadUrl>— upload your video bytes directly to managed storagePOST /v1/compliance/check-video— submit the uploaded video for analysis (returns 202)- Poll
GET /v1/compliance/check-video/{requestId}OR receive an HMAC-signed webhook
Step 1 — Request an upload URL
Response
uploadUrl is valid for 15 minutes. Save requestId + blobPath — you’ll pass blobPath back in step 3 + use requestId to poll.
Step 2 — Upload the video
PUT your video bytes directly touploadUrl. Use exactly the headers from uploadInstructions.headers — x-ms-tags is required by Azure for the integrity check.
Step 3 — Submit for analysis
Response (HTTP 202)
Request body fields
| Field | Required | Notes |
|---|---|---|
requestId | yes | UUID. Same as the one returned from upload-url. Also serves as idempotency key. |
blobPath | yes | From upload-url response. |
jurisdictions | yes | At least 1. Values: us, eu, uk, in, cn, etc. |
platforms | yes | At least 1. Values: tiktok, youtube, instagram, facebook, linkedin. |
mode | yes | "fast" only (V1). |
callbackId | no | Opaque string echoed back in webhook payloads. |
webhookUrl | no | If set + tenant has a signing secret, ZebraTruth POSTs the report when terminal. |
Possible error responses
| Status | Body code | Meaning | ||
|---|---|---|---|---|
| 400 | blob_path_invalid | Path doesn’t match videos/<tenantId>/<requestId>/... | ||
| 400 | unsupported_mode | Mode other than fast | ||
| 400 | video_too_short | Probed duration < 3 sec | ||
| 400 | video_too_long | Probed duration > 180 sec | ||
| 400 | video_too_large | Size > 200 MB | ||
| 402 | insufficient_credits | Tenant budget exhausted | ||
| 409 | idempotency_conflict | Same requestId already used with different inputs (the response body includes `reason: “blobPath" | "feature" | "inputHash”`) |
| 503 | video_analysis_disabled | Feature flag off (should not happen in prod) |
Step 4 — Poll for results
Response (in-flight)
Response (terminal)
Status state machine
Terminal report statuses
reportStatus | Meaning | Billing |
|---|---|---|
complete | Real findings produced | Charged |
insufficient_evidence | Silent video / no OCR / no signals — pipeline ran but had nothing to flag | Released (no charge) |
analysis_failed | Engine error — failure recorded for audit | Released (no charge) |
Webhooks (recommended for production)
Instead of polling, configure a webhook URL once at the account level and submit videos withwebhookUrl set.
Get / create your tenant webhook secret
Response
Verify webhook signatures
Each delivery is HMAC-SHA256-signed. Signature is stable across retries (computed once at enqueue + cached on the row). Headers:x-zt-timestamp: <unix-seconds>x-zt-signature: <hex-signature>
Retry semantics
| Attempt | Delay after previous |
|---|---|
| 1 | (immediate) |
| 2 | +1 minute |
| 3 | +5 minutes |
| 4 | +15 minutes |
| 5 | +1 hour |
failed and dropped. Webhook failures do NOT mutate the compliance job row — the job stays completed_committed. The webhook delivery has its own retry state in videoWebhookDeliveries.
Rotate the secret
Idempotency
Same(requestId, blobPath, jurisdictions, platforms, mode) → 202 with idempotent: true, no extra charge.
Same requestId with different blobPath / jurisdictions / platforms / mode → 409 idempotency_conflict:
blobPath > feature > inputHash (deterministic order for stable error messages).
Cost
Per-second pricing. A 60-second video costs ~600 credits.| Duration | Credits |
|---|---|
| 3 sec (minimum) | 30 |
| 10 sec | 100 |
| 30 sec | 300 |
| 60 sec | 600 |
| 180 sec (maximum) | 1800 |
reportStatus: complete. insufficient_evidence and analysis_failed release the reservation (no charge).
See Cost & Credits for tier multipliers + billing lifecycle.
Common errors
| HTTP | code | Cause | Fix |
|---|---|---|---|
| 400 | blob_path_invalid | Path doesn’t match the tenant’s prefix | Use the blobPath from upload-url verbatim |
| 400 | video_too_short | < 3 seconds | Cut the source long enough |
| 400 | video_too_long | > 180 seconds | Split into segments |
| 400 | video_too_large | > 200 MB | Reduce bitrate or resolution before upload |
| 402 | insufficient_credits | Budget exhausted | Top up or wait for next billing period |
| 409 | idempotency_conflict | Same requestId, different inputs | Use a fresh UUID per submission |
| 503 | video_analysis_disabled | (Should not happen in prod) | Contact support |
Next
Cost & credits
Per-second pricing math, tier multipliers, credit lifecycle.
Async + Webhooks
HMAC verification deep dive, retry semantics.
Interpreting reports
How to read scores + decisions + agent breakdowns.
LLM Skill
Install the skill so your LLM agent runs video checks autonomously.