Get the story of a fake text project
get_fake_text_storyGET/v1/projects/{projectId}/storyBeta
Returns the story of a fake text project, line by line, with the voice of each side and which lines have their voice.
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 read the story before you change it with update_fake_text_story (PUT /v1/projects/{projectId}/story): send back the line ids you read here to keep those lines and their voices. story is null until the project has a story. Each line says whether it has its voice; create_fake_text_voices (POST /v1/projects/{projectId}/story/voices) makes the missing ones.
Example use
Before it fixes a typo in one line, a script reads the story and keeps every line id. It sends the story back with those ids through update_fake_text_story (PUT /v1/projects/{projectId}/story), so only the corrected line loses its voice.
Endpoint
GET https://api.gpt-video.com/v1/projects/{projectId}/story- Scope
clips:read. - Rate limit 120 requests a minute for each key and 240 for each account, shared by every
readcall. See rate limits. - No
Idempotency-Key.
Parameters
Path
| Name | Type | Required | Description |
|---|---|---|---|
projectId | string | Required | The project id. It starts with prj_. Matches ^prj_[0-9a-f]{20}$. |
Request
Read the story.
curl "https://api.gpt-video.com/v1/projects/prj_ba8b07a88bfb14585459/story" \
-H "Authorization: Bearer $GPT_VIDEO_API_KEY"const res = await fetch("https://api.gpt-video.com/v1/projects/prj_ba8b07a88bfb14585459/story", {
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
},
});
const data = await res.json();
console.log(data);import os
import requests
r = requests.get(
"https://api.gpt-video.com/v1/projects/prj_ba8b07a88bfb14585459/story",
headers={
"Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
},
)
data = r.json()
print(data){
"method": "tools/call",
"params": {
"name": "get_fake_text_story",
"arguments": {
"projectId": "prj_ba8b07a88bfb14585459"
}
}
}Response
A successful call answers HTTP 200.
Fields to check
| Name | Type | Description |
|---|---|---|
story.id | string | The story id. It starts with cnv_. |
story.messages[].id | string | The line id. Send it back with update_fake_text_story (PUT /v1/projects/{projectId}/story) to keep the line and its voice. |
Response example
{
"story": {
"id": "cnv_a744d5ef6cc005e19285",
"projectId": "prj_ba8b07a88bfb14585459",
"title": "The surprise party",
"contactName": "Sam",
"language": "en",
"left": {
"name": "Sam"
},
"right": {
"name": "Me"
},
"voices": {
"left": "en-guy",
"right": "en-aria"
},
"messages": [
{
"id": "msg_e09afef44e32faf0bcb7",
"side": "left",
"text": "Are you free on Saturday night?",
"voiced": true,
"voiceDurationSec": 1.9
},
{
"id": "msg_568316dbc0cca81d3b24",
"side": "right",
"text": "Maybe, why?",
"voiced": false,
"voiceDurationSec": null
},
{
"id": "msg_556466181cf09d6bf0a2",
"side": "left",
"text": "No reason. Wear something nice.",
"voiced": true,
"voiceDurationSec": 1.9
},
{
"id": "msg_0d93572450a652e08706",
"side": "right",
"text": "Now I am worried.",
"voiced": false,
"voiceDurationSec": null
}
],
"voicedCount": 2,
"createdAt": "2026-08-31T22:12:00.000Z",
"updatedAt": "2026-08-31T22:14:00.000Z"
}
}All response fields
| Name | Type | Required | Description |
|---|---|---|---|
story | object or null | Required | The story of the project; null until it has one. |
story.id | string | Required | The story id. It starts with cnv_. |
story.projectId | string | Required | |
story.title | string | Required | |
story.contactName | string | Required | The name shown at the top of the chat. |
story.language | string | Required | One of en, it. |
story.left | object | Required | The other person in the chat. |
story.right | object | Required | The person whose phone shows the chat. |
story.voices | object | Required | The voice of each side, as list_voices (GET /v1/reference/voices) names it; null for the default voice of the language, or for a voice that is not available through the API. |
story.messages | array of objects | Required | |
story.voicedCount | integer | Required | How many lines have their voice. |
story.createdAt | string | Required | An ISO 8601 time in UTC. |
story.updatedAt | string | Required | An ISO 8601 time in UTC. |
Fields of story.left
| Name | Type | Required | Description |
|---|---|---|---|
story.left.name | string | Required |
Fields of story.right
| Name | Type | Required | Description |
|---|---|---|---|
story.right.name | string | Required |
Fields of story.voices
| Name | Type | Required | Description |
|---|---|---|---|
story.voices.left | string or null | Required | |
story.voices.right | string or null | Required |
Fields of story.messages[]
| Name | Type | Required | Description |
|---|---|---|---|
story.messages[].id | string | Required | The line id. Send it back with update_fake_text_story (PUT /v1/projects/{projectId}/story) to keep the line and its voice. |
story.messages[].side | string | Required | One of left, right. |
story.messages[].text | string | Required | |
story.messages[].voiced | boolean | Required | true when the line has its voice. |
story.messages[].voiceDurationSec | number or null | Required | How long the voice of the line lasts, in seconds; null without a voice. |
More examples
A project with no story yet
GET /v1/projects/prj_ba8b07a88bfb14585459/story
{
"story": null
}A project that is not a fake text project
GET /v1/projects/prj_7c2e9a4f1b3d4e8096a5/story
{
"error": {
"code": "CONFLICT",
"message": "This project is not a fake text project. Stories exist only in fake text projects.",
"requestId": "req_6e2a9c0d4b7f41583a1e9d6c"
}
}Errors
| Code | Status | When | What to do |
|---|---|---|---|
NOT_FOUND | 404 | See the error reference. | Change the request, then send it again. |
CONFLICT | 409 | A project that is not a fake text project | Read the resource again, then decide. Do not send the same request again. |
Every call can also answer these errors. VALIDATION_FAILED, UNKNOWN_PARAMETER, UNAUTHORIZED, SCOPE_MISSING, RATE_LIMITED, INTERNAL, UNAVAILABLE.
Cost
No credits are used.
Related operations
update_fake_text_story(PUT /v1/projects/{projectId}/story) Write the story of a fake text projectgenerate_fake_text_story(POST /v1/projects/{projectId}/story/generate) Write a fake text story with GPT-Videocreate_fake_text_voices(POST /v1/projects/{projectId}/story/voices) Make the voices of a fake text storyupdate_fake_text_project(PATCH /v1/projects/{projectId}/fake-text) Update a fake text project
Questions
Does a line keep its voice when I change its words?
It keeps the old voice until create_fake_text_voices (POST /v1/projects/{projectId}/story/voices) makes a new one for the new words. Lines whose words do not change are not voiced again.
Why is the voice of a side null?
null is the default voice of the language. It is also null when the project uses a voice that is not offered through the API; choose one with update_fake_text_story (PUT /v1/projects/{projectId}/story).