Automate weeks of videos with Doodaro and your AI agent (2026)
Plan a content calendar, then let a scheduler, an AI agent and the Doodaro API build a video every morning. Posting and scheduling stay in your own tools.
Last checked

“Automated” gets used loosely. This guide is exact about it. You can set up a system that wakes up every morning, builds a finished Doodaro video from a topic you approved, and hands the MP4 to a posting tool. Doodaro is one part of that system. The scheduler, the agent and the posting tool are yours.
The Doodaro API and Doodaro MCP are in beta. The limits are at the end of this guide, and they matter for automation.
What “automated” means here
What Doodaro does when your automation calls it: creates a project from your scenes, draws every scene in one of 37 styles, records the narration, renders an MP4 and returns a videoUrl. The project also appears in your dashboard, so you can open it and fix one scene by hand.
What Doodaro does not do: it does not wake up on its own, pick topics, post to YouTube or TikTok, or schedule posts. There is no built-in scheduler or recurring automation.
| Part of the system | Who does it | Examples |
|---|---|---|
| Start the run every morning | Your scheduler (third-party) | cron, GitHub Actions schedule, n8n, Make, Zapier |
| Pick the topic and write the script | Your AI agent or your script, from your calendar | Claude Code, Codex, Cursor, or a script reading a CSV |
| Draw, narrate, render | Doodaro API | create_project, generate_assets, render_video |
| Upload or schedule the post | Your posting step (third-party) | YouTube Data API, Buffer, Metricool, Publer, Later |
| Check quality | You | Script review before the build, a watch before publish |
The morning routine
Here is one run, start to finish. Only the teal step is Doodaro.
- 6:00Your schedulerThe scheduler wakes up
cron, a GitHub Actions schedule, n8n, Make or Zapier starts the run.
- ThenYour agent or scriptIt picks today's topic
It reads your content calendar and takes the row for today, only if you marked it approved.
- ThenYour agent or scriptIt writes the scenes
Title, narration and a picture description for every scene. Or it loads the script you already reviewed.
- ThenDoodaro APIDoodaro makes the video
Pictures in your style, narration in your voice, then the MP4 render. The run polls
get_jobuntil each job finishes. - ThenYour agent or scriptIt gets the MP4 link
result.videoUrlfrom the finished render job, plus the project'sdashboardUrl. - ThenThird-party posting toolThe post is uploaded or scheduled
The YouTube Data API or a scheduling tool takes the MP4. Or it waits for you to upload by hand.
- ThenYour automationYou get a summary
An email, a chat message or a line in your sheet: topic, video link, dashboard link, anything that failed.
Plan weeks or months ahead
Automation is only as good as the list it reads. Build the calendar first.
Build a content calendar
Use a CSV file, a Google Sheet, an Airtable base or a Notion database. Keep one row per video and a status column the automation checks before it spends anything.
| date | topic | style | narrator | format | platform | status |
|---|---|---|---|---|---|---|
| 2026-09-21 | Why the sky is blue | Color Chalkboard | deep English narrator | portrait | YouTube Shorts | approved |
| 2026-09-22 | How vaccines train your immune system | Sketch Note | calm English narrator | portrait | YouTube Shorts | approved |
| 2026-09-23 | What causes the seasons | Blueprint | deep English narrator | landscape | YouTube | draft |
| 2026-09-24 | Why bread rises | Crayon Stories | warm English narrator | square | idea |
Tips:
- Use style and narrator names, not ids. Let the agent or script look up the ids with
list_stylesandlist_voiceson each run. Never hard-code ids you guessed. - Keep a status column:
idea→draft→approved→rendered→posted. The run only buildsapprovedrows. - Vary the calendar. Mix topics and angles, and change styles between series. Do not publish near-identical videos.
Batch a week, or run daily
| One batch per week | One run per day | |
|---|---|---|
| How it works | On Sunday, build all 7 approved videos one after another | Every morning, build today’s video |
| Review | Watch all 7 videos in one sitting before they post | Watch each video the day it is made |
| Limits | Build videos in sequence to stay under 20 active jobs | Uses few jobs per run |
| If something fails | You have days to fix it | You may miss that day’s slot |
| Best for | Scheduling posts ahead in a posting tool | News-style or timely topics |
Many channels do both: batch the scripts once a week, build daily.
Keep a review queue
We recommend a human check before anything is published:
- Script review. The agent drafts scripts into files or a sheet. You read them, fix facts and set
statustoapproved. The run ignores everything else. - Video review. The run uploads as private or into a posting tool’s draft queue. You watch it, then publish. If a scene is wrong, open the
dashboardUrl, redraw or revoice that one scene and render again.
Recipe 1: Claude Code or Codex on a schedule
Your computer or a small server runs a coding agent every morning with a prompt file. The agent uses Doodaro MCP tools. First connect the agent to Doodaro MCP once (see Copy for AI and MCP).
The prompt file does the planning:
# prompts/daily-video.md
You make one Doodaro video per run. Use the doodaro MCP tools.
1. Open calendar.csv. Find the row where date is today and status is "approved".
If there is none, write "No approved topic today" to out/summary.txt and stop.
2. Read the reviewed script in scripts/<date>.md. Do not change the wording.
3. Call list_styles and list_voices. Use the style and narrator named in the row.
Never invent ids.
4. Call create_project with one scene per script section:
title, narration, visualDirection. Use the format from the row.
5. Call generate_assets. Call get_job every 5 seconds until each job is complete.
6. Call render_video. Call get_job every 5 seconds until it is complete.
7. Write the videoUrl and dashboardUrl to out/<date>.txt.
Set the row's status to "rendered".
If any job ends failed or uncertain, stop and write the error to out/summary.txt.
Never print the API key.
The cron entry runs it at 6:00 local time. Cron does not load your shell profile, so load the key from a private file:
# crontab -e
0 6 * * * cd "$HOME/channel" && . "$HOME/.doodaro.env" && claude -p "$(cat prompts/daily-video.md)" >> logs/daily.log 2>&1
# Codex instead of Claude Code:
# 0 6 * * * cd "$HOME/channel" && . "$HOME/.doodaro.env" && codex exec "$(cat prompts/daily-video.md)" >> logs/daily.log 2>&1
$HOME/.doodaro.env holds one line, export DOODARO_API_KEY="ddr_live_...". Make it readable only by you (chmod 600).
Notes:
- Check your agent’s CLI docs for non-interactive mode. Flags change between versions, and a headless run needs the Doodaro tools allowed without a confirmation prompt.
- An unattended agent cannot ask you before it spends. The
approvedstatus in your calendar is that confirmation, so the prompt must refuse anything else. - The computer has to be awake at 6:00. If it is often asleep, use Recipe 2.
- The agent’s own usage is billed by its provider, separately from Doodaro.
Recipe 2: GitHub Actions and a Node script
No agent at run time. A scheduled workflow runs a small script that calls the Doodaro API end to end. Your agent (or you) writes each day’s scenes into videos/<date>.json during the weekly batch, and merging that file into the repository is your approval.
Add the key as a repository secret named DOODARO_API_KEY (Settings → Secrets and variables → Actions). Then add the workflow:
# .github/workflows/daily-video.yml
name: Daily Doodaro video
on:
schedule:
- cron: '0 6 * * *' # 06:00 UTC every day
workflow_dispatch: # lets you run it by hand too
jobs:
make-video:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- id: doodaro
run: node scripts/make-video.mjs
env:
DOODARO_API_KEY: ${{ secrets.DOODARO_API_KEY }}
- run: echo "Video ready at ${{ steps.doodaro.outputs.video_url }}"
# Next step: your posting job (see Recipe 4), using steps.doodaro.outputs.video_url
GitHub schedules run in UTC and can start late when GitHub is busy. GitHub can also pause scheduled workflows in repositories with no recent activity, so check GitHub’s docs for scheduled events.
Today’s scenes file uses the same body as create_project:
{
"title": "Why the sky is blue",
"format": "portrait",
"styleId": "doodaro:<versionId from list_styles>",
"voice": {"id": "<voice id from list_voices>", "name": "<voice name>"},
"language": "en",
"scenes": [
{"title": "Hook", "narration": "The sky is not blue by accident.", "visualDirection": "A child looking up at a bright blue sky."},
{"title": "Sunlight", "narration": "Sunlight holds every color of the rainbow.", "visualDirection": "A beam of white light splitting into colors through a prism."}
]
}
And the script (Node 20 or newer, no packages):
// scripts/make-video.mjs
import { readFile, appendFile } from 'node:fs/promises';
const BASE = 'https://app.doodaro.com/api/v1';
const KEY = process.env.DOODARO_API_KEY;
const today = new Date().toISOString().slice(0, 10);
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
async function api(method, path, body, idempotencyKey) {
for (;;) {
const res = await fetch(BASE + path, {
method,
headers: {
Authorization: `Bearer ${KEY}`,
...(body ? { 'Content-Type': 'application/json' } : {}),
...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
if (res.status === 429) { // rate_limited: wait, then retry
await sleep(Number(res.headers.get('Retry-After') || 30) * 1000);
continue;
}
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error?.code}: ${data.error?.message}`);
return data;
}
}
async function waitForJob(id) {
for (;;) {
const job = await api('GET', `/jobs/${id}`);
if (['complete', 'failed', 'cancelled', 'uncertain'].includes(job.status)) return job;
await sleep(4000); // poll every 3 to 5 seconds
}
}
const video = JSON.parse(await readFile(`videos/${today}.json`, 'utf8'));
// 1. create_project with scenes
const project = await api('POST', '/projects', video);
// 2. generate_assets, then poll get_job
const { jobs } = await api('POST', `/projects/${project.id}/generate`, {}, `generate-${today}`);
for (const job of jobs) {
const done = await waitForJob(job.id);
if (done.status !== 'complete') throw new Error(`${job.kind} job ended ${done.status}: ${done.error ?? ''}`);
}
// 3. render_video, then poll get_job
const { render } = await api('POST', `/projects/${project.id}/renders`, { kind: 'video' }, `render-${today}`);
const finished = await waitForJob(render.id);
if (finished.status !== 'complete') throw new Error(`render ended ${finished.status}: ${finished.error ?? ''}`);
// 4. print the MP4 link for the next step
const videoUrl = finished.result.videoUrl;
console.log(`videoUrl: ${videoUrl}`);
console.log(`dashboardUrl: ${project.dashboardUrl}`);
if (process.env.GITHUB_OUTPUT) await appendFile(process.env.GITHUB_OUTPUT, `video_url=${videoUrl}\n`);
create_project does not take an Idempotency-Key. If a run fails after the project was created, do not rerun blindly: call list_projects, open the existing project, and continue from generate_assets (it skips scenes that are already done). The full operation list is in the API reference, and the quickstart walks through the same calls with curl.
Recipe 3: n8n, Make or Zapier
The same flow works in a no-code tool with HTTP request steps. Each tool names its steps differently, so treat this as the step list and check the tool’s docs for the exact module names. Loops and waits may need a paid plan; check each tool’s current plan.
- Schedule trigger: every day at 6:00 in your time zone.
- Read the calendar: get today’s row from Google Sheets, Airtable or Notion. Add a filter that stops unless
statusisapproved. - Optional AI step: have your AI model turn the approved script into a JSON
scenesarray (title, narration, visualDirection). - HTTP request, POST
https://app.doodaro.com/api/v1/projectswith headerAuthorization: Bearer <your key>and the project body. Saveid. - HTTP request, POST
/projects/{id}/generatewith body{}. Save eachjobs[].id. - Wait and check: wait about a minute, then GET
/jobs/{jobId}. Repeat untilstatusiscomplete(or stop onfailedoruncertain). - HTTP request, POST
/projects/{id}/renderswith body{"kind": "video"}. Saverender.id. - Wait and check the render job the same way. Save
result.videoUrl. - Update the calendar row: set
statustorenderedand store the video link anddashboardUrl. - Hand off: send the link to your posting step (Recipe 4) and a summary to email or chat.
Store the key in the tool’s credentials or secrets store, never in a visible text field of a shared workflow.
Recipe 4: posting the video (third-party)
Doodaro stops at the MP4 link. Posting is a separate step with tools Doodaro does not run.
YouTube Data API. Your automation downloads the MP4 from videoUrl and uploads it with the API’s videos.insert method, authorized with Google OAuth for your channel. To schedule instead of publishing at once, upload as private and set a publish time. Google sets the quota and the review rules for API projects, so read the YouTube Data API docs before you build this.
A social scheduling tool. Buffer, Metricool, Publer and Later can queue videos for several platforms. Some accept a file upload, some a link, and some offer an API or a Zapier or Make integration. Check each tool’s current plan and platform support.
By hand. Many channels keep this step manual on purpose: the run drops the video link in a sheet, and you upload in YouTube Studio after you watch it.
Wherever you post, turn on the platform’s AI-content label when it asks, and turn on auto-captions.
Costs and limits
- Doodaro plans (launch prices, billed monthly in USD): Starter $39/month for 120 minutes, Creator $75/month for 240 minutes, Pro $149/month for 510 minutes. Minutes are counted on rendered exports. A daily 60-second Short is about 30 minutes a month; a daily 8-minute video is about 240. See pricing explained.
- During the beta, minutes are not metered and per-key spending caps are planned, not enforced. Every account, including a free one, has its own API keys.
- Production limits: 20 active jobs, 60 per hour, 200 per day. Rate limits: 120 requests per minute per key, 30 spending requests (plan, generate, render) per minute. Details in the API reference.
- Your agent and model costs are separate. Claude Code, Codex, Cursor, n8n, Make, Zapier, GitHub Actions and posting tools each bill on their own terms.
Quality and policy checklist
- A person reviews every script before its row is
approved. - A person watches every video before it goes public.
- Topics, angles and styles vary. YouTube asks creators to avoid repetitive, mass-produced content; review every script and vary your videos.
- The platform’s AI-content label is on when the platform asks for it.
- Platform auto-captions are on. Exported MP4s do not include captions yet.
-
DOODARO_API_KEYlives only in your scheduler’s secrets or a private env file. Never in a repository, a prompt you share or a public workflow. - Each automation has its own key, named so you know which one to revoke in Developer.
- The run sends you a summary, including failures.
Troubleshooting
| What you see | What it means | What to do |
|---|---|---|
409 script_not_ready |
Script edits are not applied to scenes yet. Usually a project created from script instead of scenes. |
Create projects with a scenes array, or finish planning with apply_plan or update_scene first. |
409 not_ready on render |
A scene is missing a picture or narration, an asset is stale, or the plan is not complete. | Call get_project and read readiness.blockers. Run generate_assets again (it only does what is missing), wait for the jobs, then render. |
429 rate_limited |
Too many requests, or production limits reached (20 active, 60 per hour, 200 per day). | Wait for the Retry-After seconds. Build videos one after another, not in parallel. |
Job status uncertain |
The outcome could not be confirmed. | Call get_project or list_renders before you retry. If you do retry, reuse the same Idempotency-Key so work that already started is not paid for twice. |
Job status failed |
That job stopped with an error. | Read error. Regenerate only the affected scenes with sceneIds. |
401 unauthorized |
The key is missing, wrong or revoked. | Check the secret name in your scheduler. Create a new key in Developer if it was revoked. |
Related
- AI & MCP: make videos by talking to Claude Code, Codex or Cursor.
- Developer quickstart: key to downloaded MP4 with curl and JavaScript.
- API reference: every operation, error code and limit.
- Faceless YouTube channels: why drawn video works for faceless channels.
- How to start a faceless YouTube channel: the plan before you automate anything.
Frequently asked questions
Can Doodaro make and post a video every day automatically?
Doodaro can make the video when something calls its API. The daily trigger and the posting are yours to set up: a scheduler such as cron, GitHub Actions, n8n, Make or Zapier starts the run, and the YouTube Data API or a scheduling tool posts the MP4. Doodaro does not post or schedule by itself.
Does Doodaro have a built-in scheduler?
No. There is no scheduler, recurring automation or publishing inside Doodaro. You start runs from your own scheduler and the Doodaro API does the video work.
Can I schedule YouTube uploads of videos made with Doodaro?
Yes, outside Doodaro. Upload the MP4 in YouTube Studio and pick a publish time, upload it through the YouTube Data API as a private video with a publish time, or use a scheduling tool such as Buffer, Metricool, Publer or Later. Check each tool's current plan and platform support.
How many videos can I make per day with the Doodaro API?
During the beta, production limits apply: 20 active jobs, 60 per hour and 200 per day. Each video uses several jobs (pictures, narration and the render), so run videos one after another. Minutes are not metered yet.
Do I need GitHub, n8n or Zapier to automate Doodaro?
No. Any tool that can run on a schedule and send an HTTPS request works. A cron job on your own computer, a GitHub Actions workflow and a no-code tool are three common choices. Pick the one you already use.
Should I review every video before it goes live?
Yes. Review each script before the build and watch each video before it publishes. YouTube asks creators to avoid repetitive, mass-produced content; review every script and vary your videos.
Do videos made through the API have captions?
Not yet. Caption settings are saved but not drawn into exported MP4s. Turn on the platform's auto-captions when you upload.
Can ChatGPT run this automation?
Not today. ChatGPT and Claude chat connectors need sign-in, which is coming soon. Use Claude Code, Codex, Cursor, another MCP client that can send an API key header, or a plain script.