Skip to content
ChatClipThatAPI
Documentation

Video intelligence API

Define reusable questions as saved scanners, run them against authorized recordings, and query typed observations with evidence. One-off analysis and optional rendering remain available underneath.

RESTTyped observationsVersioned scannersAsync runs

Core concepts

A Scanner is a saved, versioned question and typed output contract. A Run applies one scanner version to one recording. An Observation is a typed result with explicit semantics, relevance, source metadata, and timestamped evidence.

A lower-level Analysis processes one video without saving a reusable definition. A Moment is its ranked time range. A Render optionally turns selected Moments into MP4 files.

Rendering is optional. Search, review, analytics, and agent workflows can operate entirely on observations or Moment JSON.

Authentication

Create a revocable API key in the console and send it from your server in the Bearer header. Never ship a secret key in browser or mobile client code.

HTTP
Authorization: Bearer cct_your_secret_key

Resources are account-scoped. Requests for an unknown resource and a resource owned by a different account both return 404.

API reference

POST/v1/scanners

Create a reusable, versioned scanner definition.

GET/v1/scanners

List account-owned scanner definitions.

PATCH/v1/scanners/{scanner_id}

Create the next immutable scanner version.

GET/v1/scanners/{scanner_id}/versions

List definition snapshots used by prior runs.

POST/v1/scanners/{scanner_id}/runs

Run the current scanner version against one recording.

GET/v1/runs/{run_id}

Read run state, source metadata, and provenance.

GET/v1/runs/{run_id}/observations

Read typed findings from one completed run.

GET/v1/observations

Query observations across account-owned runs.

POST/v1/uploads

Issue a private, time-limited direct upload target.

POST/v1/webhook-endpoints

Create a signed event-delivery endpoint when enabled.

POST/v1/analyses

Submit an authorized video for asynchronous analysis.

GET/v1/analyses/{analysis_id}

Read analysis status and terminal errors.

GET/v1/analyses/{analysis_id}/moments

Retrieve ranked Moments after completion.

GET/v1/render-presets

Read supported output and caption controls.

POST/v1/renders

Optionally render selected Moment IDs.

GET/v1/renders/{render_id}

Read render status and completed assets.

POST

Create a saved scanner

Choose a type based on the value you need: monitor, summarizer, classifier, scorer, find_moments, or extractor. Instructions must describe observable evidence and may contain up to 600 characters.

cURL
curl -X POST https://api.chatclipthat.com/v1/scanners \
  -H "Authorization: Bearer $CCT_API_KEY" \
  -H "Idempotency-Key: scanner-001" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Onboarding friction",
    "instructions": "Find where the user repeats a setup action, receives an error, or says they cannot continue.",
    "type": "find_moments",
    "profile": "conversation",
    "max_observations": 20,
    "min_seconds": 10,
    "max_seconds": 60,
    "output": {"fields": ["title", "summary", "start_ms", "end_ms", "relevance_score", "transcript_excerpt"]},
    "metadata": {"owner": "product-research"}
  }'

Updating a scanner creates a new version. Runs retain the version and definition they used; old observation provenance is not rewritten.

POST

Run a scanner

Submit one direct HTTPS source URL from a trusted hostname. Run metadata accepts up to 20 bounded scalar values and is copied onto resulting observations.

cURL
curl -X POST https://api.chatclipthat.com/v1/scanners/scn_YOUR_ID/runs \
  -H "Authorization: Bearer $CCT_API_KEY" \
  -H "Idempotency-Key: recording-1842-scanner-v3" \
  -H "Content-Type: application/json" \
  -d '{
    "source_url": "https://media.example.com/session-1842.mp4",
    "metadata": {"recording_id": "1842", "cohort": "new-user"}
  }'

Poll GET /v1/runs/{run_id} every 5–10 seconds. A completed run can contain zero observations when the recording does not support the scanner instructions.

GET

Read typed observations

An observation separates its typed value and value_type from explicit semantics. relevance_score ranks support for the scanner instructions and must not be presented as calibrated confidence.

JSON
{
  "observation_id": "obs_...",
  "scanner_id": "scn_...",
  "scanner_version": 3,
  "run_id": "run_...",
  "type": "find_moments",
  "value_type": "object",
  "semantics": "timestamped_moment",
  "value": {"event_type": "setup_blocked"},
  "title": "Repeated connection failure",
  "summary": "The user retries the same connection flow after an error.",
  "relevance_score": 0.91,
  "evidence": {"start_ms": 84210, "end_ms": 109440, "duration_ms": 25230, "transcript_excerpt": "Why won't this connect?", "signals": []},
  "source_metadata": {"recording_id": "1842", "cohort": "new-user"}
}
POST

Create a one-off analysis

