Why Promotion.GG calls this
Promotion.GG already creates proof, reports, offers, customer updates, and blog content. It calls ReelsBuilder when that written artifact should become a short-form video without Promotion.GG owning video editing orchestration, voice selection, captions, model routing, graphics, rendering, retries, or hosted asset delivery.
This endpoint is not a CMS writer and it does not post into Promotion.GG. Promotion.GG, Codex, or an AgenticFlow owns the autoblog/CMS/social write. ReelsBuilder owns the article-to-video orchestration layer and returns a durable video job.
Endpoint
POST https://api.reelsbuilder.ai/api/v1/blog-to-videoQuickstart
curl -X POST https://api.reelsbuilder.ai/api/v1/blog-to-video \
-H "Authorization: Bearer $REELSBUILDER_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"article_url": "https://promotion.gg/customer/acme-growth-recap",
"article_title": "How ACME turned creator traffic into measurable pipeline",
"article_summary": "A campaign recap showing how Promotion.GG converted creator reach into attributed signups.",
"article_text": "ACME launched a two-week creator campaign with Promotion.GG...",
"brand_id": "promotion-gg",
"platforms": ["youtube_shorts", "tiktok", "instagram"],
"duration_target_sec": 30,
"aspect_ratio": "9:16",
"content_style": "professional",
"agent_run_id": "promotion-autoblog-2026-05-20-001"
}'Accepted response
{
"success": true,
"data": {
"job_id": "job_...",
"generation_id": "vid_...",
"video_id": "vid_...",
"status": "queued",
"poll_url": "/api/v1/jobs/job_...",
"source_article": {
"url": "https://promotion.gg/customer/acme-growth-recap",
"title": "How ACME turned creator traffic into measurable pipeline",
"summary": "A campaign recap showing how Promotion.GG converted creator reach into attributed signups.",
"categories": [],
"tags": []
},
"distribution": {
"mode": "external_agent_distribution",
"requested_platforms": ["youtube_shorts", "tiktok", "instagram"],
"note": "ReelsBuilder orchestrates the article-to-video render. Your CMS, autoblog, Codex script, or AgenticFlow publishes the completed asset downstream."
},
"output_contract": {
"video_url": "available after completion on GET /api/v1/jobs/{job_id}.data.job.artifacts.videoUrl",
"captions": "available when the selected render path produces captions; consumers should tolerate an empty array",
"blog_embed": {
"type": "html_video_embed",
"source_url": "https://promotion.gg/customer/acme-growth-recap",
"title": "How ACME turned creator traffic into measurable pipeline",
"placement": "recommended near the first or second article section"
},
"headless_cms_payload": {
"component": "reelsbuilder_video",
"video_url": "<completed videoUrl>",
"caption_tracks": [],
"source_article_url": "https://promotion.gg/customer/acme-growth-recap"
},
"social_metadata": {
"title": "How ACME turned creator traffic into measurable pipeline",
"description": "A campaign recap showing how Promotion.GG converted creator reach into attributed signups.",
"platforms": ["youtube_shorts", "tiktok", "instagram"]
}
}
},
"meta": {
"agent_run_id": "promotion-autoblog-2026-05-20-001",
"key_mode": "live",
"retryable": false,
"estimated_completion_seconds": 180
}
}Request fields
| Field | Required | Description |
|---|---|---|
article_url | one content field | Canonical article, campaign, or CMS URL. Preserved for attribution and downstream embeds. |
article_title | one content field | Title used for the video topic, blog embed title, and social metadata. |
article_text | recommended | Extracted plain text. Best source for accurate narration and captions. |
article_markdown | recommended | Markdown article body. ReelsBuilder strips markup before generating the narration script. |
article_summary | no | Short summary for social description and fallback narration. |
script | no | Final narration script. If present, it overrides automatic article script extraction. |
brand_id | recommended | External or ReelsBuilder brand identifier to preserve in render metadata. |
asset_urls | no | Images, clips, logos, or screenshots to consider during the render. |
platforms | no | Intended targets for downstream publishing metadata. |
agent_run_id | recommended | Your trace id for reconciling the render with an autoblog, Codex, or AgenticFlow run. |
Autoblog agent pattern
const article = await promotion.getCampaignRecap("acme-growth-recap");
const runId = crypto.randomUUID();
const start = await fetch("https://api.reelsbuilder.ai/api/v1/blog-to-video", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.REELSBUILDER_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": runId,
},
body: JSON.stringify({
article_url: article.url,
article_title: article.title,
article_text: article.bodyText,
article_summary: article.excerpt,
brand_id: "promotion-gg",
platforms: ["youtube_shorts", "tiktok", "instagram"],
agent_run_id: runId,
}),
});
const accepted = await start.json();
const jobId = accepted.data.job_id;
let job;
for (;;) {
const status = await fetch(`https://api.reelsbuilder.ai/api/v1/jobs/${jobId}`, {
headers: { Authorization: `Bearer ${process.env.REELSBUILDER_API_KEY}` },
});
job = await status.json();
if (["completed", "failed", "cancelled", "dead_lettered"].includes(job.data.job.status)) break;
await new Promise((resolve) => setTimeout(resolve, 15000));
}
const videoUrl = job.data.job.artifacts.videoUrl;
await promotion.cms.attachVideoEmbed(article.id, {
component: "reelsbuilder_video",
video_url: videoUrl,
source_article_url: article.url,
});Sandbox and billing
- Live keys prefixed with
rb_queue paid renders and consume credits. - Sandbox keys prefixed with
rb_test_return fixtures and never create production jobs. - Every request requires
Idempotency-Keyso retries do not double-charge. - Each API key is limited to 5 active heavy render jobs by default.
- Polling is free but rate-limited; use 5 to 15 second intervals.