FrameQuery
API Reference

FrameQuery API

Programmatically upload videos and trigger processing through the FrameQuery cloud pipeline. Integrate FrameQuery into your workflow, automate bulk uploads, or build custom tooling on top of your video library.

Base URL

https://api.framequery.com/v1

All requests must be made over HTTPS.

Auth

API key via header

Rate limit

100 req/min per key

Pricing

$2.00 / hour processed

Quick start

Process a video via URL in two API calls:

1Create an API key from your dashboard
2Submit a job with a video URL (or request a presigned upload URL)
3Poll the job status until processing completes
# Submit a video from URL
curl -X POST https://api.framequery.com/v1/api/jobs/from-url \
  -H "X-API-Key: fq_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/video.mp4"}'

Response envelope

All successful responses are wrapped in a data key. Errors return an error string.

{
  "data": { ... }
}

Authentication

All API requests require authentication via an API key. Include your key in the request headers using either format:

X-API-Key: fq_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6

API keys use the fq_live_ prefix followed by 32 hex characters. Create and manage keys from your dashboard — see the section below.

Important: Keep your API keys secret. Do not expose them in client-side code, public repositories, or share them in plain text. If a key is compromised, revoke it immediately and generate a new one.

API Keys

Create and manage API keys directly from here. Each key is identified by its keyPrefix — the first 8 hex characters after fq_live_. Keys support scopes: jobs:read, jobs:write, and quota:read.

Loading...

API reference

You can also manage keys programmatically. These endpoints are authenticated via your session token (not an API key).

POST/v1/api/keys

Generate a new API key. The full key is only returned once — store it securely.

Body parameters

ParameterTypeDescription
namestringA human-readable label for this key (e.g. "CI Pipeline")
scopesstring[]Permissions for this key. Defaults to ["jobs:read", "jobs:write", "quota:read"]
curl -X POST https://api.framequery.com/v1/api/keys \
  -H "Authorization: Bearer <your_session_token>" \
  -H "Content-Type: application/json" \
  -d '{"name": "CI Pipeline"}'

Response

200
JSON
{
  "data": {
    "key": "fq_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
    "keyPrefix": "a1b2c3d4",
    "name": "CI Pipeline"
  }
}
Important: The full API key is only returned in this response. Store it in a secure location like a secrets manager or environment variable. It cannot be retrieved again.

GET/v1/api/keys

List all API keys associated with your account. Returns the key prefix, name, scopes, and revocation status — never the full key.

curl https://api.framequery.com/v1/api/keys \
  -H "Authorization: Bearer <your_session_token>"

Response

200
JSON
{
  "data": [
    {
      "keyPrefix": "a1b2c3d4",
      "name": "CI Pipeline",
      "scopes": ["jobs:read", "jobs:write", "quota:read"],
      "createdAt": "2026-02-21T14:30:00Z",
      "revoked": false
    },
    {
      "keyPrefix": "e5f6a7b8",
      "name": "Staging",
      "scopes": ["jobs:read", "quota:read"],
      "createdAt": "2026-02-19T09:00:00Z",
      "revoked": false
    }
  ]
}

DELETE/v1/api/keys/:keyPrefix

Permanently revoke an API key. Any requests using this key will immediately start failing with 401.

Path parameters

ParameterTypeDescription
keyPrefixstringThe 8-character key prefix (e.g. a1b2c3d4)
curl -X DELETE https://api.framequery.com/v1/api/keys/a1b2c3d4 \
  -H "Authorization: Bearer <your_session_token>"

Response

200
JSON
{
  "data": {
    "revoked": true
  }
}
Note: Revocation is immediate and irreversible. Create a new key if you need to restore access.

Jobs

A job represents a video being uploaded and processed through the FrameQuery pipeline. Once complete, the job contains scenes, transcripts, and detected objects. Jobs progress through these statuses:

PENDING_UPLOAD
PENDING_FETCH
COMPLETED
StatusMeaning
PENDING_UPLOADJob created via presigned URL — waiting for you to PUT the file
PENDING_FETCHJob created from URL — FrameQuery is downloading the file
FAILED_FETCHURL download failed (unreachable, private IP, etc.)
COMPLETEDProcessing finished with scenes and transcript
COMPLETED_NO_SCENESProcessing finished but no scenes were detected
Tip: Camera RAW formats (R3D, BRAW) are supported and automatically transcoded to H.264 proxy before processing. See supported formats.
POST/v1/api/jobs

