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.

Create a voiceover

create_voiceoverPOST/v1/voiceoversBeta

Starts reading a script aloud with a synthetic voice, and returns the tool run that makes the audio file.

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 this to turn a script into an MP3 file read by a synthetic voice. Choose the voice with list_voices (GET /v1/reference/voices): it must speak the language you send. The call answers 202 at once with the run, queued, and a Location to follow; read it with get_tool_run (GET /v1/tool-runs/{toolRunId}) (with ?wait= to hold the request) until it is done, then download the file from its downloadUrl. The file is also an asset of the account, with origin voice. Always send an Idempotency-Key, the same one on every retry: a retry of the same request returns the same run and never uses a second tool run.

Example use

A team that makes explainer videos sends a script and a voice chosen with list_voices (GET /v1/reference/voices). It follows the run with get_tool_run (GET /v1/tool-runs/{toolRunId}) and uses the MP3 as the sound of its next video.

Endpoint

Code
POST https://api.gpt-video.com/v1/voiceovers
  • 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

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.

Body

NameTypeRequiredDescription
scriptstringRequiredThe text to read aloud, up to 5000 characters. From 1 to 5000 characters.
voicestringRequiredThe voice that reads the script, as list_voices (GET /v1/reference/voices) names it, like en-aria. It must speak the language of the script. One of en-aria, en-jenny, en-guy, en-christopher, it-elsa, it-isabella, it-diego, it-giuseppe.
languagestringRequiredThe language of the script: en for English, it for Italian. One of en, it.
titlestringOptionalA name for the run and its file. Leave it out to use the start of the script. From 1 to 120 characters.

Send only the fields listed here. Any other field is refused with UNKNOWN_PARAMETER.

Request

Read a script with an English voice.

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/voiceovers" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "script": "Meet the editor that turns one long video into ten short clips.",
    "voice": "en-aria",
    "language": "en",
    "title": "Launch voiceover"
  }'
// 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/voiceovers", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
    "Idempotency-Key": idempotencyKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "script": "Meet the editor that turns one long video into ten short clips.",
    "voice": "en-aria",
    "language": "en",
    "title": "Launch voiceover"
  }),
});
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/voiceovers",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
        "Idempotency-Key": idempotency_key,
    },
    json={
        "script": "Meet the editor that turns one long video into ten short clips.",
        "voice": "en-aria",
        "language": "en",
        "title": "Launch voiceover"
    },
)
data = r.json()
print(data)
{
  "method": "tools/call",
  "params": {
    "name": "create_voiceover",
    "arguments": {
      "script": "Meet the editor that turns one long video into ten short clips.",
      "voice": "en-aria",
      "language": "en",
      "title": "Launch voiceover",
      "confirm": true,
      "idempotencyKey": "REPLACE-WITH-A-NEW-UUID-FOR-THIS-CALL"
    }
  }
}

Response

A successful call answers HTTP 202. Returns a Tool run object in toolRun.

Fields to check

NameTypeDescription
toolRun.idstringThe tool run id. It starts with run_.
toolRun.statusstringqueued and running are still working; done and failed are final.
toolRun.file.downloadUrlstring or nullA link to download the file, on a read of a finished run; null otherwise.
toolRun.file.downloadUrlExpiresAtstring or nullAn ISO 8601 time in UTC.
toolRun.jobIdstring or nullThe job that carries out the run, to follow with get_job (GET /v1/jobs/{jobId}); null once it is gone.
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/tool-runs/run_5e8a1c3f7d2b4096a1e4
HTTP 202
{
  "toolRun": {
    "id": "run_5e8a1c3f7d2b4096a1e4",
    "tool": "voiceover",
    "status": "queued",
    "progress": 0,
    "errorMessage": null,
    "file": null,
    "ideas": null,
    "jobId": "job_2c7f9e1a4d6b48035f9e",
    "createdAt": "2026-09-01T11:00:00.000Z",
    "finishedAt": null,
    "voiceover": {
      "title": "Launch voiceover",
      "script": "Meet the editor that turns one long video into ten short clips.",
      "voice": "en-aria",
      "language": "en"
    },
    "separation": null,
    "brainstorm": null
  },
  "paidWith": "plan"
}
All response fields
NameTypeRequiredDescription
toolRunTool run objectRequiredDescribed in Tool run object.
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

A voice that does not speak the language of the script

POST /v1/voiceovers

Request body
{
  "script": "Meet the editor that turns one long video into ten short clips.",
  "voice": "it-elsa",
  "language": "en"
}
HTTP 400
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Voice it-elsa is not available in English. Call list_voices to see the voices you can use.",
    "hint": "Fix the request as the message says, then send it again.",
    "requestId": "req_3e9b1d7a5c2f4e8a0d6b9c13"
  }
}

The tool runs of the day are used up

POST /v1/voiceovers

Request body
{
  "script": "Meet the editor that turns one long video into ten short clips.",
  "voice": "en-aria",
  "language": "en"
}
HTTP 429
{
  "error": {
    "code": "DAILY_LIMIT_REACHED",
    "message": "Daily limit of tool runs reached (100). It resets at 00:00 UTC. Upgrade your plan for a higher limit.",
    "hint": "The limit resets at 00:00 UTC. A higher plan raises it: https://www.gpt-video.com/app/billing.",
    "requestId": "req_6a2d9f1c4e8b3a7d0f5c2e94"
  }
}

Voices through the API are off

POST /v1/voiceovers

Request body
{
  "script": "Meet the editor that turns one long video into ten short clips.",
  "voice": "en-aria",
  "language": "en"
}
  • Retry-After: 60
HTTP 503
{
  "error": {
    "code": "UNAVAILABLE",
    "message": "Making voices through the API is not available right now.",
    "hint": "Retry later.",
    "requestId": "req_9a3d7f1c5e8b2a6d0c4f7e13"
  }
}

Errors

CodeStatusWhenWhat to do
INSUFFICIENT_CREDITS402See the error reference.Stop and tell the user.
PLAN_REQUIRED402See the error reference.Stop and tell the user.
DAILY_LIMIT_REACHED429The tool runs 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 tool run 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 run fails.

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

Questions

What happens if my request times out and I send it again?

Send it again with the same Idempotency-Key. You get the same run back and no second tool run is used from the daily allowance. A new key starts a new run.

Which voices can I use?

The ones list_voices (GET /v1/reference/voices) returns for the language of the script. A voice of another language answers VALIDATION_FAILED, and nothing is used.

Where is the audio file?

Once the run is done, get_tool_run (GET /v1/tool-runs/{toolRunId}) gives its file with a downloadUrl. The file is also an asset of the account, with origin voice, so get_asset (GET /v1/assets/{assetId}) and list_assets (GET /v1/assets) show it too.

What does UNAVAILABLE mean here?

Making voices through the API is off for now. Nothing is used: wait the seconds in Retry-After and send the same request again later.

View as Markdown