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.

Make the voices of a fake text story

create_fake_text_voicesPOST/v1/projects/{projectId}/story/voicesBeta

Starts making the voice of every line of the story that does not have it yet, 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 once the story is as you want it and voiceover is on. Only lines without their voice are voiced: new lines, lines whose words changed, and the lines of a side whose voice changed. The answer is 202 with the job: follow it with get_job (GET /v1/jobs/{jobId}), then export the video with create_export (POST /v1/compositions/{compositionId}/exports). If voices are already being made for the story, you get that job back and nothing is used (reused is true). A story whose lines all have their voice is refused before anything is used.

Example use

After the story is final, a script asks for the voice of every line that does not have one yet. It follows the job with get_job (GET /v1/jobs/{jobId}) and calls create_export (POST /v1/compositions/{compositionId}/exports) when it is done.

Endpoint

Code
POST https://api.gpt-video.com/v1/projects/{projectId}/story/voices
  • 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

Make the voices of the story.

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_ba8b07a88bfb14585459/story/voices" \
  -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_ba8b07a88bfb14585459/story/voices", {
  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_ba8b07a88bfb14585459/story/voices",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
        "Idempotency-Key": idempotency_key,
    },
)
data = r.json()
print(data)
{
  "method": "tools/call",
  "params": {
    "name": "create_fake_text_voices",
    "arguments": {
      "projectId": "prj_ba8b07a88bfb14585459",
      "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.
reusedbooleantrue when making the voices was already running for this project and this is its job, paid by 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

  • Location: https://api.gpt-video.com/v1/jobs/job_7d2c9a4e1f0b4386c5a2
HTTP 202
{
  "job": {
    "status": "queued",
    "progress": 0,
    "errorMessage": null,
    "projectId": "prj_ba8b07a88bfb14585459",
    "compositionId": null,
    "exportId": null,
    "assetId": null,
    "toolRunId": null,
    "turnId": null,
    "createdAt": "2026-09-01T11:10:00.000Z",
    "startedAt": null,
    "finishedAt": null,
    "id": "job_7d2c9a4e1f0b4386c5a2",
    "kind": "voices"
  },
  "reused": false,
  "paidWith": "plan"
}
All response fields
NameTypeRequiredDescription
jobJob objectRequiredDescribed in Job object.
reusedbooleanRequiredtrue when making the voices was already running for this project and this is its job, paid by 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

Voices that are already being made

POST /v1/projects/prj_ba8b07a88bfb14585459/story/voices

HTTP 202
{
  "job": {
    "status": "running",
    "progress": 0.5,
    "errorMessage": null,
    "projectId": "prj_ba8b07a88bfb14585459",
    "compositionId": null,
    "exportId": null,
    "assetId": null,
    "toolRunId": null,
    "turnId": null,
    "createdAt": "2026-08-31T22:12:00.000Z",
    "startedAt": "2026-08-31T22:13:00.000Z",
    "finishedAt": null,
    "id": "job_8060ba8cd16645d280c1",
    "kind": "voices"
  },
  "reused": true,
  "paidWith": null
}

Every line already has its voice

POST /v1/projects/prj_ba8b07a88bfb14585459/story/voices

HTTP 409
{
  "error": {
    "code": "CONFLICT",
    "message": "Every line of this story already has its voice.",
    "requestId": "req_1e6b9d3a0c7f48252d8b4f0e"
  }
}

A project with no story yet

POST /v1/projects/prj_ba8b07a88bfb14585459/story/voices

HTTP 409
{
  "error": {
    "code": "CONFLICT",
    "message": "This project has no story yet. Write one with update_fake_text_story, or let GPT-Video write one with generate_fake_text_story.",
    "requestId": "req_4a7c2e9f1b5d40636f0a3c8e"
  }
}

Voices are turned off

POST /v1/projects/prj_ba8b07a88bfb14585459/story/voices

HTTP 409
{
  "error": {
    "code": "CONFLICT",
    "message": "Voices are turned off for this project. Turn them on with update_fake_text_project.",
    "requestId": "req_8d3f6b1a4e9c27050a5d8e2c"
  }
}

A voice that is not available through the API

POST /v1/projects/prj_ba8b07a88bfb14585459/story/voices

HTTP 409
{
  "error": {
    "code": "CONFLICT",
    "message": "This project uses a voice that is not available through the API. Choose one with update_fake_text_story.",
    "requestId": "req_2b9e5c8d0a3f46171e4c9a6d"
  }
}

The fake text scripts of the day are used up

POST /v1/projects/prj_ba8b07a88bfb14585459/story/voices

HTTP 429
{
  "error": {
    "code": "DAILY_LIMIT_REACHED",
    "message": "Daily limit of fake text scripts reached (100). It resets at 00:00 UTC. Upgrade your plan for a higher limit.",
    "requestId": "req_6f2a0d7c3e9b41588b1f6d3a"
  }
}

Errors

CodeStatusWhenWhat to do
INSUFFICIENT_CREDITS402See the error reference.Stop and tell the user.
PLAN_REQUIRED402See the error reference.Stop and tell the user.
NOT_FOUND404See the error reference.Change the request, then send it again.
CONFLICT409Every line already has its voiceRead the resource again, then decide. Do not send the same request again.
DAILY_LIMIT_REACHED429The fake text scripts of the day are used upStop 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

Uses one fake text script of the plan's daily allowance, which resets at 00:00 UTC. When the API bonus pays, it also uses one bonus credit. Nothing is returned if the work fails.

  • Paid by the API bonus, it uses 1 bonus credit.
  • When the API bonus pays, an account can make 10 fake text scripts a day.
  • See API pricing for who pays first.

Questions

Which lines get a voice?

Lines that do not have their voice yet: new lines, lines whose words changed, and the lines of a side whose voice changed. Lines that already have their voice are not made again.

Is the script returned if making the voices fails?

No. Ask for the voices again: lines that got their voice before the failure keep it, and a retry with the same Idempotency-Key never uses a second script.

View as Markdown