Create a job and get a presigned upload URL. You then PUT your file directly to that URL.

Body parameters

ParameterTypeDescription
fileNamestringThe filename including extension (e.g. "video.mp4")
# Step 1: Create the job and get an upload URL
curl -X POST https://api.framequery.com/v1/api/jobs \
  -H "X-API-Key: fq_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"fileName": "video.mp4"}'

# Step 2: Upload the file to the presigned URL (expires in 15 min)
curl -X PUT "<uploadUrl from step 1>" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @/path/to/video.mp4

Response

200
JSON
{
  "data": {
    "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "uploadUrl": "https://storage.googleapis.com/...",
    "expiresInSeconds": 900,
    "uploadMethod": "PUT"
  }
}
Note: The presigned URL expires after 15 minutes. Upload the file using a PUT request with Content-Type: application/octet-stream. Processing starts automatically once the upload completes.

POST/v1/api/jobs/from-url

Submit a publicly accessible video URL for FrameQuery to download and process. No file upload needed.

Body parameters

ParameterTypeDescription
urlstringPublicly accessible URL of the video file (http or https)
fileNamestringOverride the filename (defaults to filename from URL)
curl -X POST https://api.framequery.com/v1/api/jobs/from-url \
  -H "X-API-Key: fq_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://storage.example.com/rushes/A003_C008.R3D",
    "fileName": "Camera A Take 8.R3D"
  }'

Response

200
JSON
{
  "data": {
    "jobId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "status": "PENDING_FETCH"
  }
}
Note: The URL must be publicly accessible. The server rejects URLs pointing to private or internal IP ranges (SSRF protection).

GET/v1/api/jobs/:jobId

Retrieve the current status and details of a job. Completed jobs include the full processedData with scenes and transcript.

Path parameters

ParameterTypeDescription
jobIdstringThe job ID
curl https://api.framequery.com/v1/api/jobs/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
  -H "X-API-Key: fq_live_your_key_here"

Response — in progress

Response

200
JSON
{
  "data": {
    "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "PENDING_FETCH",
    "originalFilename": "A003_C008.R3D",
    "source": "api",
    "createdAt": "2026-02-21T14:30:00Z",
    "updatedAt": "2026-02-21T14:30:00Z"
  }
}

Response — completed

Response

200
JSON
{
  "data": {
    "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "COMPLETED",
    "originalFilename": "A003_C008.R3D",
    "source": "api",
    "createdAt": "2026-02-21T14:30:00Z",
    "updatedAt": "2026-02-21T14:38:42Z",
    "processedData": {
      "length": 1847.5,
      "scenes": [
        {
          "sceneId": "scene_a3f7c291-8e4b-4d1a-b562-9c0e3f8a71d4_45.8",
          "startTs": 12.467,
          "endTs": 45.8,
          "description": "A woman in a blue blazer stands at the front of the room presenting a bar chart showing revenue growth across four quarters.",
          "mainColor": "#3b82f6",
          "detections": [
            {
              "name": "person",
              "x": 0.12,
              "y": 0.08,
              "width": 0.22,
              "height": 0.88,
              "confidence": 0.9789
            },
            {
              "name": "bar chart",
              "x": 0.42,
              "y": 0.05,
              "width": 0.52,
              "height": 0.68,
              "confidence": 0.9156
            }
          ]
        }
      ],
      "transcript": [
        {
          "Speaker": "a4b2c3d4-e5f6-7890-abcd-ef1234567890",
          "StartTime": 12.4,
          "EndTime": 18.9,
          "Text": "Welcome everyone to today's product reveal."
        },
        {
          "Speaker": "a4b2c3d4-e5f6-7890-abcd-ef1234567890",
          "StartTime": 19.2,
          "EndTime": 27.1,
          "Text": "What we're about to show you has been two years in the making."
        }
      ]
    }
  }
}
Note: The processedData field is only present when the job status is COMPLETED. Transcript fields use capitalised keys: StartTime, EndTime, Text. Times are in seconds.

GET/v1/api/jobs

List jobs for your account with optional filtering. Uses cursor-based pagination.

Query parameters

