Skip to content
Create a key

Paste a key to use it in the examples on these pages. The key stays in this browser tab. These pages never send it anywhere.

Analyze a project

analyze_projectPOST/v1/projects/{projectId}/analyzeBeta

Starts the analysis that transcribes the source video and finds its clips, and returns the job to follow.

Beta. This endpoint is supported and can gain new fields. If a change would break your code, we tell you before it takes effect and list it in the changelog.

About

Call it when missingSettings is empty; estimate_analysis (POST /v1/projects/{projectId}/analyze/estimate) gives the price first. The answer is 202 with the job of the analysis: follow it with get_job (GET /v1/jobs/{jobId}), and when it is done list the clips with list_clips (GET /v1/projects/{projectId}/clips). If an analysis of the project is already running, you get that job back and nothing is charged (reused is true). Retrying with the same Idempotency-Key never charges twice: if the first attempt was charged, the retry answers what it paid and who paid it (paidWith). Analyzing a project again replaces its proposed and rejected clips and keeps the accepted ones.

Example use

A script that clips every new episode of a show checks the price with estimate_analysis (POST /v1/projects/{projectId}/analyze/estimate), then calls analyze_project (POST /v1/projects/{projectId}/analyze). It follows the job with get_job (GET /v1/jobs/{jobId}) and reads the clips with list_clips (GET /v1/projects/{projectId}/clips) when the job is done.

Endpoint

Code
POST https://api.gpt-video.com/v1/projects/{projectId}/analyze
  • Scope spend.
  • Rate limit 10 requests a minute for each key and 20 for each account, shared by every spend call. See rate limits.
  • Idempotency-Key is required.
  • It starts work that runs on its own. The answer comes back before the work is done.

Parameters

Path

NameTypeRequiredDescription
projectIdstringRequiredThe project id. It starts with prj_. Matches ^prj_[0-9a-f]{20}$.

Headers

NameTypeRequiredDescription
Idempotency-KeystringRequiredThis operation spends, so the key is required. Create it once, before the request, and send the same key on every retry. From 1 to 255 visible characters, such as a UUID. See idempotency.

Request

Analyze a project.

Request example
# Create the key once. Send this same key again if you retry this request.
IDEMPOTENCY_KEY=$(uuidgen)
curl -X POST "https://api.gpt-video.com/v1/projects/prj_7c2e9a4f1b3d4e8096a5/analyze" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY"
// Create the key once. Send this same key again if you retry this request.
const idempotencyKey = crypto.randomUUID();
const res = await fetch("https://api.gpt-video.com/v1/projects/prj_7c2e9a4f1b3d4e8096a5/analyze", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
    "Idempotency-Key": idempotencyKey,
  },
});
const data = await res.json();
console.log(data);
import os
import uuid

import requests

# Create the key once. Send this same key again if you retry this request.
idempotency_key = str(uuid.uuid4())
r = requests.post(
    "https://api.gpt-video.com/v1/projects/prj_7c2e9a4f1b3d4e8096a5/analyze",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
        "Idempotency-Key": idempotency_key,
    },
)
data = r.json()
print(data)
{
  "method": "tools/call",
  "params": {
    "name": "analyze_project",
    "arguments": {
      "projectId": "prj_7c2e9a4f1b3d4e8096a5",
      "confirm": true,
      "idempotencyKey": "REPLACE-WITH-A-NEW-UUID-FOR-THIS-CALL"
    }
  }
}

Response

A successful call answers HTTP 202. Returns a Job object in job.

Fields to check

NameTypeDescription
job.idstringThe job id. It starts with job_.
job.statusstringqueued and running are still working; done, failed and cancelled are final.
creditsChargedintegerThe credits this request was charged: the price for a new analysis, 0 when an analysis already running was returned.
reusedbooleantrue when an analysis of the project was already running and this is its job, charged to nobody again.
paidWithstring or nullWho paid for this request: plan is the credits or the daily allowance of the account's plan, api_bonus is the API bonus. null when this request paid nothing, because the same work was already running. A retry with the same Idempotency-Key says who paid the first time.

Response example

HTTP 202
{
  "job": {
    "id": "job_b582bc8315e372bf9ba3",
    "kind": "analysis",
    "status": "queued",
    "progress": 0,
    "errorMessage": null,
    "projectId": "prj_7c2e9a4f1b3d4e8096a5",
    "compositionId": null,
    "exportId": null,
    "assetId": null,
    "toolRunId": null,
    "turnId": null,
    "createdAt": "2026-09-01T11:10:00.000Z",
    "startedAt": null,
    "finishedAt": null
  },
  "creditsCharged": 30,
  "reused": false,
  "paidWith": "plan"
}
All response fields
NameTypeRequiredDescription
jobJob objectRequiredDescribed in Job object.
creditsChargedintegerRequiredThe credits this request was charged: the price for a new analysis, 0 when an analysis already running was returned. At least 0.
reusedbooleanRequiredtrue when an analysis of the project was already running and this is its job, charged to nobody again.
paidWithstring or nullRequiredWho paid for this request: plan is the credits or the daily allowance of the account's plan, api_bonus is the API bonus. null when this request paid nothing, because the same work was already running. A retry with the same Idempotency-Key says who paid the first time. One of plan, api_bonus.
More examples