Use the lower-level analysis endpoint when you do not need a saved definition or cross-run observation model. Submit a direct HTTPS media URL from a hostname configured under Trusted Sources and use what_to_find as an evidence-based brief.

cURL
curl -X POST https://api.chatclipthat.com/v1/analyses \
  -H "Authorization: Bearer $CCT_API_KEY" \
  -H "Idempotency-Key: request-001" \
  -H "Content-Type: application/json" \
  -d '{
    "source_url": "https://media.example.com/session.mp4",
    "what_to_find": "Find where the user repeatedly fails to connect an integration",
    "profile": "conversation",
    "max_moments": 10,
    "min_seconds": 10,
    "max_seconds": 60
  }'

Request fields

source_urlstringDirect HTTPS media URL on a trusted hostname.
what_to_findstringPlain-language search brief, up to 600 characters.
profileenumconversation or gameplay.
max_momentsintegerMaximum results from 1–50.
min_seconds / max_secondsintegerTarget Moment length, each from 5–600 seconds.
GET

Poll analysis status

Poll /v1/analyses/{analysis_id} every 5–10 seconds. Stop at completed or failed.

JSON
{
  "analysis_id": "ana_0123456789abcdef0123456789abcdef",
  "status": "completed",
  "profile": "conversation",
  "created_at": "2026-08-14T18:00:00Z",
  "updated_at": "2026-08-14T18:03:24Z",
  "error": null
}
GET

Retrieve Moments

A completed analysis returns ranked timestamps, summaries, transcript evidence, selection signals, and edit instructions. Zero Moments is a valid answer when the recording does not support the brief.

JSON
{
  "analysis_id": "ana_...",
  "count": 1,
  "moments": [{
    "id": "mom_0123456789abcdef0123456789abcdef",
    "start_ms": 84210,
    "end_ms": 109440,
    "duration_ms": 25230,
    "score": 0.91,
    "title": "Repeated setup failure",
    "event_type": "highlight",
    "transcript_excerpt": "Why won't this connect?",
    "edit": {"mode": "continuous", "subclips": []}
  }]
}

Read render capabilities

GET /v1/render-presets returns the supported aspect ratios, output format, caption presets, bundled fonts, effects, and bounded editor controls. Read this response instead of hard-coding capability values.

POST

Create an optional render

Choose 1–20 Moment IDs from one completed analysis. ChatClipThat reuses the privately acquired source and creates one MP4 per Moment.

cURL
curl -X POST https://api.chatclipthat.com/v1/renders \
  -H "Authorization: Bearer $CCT_API_KEY" \
  -H "Idempotency-Key: render-001" \
  -H "Content-Type: application/json" \
  -d '{
    "analysis_id": "ana_...",
    "moment_ids": ["mom_..."],
    "render": {
      "output": {"format": "mp4", "aspect_ratio": "9:16"},
      "captions": {"enabled": true, "preset_id": "cct_clean_v1"}
    }
  }'

Private uploads

When upload storage is enabled, POST /v1/uploads accepts the plain filename, one supported video content type, and declared byte size. It returns a time-limited PUT URL and required headers. Upload the bytes directly, call POST /v1/uploads/{upload_id}/complete, then pass the ready upload_id instead of source_url when creating a scanner run.

Availability is explicit. A 503 uploads_unavailable response means this deployment has no private-upload storage. Trusted direct HTTPS URLs remain supported.

Signed completion webhooks

When event delivery is enabled, create a target with POST /v1/webhook-endpoints and subscribe to scanner-run, analysis, render, or upload terminal events. The signing secret is returned once. Verify the HMAC against the raw request body, reject stale timestamps, and deduplicate by event ID.

List delivery state at GET /v1/webhook-deliveries. If webhook service is unavailable for the account, poll run status every 5–10 seconds instead.

Errors

invalid_api_key401The bearer key is missing, invalid, or revoked.
source_host_not_allowed403The media hostname is not trusted for this account.
scanner_not_found404The scanner is unknown or belongs to another account.
run_not_found404The run is unknown or belongs to another account.
run_not_ready409Observations were requested before the run completed.
analysis_not_ready409Moments or rendering were requested before completion.
insufficient_credits402The shared account wallet cannot cover the operation.
dispatch_failed503The operation could not be queued.

Idempotency and retries

Send a unique Idempotency-Key with every POST. Retrying the same operation with the same key returns its original resource rather than creating and charging for duplicate work.

Limits, source safety, and retention

Only direct HTTPS media from account-approved public DNS hostnames is accepted. Private and loopback destinations are blocked. Scanner and run metadata is limited to 20 bounded scalar fields. Account concurrency and monthly allowances are shown under Console → Usage.

Request and response fields are allowlisted; raw source URLs, signed query strings, secrets, and renderer-internal identifiers are excluded from public control responses.

Use only video you are authorized to process. Configure exact source hostnames in the console before submitting production requests.