Create a Reddit story project
create_reddit_story_projectPOST/v1/projects/reddit-storyBeta
Creates a Reddit story project: a post read by a synthetic voice over a background video, with a title card and captions.
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
Send the post, who wrote it and where, the voice and the language: list_voices (GET /v1/reference/voices) names the voices of each language. The background video is optional and can be changed later. Everything can be changed with update_reddit_story_project (PATCH /v1/projects/{projectId}/reddit-story). Nothing is built and no credits are used until you call build_reddit_story_video (POST /v1/projects/{projectId}/reddit-story/build). Send an Idempotency-Key: a retry without one creates a second project.
Example use
A channel that posts story videos sends the text of a post, the author shown on the title card and a gameplay background. It picks a voice from list_voices (GET /v1/reference/voices) that speaks the language of the post.
Endpoint
POST https://api.gpt-video.com/v1/projects/reddit-story- Scope
clips:write. - Rate limit 60 requests a minute for each key and 120 for each account, shared by every
writecall. See rate limits. Idempotency-Keyis optional.
Parameters
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string | Optional | Send the same key on every retry of this request. From 1 to 255 visible characters, such as a UUID. See idempotency. |
Body
| Name | Type | Required | Description |
|---|---|---|---|
postTitle | string | Required | The title of the post, shown on the title card and read first. From 1 to 300 characters. From 1 to 300 characters. Matches \S. |
postBody | string | Required | The text of the post, read by the voice. From 1 to 8000 characters. From 1 to 8000 characters. Matches \S. |
author | string | Required | The author shown on the title card, such as u/thrown_away. From 1 to 40 characters. From 1 to 40 characters. |
subreddit | string | Required | The community shown on the title card, such as r/stories. From 1 to 40 characters. From 1 to 40 characters. |
voice | string | Required | The voice that reads the story, as list_voices (GET /v1/reference/voices) names it. It must be a voice of the story's language. One of en-aria, en-jenny, en-guy, en-christopher, it-elsa, it-isabella, it-diego, it-giuseppe. |
language | string | Required | The language of the story and of its voice. One of en, it. |
captionStyle | string | Required | The caption style. get_setting_options (GET /v1/reference/setting-options) lists every style with what it looks like. One of bold-karaoke, word-pop, boxed, outline. |
backgroundAssetId | string or null | Required | The background video, as complete_upload (POST /v1/uploads/{uploadId}/complete) returned it; null for none. Matches ^ast_n?[0-9a-f]{20}$. |
vocabulary | string | Optional | Names, brands and jargon the transcription should spell right, separated by commas. At most 311 characters. At most 311 characters. |
title | string | Optional | A name for the project, shown in the GPT-Video app. Leave it out to get a default name. From 1 to 120 characters. Matches \S. |
Send only the fields listed here. Any other field is refused with UNKNOWN_PARAMETER.
Request
Create a Reddit story project.
# 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/reddit-story" \
-H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
-d '{
"postTitle": "I said no to my boss'\''s weekend trip",
"postBody": "My boss planned a team trip on my only free weekend of the month. I said no, and now the team thinks I am the problem.",
"author": "u/weekend_keeper",
"subreddit": "r/stories",
"voice": "en-jenny",
"language": "en",
"captionStyle": "bold-karaoke",
"backgroundAssetId": "ast_8ac5d8b97546145cdbf6"
}'// 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/reddit-story", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
"postTitle": "I said no to my boss's weekend trip",
"postBody": "My boss planned a team trip on my only free weekend of the month. I said no, and now the team thinks I am the problem.",
"author": "u/weekend_keeper",
"subreddit": "r/stories",
"voice": "en-jenny",
"language": "en",
"captionStyle": "bold-karaoke",
"backgroundAssetId": "ast_8ac5d8b97546145cdbf6"
}),
});
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/reddit-story",
headers={
"Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
"Idempotency-Key": idempotency_key,
},
json={
"postTitle": "I said no to my boss's weekend trip",
"postBody": "My boss planned a team trip on my only free weekend of the month. I said no, and now the team thinks I am the problem.",
"author": "u/weekend_keeper",
"subreddit": "r/stories",
"voice": "en-jenny",
"language": "en",
"captionStyle": "bold-karaoke",
"backgroundAssetId": "ast_8ac5d8b97546145cdbf6"
},
)
data = r.json()
print(data){
"method": "tools/call",
"params": {
"name": "create_reddit_story_project",
"arguments": {
"postTitle": "I said no to my boss's weekend trip",
"postBody": "My boss planned a team trip on my only free weekend of the month. I said no, and now the team thinks I am the problem.",
"author": "u/weekend_keeper",
"subreddit": "r/stories",
"voice": "en-jenny",
"language": "en",
"captionStyle": "bold-karaoke",
"backgroundAssetId": "ast_8ac5d8b97546145cdbf6"
}
}
}Response
A successful call answers HTTP 201. Returns a Project object in project.
Fields to check
| Name | Type | Description |
|---|---|---|
project.id | string | The project id. It starts with prj_. |
project.status | string | draft has not been analyzed yet, processing is being analyzed, ready has clips, failed means the last analysis failed and errorMessage says why. |
Response example
{
"project": {
"id": "prj_e94a1c6b07d35f28c1b4",
"kind": "redditstory",
"title": "Reddit story",
"status": "draft",
"sourceAssetId": null,
"compositionId": null,
"settings": null,
"missingSettings": [],
"errorMessage": null,
"splitScreen": null,
"streamer": null,
"redditStory": {
"postTitle": "I said no to my boss's weekend trip",
"postBody": "My boss planned a team trip on my only free weekend of the month. I said no, and now the team thinks I am the problem.",
"author": "u/weekend_keeper",
"subreddit": "r/stories",
"voice": "en-jenny",
"language": "en",
"backgroundAssetId": "ast_8ac5d8b97546145cdbf6",
"captionStyle": "bold-karaoke",
"vocabulary": null
},
"fakeText": null,
"vibeEdit": null,
"createdAt": "2026-09-01T11:00:00.000Z",
"updatedAt": "2026-09-01T11:00:00.000Z"
}
}All response fields
| Name | Type | Required | Description |
|---|---|---|---|
project | Project object | Required | Described in Project object. |
More examples
A voice of another language
POST /v1/projects/reddit-story
{
"postTitle": "I said no to my boss's weekend trip",
"postBody": "My boss planned a team trip on my only free weekend of the month. I said no, and now the team thinks I am the problem.",
"author": "u/weekend_keeper",
"subreddit": "r/stories",
"voice": "it-elsa",
"language": "en",
"captionStyle": "bold-karaoke",
"backgroundAssetId": null
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "Voice it-elsa is not available in en. Call list_voices to see the voices you can use.",
"hint": "Fix the request as the message says, then send it again.",
"requestId": "req_b0e7d3a9c6f2418e5d0b7a31"
}
}A background video that does not exist
POST /v1/projects/reddit-story
{
"postTitle": "I said no to my boss's weekend trip",
"postBody": "My boss planned a team trip on my only free weekend of the month. I said no, and now the team thinks I am the problem.",
"author": "u/weekend_keeper",
"subreddit": "r/stories",
"voice": "en-guy",
"language": "en",
"captionStyle": "bold-karaoke",
"backgroundAssetId": "ast_0b1e5c9d3a7f40628e2d"
}{
"error": {
"code": "NOT_FOUND",
"message": "Asset ast_0b1e5c9d3a7f40628e2d not found",
"hint": "Check the id. An id that belongs to another account is not found either.",
"requestId": "req_4c1e8b5f2d9a06c73e1b8d52"
}
}Errors
| Code | Status | When | What to do |
|---|---|---|---|
NOT_FOUND | 404 | A background video that does not exist | Change the request, then send it again. |
CONFLICT | 409 | The background is not a video, or the file of the background video was deleted to free up storage. The message says which one. | 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, IDEMPOTENCY_IN_PROGRESS, PAYLOAD_TOO_LARGE, IDEMPOTENCY_KEY_REUSED, RATE_LIMITED, INTERNAL, UNAVAILABLE.
Cost
No credits are used. The build is charged when you call build_reddit_story_video (POST /v1/projects/{projectId}/reddit-story/build).
Related operations
update_reddit_story_project(PATCH /v1/projects/{projectId}/reddit-story) Update a Reddit story projectbuild_reddit_story_video(POST /v1/projects/{projectId}/reddit-story/build) Build a Reddit story videoestimate_analysis(POST /v1/projects/{projectId}/analyze/estimate) Estimate the credits of an analysis or a buildcomplete_upload(POST /v1/uploads/{uploadId}/complete) Complete an uploadlist_voices(GET /v1/reference/voices) List the voices
Questions
Why must I choose the author and the community?
They are text in the video, on the title card. Nothing is filled in for you, so the video shows only what you chose.
Which voices can I use?
list_voices (GET /v1/reference/voices) lists them with their language. The voice must be one of the story's language; another one is refused with VALIDATION_FAILED.