Set it up
Step-by-step setup
Follow the steps in order. Stay on private visibility until a test Short appears in YouTube Studio.
#Get the API keys
#JSON2Video
- Sign up at json2video.com and copy the API key from the dashboard.
- If you will post commercially, upgrade off the free watermarked plan. Official paid billing is 1 credit per second. See pricing.
#OpenAI or OpenRouter
Pick one, then set Config llm_provider to openai or openrouter.
- OpenAI: create an API key at platform.openai.com. This is not a ChatGPT Plus login.
- OpenRouter: create a key at openrouter.ai. Set
llm_modelto a model id your account can call (change the defaultgpt-4o-miniif it is not available).
Captions do not need a separate Whisper key. JSON2Video auto-subtitles use the official model: whisper (or default / elevenlabs / deepgram) on the movie itself.
#Zernio and YouTube
- Sign up at zernio.com and copy the API key.
- Connect the YouTube channel (
GET /v1/connect/youtube— see Zernio YouTube). Sign in as the Google identity that owns the channel. - Copy the connected account id. You will paste it into Config
zernio_account_id.
#Telegram (optional)
Only if you will enable the disabled Telegram: Preview Ready node. Create a bot with @BotFather and copy the bot token and chat id.
#Create the Google Sheet
- Create a new Google Sheet.
- Rename the first tab to exactly
queue. - Import or paste
sample-queue.csv(header plus three fictional examples). You can delete the sample data rows later; keep the header row. - Add a second tab named
error_logand pasteerror-log-header.csv. - Copy the Sheet ID from the URL:
https://docs.google.com/spreadsheets/d/THIS_ID/edit.
#Queue statuses
| Status | Meaning | Who sets it |
|---|---|---|
queued |
Waiting to render | The form, or you typing a new row |
rendering |
JSON2Video job in flight (project id saved on the row) | Ingest & Render |
awaiting_approval |
Preview and draft metadata are ready | Ingest & Render |
approved |
You have watched the preview and want it posted | You |
publishing |
Zernio request in flight | Post Approved |
posted |
Published (or uploaded now) | Post Approved |
scheduled |
Zernio accepted a future scheduledFor |
Post Approved |
failed |
See the error column and error_log |
Either workflow |
Any other status is ignored. Rows are never posted from awaiting_approval.
#Create n8n credentials
Do not paste API keys into node parameters. Use these names so they match the imported JSON (you can rename later, but then re-select the credential on every node that uses it).
| Credential name in n8n | Type | How to fill it |
|---|---|---|
| Google Sheets (Auto Shorts Queue) | Google Sheets OAuth2 | Sign in with the account that owns the Sheet. |
| JSON2Video API | Header Auth | Name: x-api-key. Value: your JSON2Video API key. |
| OpenAI | OpenAI | API key from the OpenAI API platform. Skip if you only use OpenRouter. |
| OpenRouter API | Header Auth | Name: Authorization. Value: Bearer + your OpenRouter key (include the word Bearer and a space). Skip if you only use OpenAI. |
| Zernio API | Header Auth | Name: Authorization. Value: Bearer + your Zernio key. |
| Telegram (Auto Shorts) | Telegram | Bot token. Only needed if you enable the Telegram node. |
After import, open each HTTP Request or Sheets node and confirm the credential is selected. The JSON uses id: REPLACE_ME, so n8n will ask you to pick the real credential on first edit.
#Import the workflows
Import order matters because the other workflows point at the error handler by name.
- Import
auto-shorts-error-handler.json. Open Config, paste the Sheet ID, leaveerror_sheet_nameaserror_log. Select the Google Sheets credential on Log Error to Sheet. Save. - Import
auto-shorts-submit-form.json,auto-shorts-ingest-render.json, andauto-shorts-post-approved.json. - In each workflow, open Config and paste the same Sheet ID, timezone,
zernio_account_id(on Ingest and Post), andllm_provider. Re-select credentials on every node that shows a warning.
- For each of the three producer workflows: Workflow settings (the
…menu) → Error workflow → Auto Shorts – Error Handler. Leave every workflow inactive / unpublished. - Share the Google Sheet with the Google account used in the credential if they are not the same.
#Run a private test
- Confirm a test clip is reachable at a public
https://URL. A signed URL must last for the whole render — JSON2Video downloads media during the render, not at submit time. - Add a
queuedrow (the form or the Sheet).idmust be unique (the form usesAS-YYYYMMDD-xxxx). - Open Auto Shorts – Ingest & Render → Manual Test Run. A 30-second clip often takes one to a few minutes plus polling (default 40 × 10 seconds).
- Confirm the row is
awaiting_approvalandpreview_urlplays. Check captions. Edit title, description, tags, visibility, orscheduled_atif you want. - Set
statustoapproved. Leavevisibilityasprivate. - Open Auto Shorts – Post Approved → Manual Test Run.
- Confirm YouTube Studio shows the private video (or a scheduled item) and the Sheet shows
postedorscheduledwithzernio_post_id. - Only then publish (activate) the form, ingest, and post workflows.
The production form URL is /form/auto-shorts-submit on your n8n host (shown on the Form Trigger node). During tests, use Execute workflow and the Test URL — a production form URL only works when the workflow is active.
#Optional Telegram notices
- Select Telegram (Auto Shorts) on Telegram: Preview Ready.
- Put the chat id in Config
telegram_chat_id. - Enable the node (toggle off Disabled).
- Approval is still a Sheet status change. Telegram is notify-only in v1.
#Config defaults you can change
These live in the Config node of each workflow. Keep the shared values in sync.
| Field | Default | Meaning |
|---|---|---|
timezone |
Asia/Taipei |
Form timestamps and Zernio scheduledFor values that have no Z or offset. |
subtitle_model |
whisper |
Official enum: whisper, default, elevenlabs, or deepgram. |
subtitle_language |
auto |
Official language or auto. |
subtitle_settings |
boxed-word, Oswald Bold, 90 px | Official subtitles settings keys only. |
output_width / output_height |
1080 / 1920 |
Official resolution: custom. |
render_quality |
high |
Official low, medium, or high. |
poll_seconds |
10 |
Documented target. The Wait node is a static 10 — edit that node too if you change this. |
poll_max_attempts |
40 |
About 6–7 minutes of polling. |
max_renders_per_run |
3 |
Caps paid renders per scheduled tick. |
max_posts_per_run |
5 |
Caps Zernio posts per tick. |
llm_provider |
openai |
openai or openrouter. |
llm_model |
gpt-4o-mini |
Chat-completions model id. |
youtube_visibility |
private |
Official public, private, or unlisted. Start private. |
made_for_kids |
false |
Always sent. Override per row if needed. |
contains_synthetic_media |
false |
Set true on the row or in Config when it applies. |