ParameterTypeDescription
statusstringFilter by exact status (e.g. COMPLETED, PENDING_FETCH)
limitintegerResults per page, 1–100 (default: 20)
cursorstringJob ID from a previous response's nextCursor for pagination
curl "https://api.framequery.com/v1/api/jobs?status=COMPLETED&limit=10" \
  -H "X-API-Key: fq_live_your_key_here"

Response

200
JSON
{
  "data": [
    {
      "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": "COMPLETED",
      "originalFilename": "video.mp4",
      "createdAt": "2026-02-21T14:30:00Z",
      "updatedAt": "2026-02-21T14:38:42Z"
    }
  ],
  "nextCursor": "c3d4e5f6-a7b8-9012-cdef-345678901234"
}
Tip: To paginate through all results, keep passing the nextCursor value as the cursor query parameter until nextCursor is null.

Billing & Credits

Video processing is billed per second based on the duration of the source video, with a 30-second minimum per job. Volume discounts kick in automatically after 100 hours per month.

Pricing

$2.00per hour of video

Billed per second with a 30-second minimum per job. After 100 hours in a billing month, the rate drops to $1.50/hr.

Video durationBilled durationCost
10 seconds30 seconds (minimum)$0.017
5 minutes5 min 0 sec$0.167
45 minutes45 min 0 sec$1.50
1 hour1 hr 0 min 0 sec$2.00
3 hr 10 min3 hr 10 min 0 sec$6.33

Volume discount

After 100 hours of processing in a billing month, all additional usage is billed at $1.50/hr instead of $2.00/hr. The discount applies automatically.

Plan allowances

PlanIncluded hours / month
Starter10 hours
Pro50 hours
Max250 hours

Need more? Purchase credit packs (5 or 20 hours) from your dashboard. Credits roll over and don't expire.

Tip: Cancelled jobs that haven't finished processing are not charged. You only pay for completed jobs.

How FrameQuery compares

FrameQuery delivers scene detection, transcription, object recognition, and semantic search in a single API call, no stitching services together.

 FrameQueryTwelve LabsGoogle Video AIAWS Rekognition
Price / hr$2.00$2.40~$4.68*~$4.32*
Volume rate$1.50 after 100 hrCustomNoneNone
Billing granularityPer secondPer secondPer 1-min chunkPer 1-min chunk
Minimum charge30 sec10 sec1 min1 min
Scene detectionIncludedIncludedAdd-onNot available
TranscriptionIncludedIncludedSeparate APISeparate API
Object detectionIncludedLimitedAdd-onIncluded
Semantic searchIncludedIncludedNot availableNot available
Speaker diarizationIncludedNot availableSeparate APINot available
Camera RAW supportIncludedNot availableNot availableNot available
Single API callYesYesNo (multiple)No (multiple)

* Estimated cost when combining label detection, transcription, and object tracking at published per-minute rates. Actual costs vary by feature selection.

Check your quota

GET/v1/api/quota

Retrieve your current plan, included hours, credit balance, and reset date.

curl https://api.framequery.com/v1/api/quota \
  -H "X-API-Key: fq_live_your_key_here"

Response

200
JSON
{
  "data": {
    "plan": "pro",
    "includedHours": 50,
    "creditsBalanceHours": 5.0,
    "resetDate": "2026-03-01T00:00:00Z"
  }
}

Errors

When a request fails, the API returns a JSON body with an error string and an appropriate HTTP status code.

{
  "error": "The provided API key is invalid or has been revoked."
}

Common error responses

StatusDescription
400Bad request — missing required fields or malformed body
401Unauthorized — missing or invalid API key
403Forbidden — insufficient credits or missing scopes
404Not found — the requested job or resource does not exist
429Rate limited — too many requests, retry after the reset window
500Internal error — something went wrong on our end

Rate Limits

Rate limits protect the API from abuse and ensure fair usage across all accounts. Limits are applied per API key.

EndpointLimit
General100 requests / minute
Uploads10 concurrent uploads
Key management10 requests / minute

Rate limit information is included in response headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1708523400

When rate limited, the API returns 429 Too Many Requests. Use the X-RateLimit-Reset header (Unix timestamp) to determine when you can retry.

Tip: Implement exponential backoff in your integration to handle rate limits gracefully. Most HTTP client libraries support automatic retries with backoff.

Need help?

Having trouble with the API? Reach out and we'll get you sorted.