API docs · Get started
Agent quickstart
The brief for an LLM agent writing code against the FrameQuery API. Auth, the three calls, exact JSON shapes and which errors to retry.
The brief
Base https://api.framequery.com/v1/api. Header Authorization: Bearer $FRAMEQUERY_API_KEY (keys start fq_live_, server-side only). Success {"data": …}; error {"error", "code", "docUrl", "param"}: branch on code.
- Create.
POST /jobs/from-url, headerIdempotency-Key: <uuid>, body{"url": "https://…/a.mp4", "processingMode": "all"}(all|transcript|vision) →data.jobId.Local file:
POST /jobs{"fileName": "a.mp4", "fileSizeBytes": 1048576}, then, within an hour,PUTthe bytes todata.uploadUrlsending everydata.uploadHeadersentry and noAuthorization. The URL accepts exactly one object (a412means it already landed; read the job rather than re-uploading). - Wait.
GET /jobs/{jobId}?include=noneevery 5–15 s untildata.stateiscompleted,failed,cancelledorexpired(ignorestatus). Or pass"callbackUrl"at create for a signed webhook. - Read.
GET /jobs/{jobId}/transcript→data.text,data.speakers[],data.segments[{startTime, endTime, text, speaker}];?format=srt|vtt|txtfor a file.GET /jobs/{jobId}/scenes→data.scenes[{index, startTime, endTime, description, objects[], colorPalette[], shotType, shotAngle}]. Times in seconds.
Errors. Retry 429, 503 and 409 IDEMPOTENCY_IN_PROGRESS after Retry-After; retry 500 with exponential backoff. Reuse the same Idempotency-Key on every retry. 409 RESULTS_NOT_READY: later. 404 RESULTS_UNAVAILABLE: never (see reason). 402: out of credits. Others: fix the request. state failed → data.error {code, message, stage}; completed stages stay readable.
Copy-paste script
The brief above as a runnable bash script (needs curl and jq):
set -euo pipefail
API=https://api.framequery.com/v1/api
AUTH="Authorization: Bearer $FRAMEQUERY_API_KEY"
JOB_ID=$(curl -sS -X POST "$API/jobs/from-url" \
-H "$AUTH" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"url": "https://example.com/interview.mp4", "processingMode": "all"}' | jq -r .data.jobId)
while :; do
STATE=$(curl -sS "$API/jobs/$JOB_ID?include=none" -H "$AUTH" | jq -r .data.state)
echo "state: $STATE"
case "$STATE" in completed|failed|cancelled|expired) break ;; esac
sleep 10
done
curl -sS "$API/jobs/$JOB_ID/transcript" -H "$AUTH" | jq '.data.segments[:3]'
curl -sS "$API/jobs/$JOB_ID/scenes" -H "$AUTH" | jq '.data.scenes[:3]'With an SDK
The Python and TypeScript SDKs do the create, upload, wait and fetch in one call, with idempotency keys and retries built in:
from framequery import FrameQuery
fq = FrameQuery() # reads FRAMEQUERY_API_KEY
result = fq.process("https://example.com/interview.mp4") # or a local path
print(result.transcript.text if result.transcript else "no transcript")
for scene in result.scenes or []:
print(scene.start_time, scene.description)Rules of thumb
- Decide everything from
stateandstages.*.status. Thestatusstring is a legacy internal value and changes without notice. - Poll no faster than every 5 seconds;
estimatedCompletionTimeSecondson the job is a good hint. GET requests are limited to 600 per minute per account. - Send an
Idempotency-Keyon every create and reuse it on retries. A replay returns the original job withIdempotent-Replayed: true. - A failed or skipped stage costs nothing. A job whose vision stage failed can still have a completed, readable (and charged) transcript.
- Never ship the key to a browser or mobile app. Proxy through your server.
- Cost per footage-hour: $1.50
all, $1.15vision, $0.35transcript(per audio track); camera RAW $2.50 / $1.65 / $0.85. Per second, 30 s minimum per job. Check before spending withGET /pricing/estimate?durationSeconds=600&mode=all(no key) andGET /quota(data.api.availableCents). - More detail: Jobs, Job lifecycle, Results, Errors, OpenAPI.