An analysis that is already running

POST /v1/projects/prj_7c2e9a4f1b3d4e8096a5/analyze

HTTP 202
{
  "job": {
    "id": "job_6c1e8b4a2f0d4a97e3b5",
    "kind": "analysis",
    "status": "running",
    "progress": 0.4,
    "errorMessage": null,
    "projectId": "prj_7c2e9a4f1b3d4e8096a5",
    "compositionId": null,
    "exportId": null,
    "assetId": null,
    "toolRunId": null,
    "turnId": null,
    "createdAt": "2026-09-01T09:11:00.000Z",
    "startedAt": "2026-09-01T09:12:00.000Z",
    "finishedAt": null
  },
  "creditsCharged": 0,
  "reused": true,
  "paidWith": null
}

A project without a source video

POST /v1/projects/prj_1d8b6e0c47a24f93b1c2/analyze

HTTP 422
{
  "error": {
    "code": "SOURCE_MISSING",
    "message": "Upload or import a source video before starting the analysis.",
    "hint": "A project's video cannot be changed through the API. Upload the video, then create a new project with its asset id as sourceAssetId.",
    "requestId": "req_6c77b252f5f65fabd4aa7561"
  }
}

Settings still to choose

POST /v1/projects/prj_7c2e9a4f1b3d4e8096a5/analyze

HTTP 409
{
  "error": {
    "code": "CONFLICT",
    "message": "Set these settings before analyzing: captionStyle, reframe. Change them with update_project.",
    "requestId": "req_205c2427bb67aad78f846bdd"
  }
}

A minimum longer than the maximum

POST /v1/projects/prj_7c2e9a4f1b3d4e8096a5/analyze

HTTP 409
{
  "error": {
    "code": "CONFLICT",
    "message": "minDurationSec (60) is longer than maxDurationSec (30). Change them with update_project.",
    "requestId": "req_9d4a0c7e2b1f4863a5c0e7d2"
  }
}

Not enough credits

POST /v1/projects/prj_7c2e9a4f1b3d4e8096a5/analyze

HTTP 402
{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "Out of credits: 10 of 800 left this month and this video needs 30. Top up or upgrade your plan.",
    "hint": "Buy credits or change plan at https://www.gpt-video.com/app/billing.",
    "requestId": "req_3e8b5f1a0c7d4e29b6a4f0c1"
  }
}

A project that does not exist

POST /v1/projects/prj_9f0d3b7e1c5a4d28b6f3/analyze

HTTP 404
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Project prj_9f0d3b7e1c5a4d28b6f3 not found",
    "hint": "Check the id. An id that belongs to another account is not found either.",
    "requestId": "req_7a2f9c4e1d6b4058e3b1a9c2"
  }
}

Errors

CodeStatusWhenWhat to do
INSUFFICIENT_CREDITS402Not enough creditsStop and tell the user.
PLAN_REQUIRED402See the error reference.Stop and tell the user.
NOT_FOUND404A project that does not existChange the request, then send it again.
CONFLICT409Settings still to chooseRead the resource again, then decide. Do not send the same request again.
SOURCE_MISSING422A project without a source videoChange the request, then send it again.
DAILY_LIMIT_REACHED429See the error reference.Stop until the limit resets at 00:00 UTC.

Every call can also answer these errors. VALIDATION_FAILED, UNKNOWN_PARAMETER, IDEMPOTENCY_KEY_REQUIRED, UNAUTHORIZED, SCOPE_MISSING, IDEMPOTENCY_IN_PROGRESS, PAYLOAD_TOO_LARGE, IDEMPOTENCY_KEY_REUSED, RATE_LIMITED, INTERNAL, UNAVAILABLE.

Cost

One credit per started minute of source video, charged when the analysis starts and not returned if it fails. Analyzing again is a new analysis and is charged again.

  • Paid by the API bonus, it uses the same number of bonus credits.
  • When the API bonus pays, 1 of its jobs runs at a time. The next one waits with status queued.
  • See API pricing for who pays first.
  • estimate_analysis (POST /v1/projects/{projectId}/analyze/estimate) Estimate the credits of an analysis or a build
  • update_project (PATCH /v1/projects/{projectId}) Update a project
  • get_project (GET /v1/projects/{projectId}) Get a project
  • get_job (GET /v1/jobs/{jobId}) Get a job
  • list_clips (GET /v1/projects/{projectId}/clips) List the clips of a project
  • get_transcript (GET /v1/assets/{assetId}/transcript) Get the transcript of a video

Questions

What does an analysis cost?

One credit per started minute of the source video: a 30 minute video costs 30 credits. estimate_analysis (POST /v1/projects/{projectId}/analyze/estimate) tells you the price and your balance before you start.

Are the credits returned if the analysis fails?

No. The credits are charged when the analysis starts, because the work on the video has begun. A retry with the same Idempotency-Key is never charged twice.

What happens if two requests start the same analysis?

One analysis runs and it is charged once. The other request gets the same job back with creditsCharged 0 and reused true.

Can I change the settings while the analysis is waiting to start?

Yes. The analysis reads the settings when it starts, so a change made before then is used. The price depends only on the source video, which cannot change.

View as Markdown