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.

Write a fake text story with GPT-Video

generate_fake_text_storyPOST/v1/projects/{projectId}/story/generateBeta

Starts writing a new story for a fake text project from your brief, 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

Use it to let GPT-Video write the story from a short brief; an empty brief writes a sample story. The answer is 202 with the job: follow it with get_job (GET /v1/jobs/{jobId}), then read the story with get_fake_text_story (GET /v1/projects/{projectId}/story). The new story replaces the story of the project, and the video follows it; the old story is no longer shown. If a story is already being written for the project, you get that job back and nothing is used (reused is true). Make the voices afterwards with create_fake_text_voices (POST /v1/projects/{projectId}/story/voices).

Example use

A creator who posts a new chat story every morning sends a one-line brief, follows the job with get_job (GET /v1/jobs/{jobId}), and reads the result with get_fake_text_story (GET /v1/projects/{projectId}/story) before making the voices.

Endpoint

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

Body

NameTypeRequiredDescription
briefstringRequiredWhat the story is about, up to 4000 characters. An empty brief writes a sample story. At most 4000 characters.

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

Request

Write a story from a brief.

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/generate" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "brief": "Two roommates argue about who ate the last slice of pizza"
  }'
// 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/generate", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
    "Idempotency-Key": idempotencyKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "brief": "Two roommates argue about who ate the last slice of pizza"
  }),
});
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/generate",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
        "Idempotency-Key": idempotency_key,
    },
    json={
        "brief": "Two roommates argue about who ate the last slice of pizza"
    },
)
data = r.json()
print(data)
{
  "method": "tools/call",
  "params": {
    "name": "generate_fake_text_story",
    "arguments": {
      "projectId": "prj_ba8b07a88bfb14585459",
      "brief": "Two roommates argue about who ate the last slice of pizza",
      "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 a story 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": "story"
  },
  "reused": false,
  "paidWith": "plan"
}
All response fields
NameTypeRequiredDescription
jobJob objectRequiredDescribed in Job object.
reusedbooleanRequiredtrue when a story 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

A story that is already being written

POST /v1/projects/prj_ba8b07a88bfb14585459/story/generate

Request body
{
  "brief": "A text from an old friend"
}
HTTP 202
{
  "job": {
    "status": "running",
    "progress": 0.4,
    "errorMessage": null,
    "projectId": "prj_ba8b07a88bfb14585459",
    "compositionId": null,
    "exportId": null,
    "assetId": null,
    "toolRunId": null,
    "turnId": null,
    "createdAt": "2026-08-31T22:10:00.000Z",
    "startedAt": "2026-08-31T22:11:00.000Z",
    "finishedAt": null,
    "id": "job_a84eefa1e7fd196089dd",
    "kind": "story"
  },
  "reused": true,
  "paidWith": null
}

The fake text scripts of the day are used up

POST /v1/projects/prj_ba8b07a88bfb14585459/story/generate

Request body
{
  "brief": "A wrong number"
}
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_3c8e0a5d7b2f49146e9c1a8d"
  }
}

A project that is not a fake text project

POST /v1/projects/prj_7c2e9a4f1b3d4e8096a5/story/generate

Request body
{
  "brief": "A wrong number"
}
HTTP 409
{
  "error": {
    "code": "CONFLICT",
    "message": "This project is not a fake text project. Stories exist only in fake text projects.",
    "requestId": "req_7f1d4b8e2a6c40935b7e2d9a"
  }
}

Writing stories through the API is off

POST /v1/projects/prj_ba8b07a88bfb14585459/story/generate

Request body
{
  "brief": "A wrong number"
}
HTTP 503
{
  "error": {
    "code": "UNAVAILABLE",
    "message": "Writing a story through the API is not available yet.",
    "requestId": "req_5d0a8c3e6f1b42977c4a0e5b"
  }
}

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.
CONFLICT409A project that is not a fake text projectRead 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

What happens to the story the project had?

The new story replaces it: the project and its video show only the new one. Read it with get_fake_text_story (GET /v1/projects/{projectId}/story) once the job is done.

Is the script returned if writing the story fails?

No. The script of the day is used when the request is accepted. Ask for a new story again; a retry with the same Idempotency-Key never uses a second one.

View as Markdown