Automate short vertical AI videos (TikTok / Reels / Shorts) using SORA-2 + n8n. This guide explains the workflow, provides practical tips, and shows exactly where to paste your importable n8n JSON.
Keywords: SORA-2, n8n workflow, AI video generator, OpenAI video API, vertical video automation, TikTok automation
TL;DR
- Simple n8n pipeline: trigger → create video → wait → fetch content → deliver.
- Use vertical format for short-form:
720x1280(or1024x1792if supported). - Do not hardcode API keys in public JSON — use n8n credentials or environment variables.
Why this workflow
No extra servers — everything runs inside n8n. This minimal pipeline uses the OpenAI/SORA-2 video endpoint to create short cinematic videos from text prompts, and is easy to extend with TTS, stock assets, FFmpeg post-processing, or auto-posting integrations.
What you’ll get (overview)
- A chat/Telegram/webhook trigger to accept prompts.
- An HTTP node that calls
POST /v1/videos(SORA-2) withmodel,prompt,seconds, andsize. - A loop/wait pattern to poll until the job completes.
- A second HTTP node to fetch
/v1/videos/{id}/content. - Instructions to save and upload the output to TikTok (manual upload recommended if you don’t have paid auto-posting access).
Prerequisites & safety
- OpenAI API key with credits — SORA-2 video generation is not free.
- n8n instance (self-hosted or cloud) with permissions to make external HTTP requests.
- Do not paste real API keys into public posts or the workflow JSON. Use n8n credentials or environment variables.
- Supported
sizevalues vary by provider. Recommended portrait:720x1280.
How the workflow works — node by node
1) Trigger (When message received)
Use a Telegram trigger, webhook, Slack event, or chat trigger. The node should output the user’s text as $json.chatInput (or another field you choose).
2) HTTP Request — Create video (POST /v1/videos)
Important fields to send in the JSON body:
model:"sora-2"prompt: e.g.={{ $json.chatInput }}. Create a cinematic vertical video (portrait 9:16).seconds: desired video length (8–40 seconds recommended)size: use a supported value —720x1280for TikTok
Header: Authorization: Bearer <YOUR_KEY> (use n8n credentials instead of hardcoding).
3) Split / Loop
Use SplitInBatches when you may receive many requests at once — it helps rate limit and queue jobs.
4) Wait node
After creating the job, wait (e.g., 30–60 seconds depending on video length) before fetching the result. For longer videos increase wait time or implement polling.
5) Fetch video content (GET /v1/videos/{id}/content)
Use the job ID returned by the create call to request the final content. The node may return a file or a downloadable URL. If you receive a 202 or “not ready” status, loop and retry after another wait.
6) Deliver
Save to disk, send via Telegram, or pass to another node for upload. Manual upload to TikTok is often easiest because auto-posting APIs frequently require paid tiers.
How to import into n8n
- Open n8n → Workflows → Import from Clipboard.
- Paste the JSON (the one you added above) and import.
- Edit each HTTP Request node and switch the Authorization header to use n8n Credentials (do not keep raw keys in the workflow).
- Connect your trigger node to your real input (Telegram, webhook, Slack, etc.).
- Save, test, and activate the workflow.
Practical prompt & quality tips
- Add framing & quality instructions to the prompt: “portrait 9:16, cinematic lighting, high detail, no watermark”.
- Camera cues help: “slow dolly in, close-up, shallow depth of field”.
- Keep videos between 8–40 seconds for cost predictability and reliable generation times.
Troubleshooting — common errors & fixes
Bad request — Unknown parameter Remove unsupported fields (e.g., quality). Use only accepted parameters: model, prompt, seconds, size. Invalid size value Use supported sizes like 720x1280, 1280x720, 1024x1792, or 1792x1024 depending on the provider. Job returns 202 / not ready Increase Wait time or implement a polling loop that retries until the job status is complete. Binary file not returned Check whether the API returns a direct file or a URL. For binary files, ensure the n8n node is set to handle binary responses.
Production & security considerations
- Use n8n credential manager / environment variables for API keys.
- Implement concurrency limits (SplitInBatches) to avoid rate limit errors and runaway costs.
- Log job IDs and errors to a simple storage (Google Sheets, DB, or file) for retries.
- Consider adding a pre-validation step to block overly long requests.
Wrap-up
This guide gives you a lean, practical foundation to generate vertical AI videos with SORA-2 inside n8n. It’s modular, low-friction, and suitable for experimenting with short-form content at scale. Paste your workflow JSON where indicated, secure your keys, and you’ll be up and running.
If you want, I can also produce a step-by-step screenshot tutorial for n8n, or add TTS + FFmpeg steps to the workflow — tell me which one and I’ll draft it next.
— Published by [WASEEM NASIR]. Want the ready workflow or need help customizing it? Comment or DM.
Hire us on fiverr for COMPLEX AUTOMATIONS –> https://www.fiverr.com/skynetjoe843/create-cinematic-ai-video-ads-with-google-veo3-flow-or-gemini
{
"name": "SOR2 AI",
"nodes": [
{
"parameters": {
"method": "POST",
"url": "https://api.openai.com/v1/videos",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_OPENAI_API_KEY_HERE"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "model",
"value": "sora-2"
},
{
"name": "prompt",
"value": "={{ $json.chatInput }}"
},
{
"name": "seconds",
"value": "8"
},
{
"name": "size",
"value": "720x1280"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-688,
160
],
"id": "9bde0606-a619-47ee-b3bb-18debd5e98e3",
"name": "Create Video Request"
},
{
"parameters": {
"amount": 60
},
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
-480,
160
],
"id": "bdd78cec-e0bd-4ad1-8817-a051ee7a6968",
"name": "Initial Wait",
"webhookId": "initial-wait-webhook"
},
{
"parameters": {
"url": "=https://api.openai.com/v1/videos/{{ $json.id }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_OPENAI_API_KEY_HERE"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-272,
160
],
"id": "cd966a6d-fb64-40c1-aaee-16083c7bfb8d",
"name": "Check Video Status"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "status-condition",
"leftValue": "={{ $json.status }}",
"rightValue": "completed",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-64,
160
],
"id": "a4456f8b-9a6a-4e0e-86ac-2ef75e3903e8",
"name": "Is Video Ready?"
},
{
"parameters": {
"amount": 60
},
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
144,
272
],
"id": "94caf1f1-0875-4a6a-b88f-72e800220089",
"name": "Wait Before Retry",
"webhookId": "poll-wait-webhook"
},
{
"parameters": {
"url": "=https://api.openai.com/v1/videos/{{ $json.id }}/content",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_OPENAI_API_KEY_HERE"
}
]
},
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
144,
32
],
"id": "2718e8f0-09f5-40a8-8400-7a6c18acfc9e",
"name": "Get Video Content"
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"typeVersion": 1.3,
"position": [
-896,
160
],
"id": "22de28e0-2e89-42c9-a008-f3844c615eef",
"name": "When chat message received",
"webhookId": "aef99f21-a861-48c3-b3ed-3ee8f455fd65"
}
],
"pinData": {},
"connections": {
"Create Video Request": {
"main": [
[
{
"node": "Initial Wait",
"type": "main",
"index": 0
}
]
]
},
"Initial Wait": {
"main": [
[
{
"node": "Check Video Status",
"type": "main",
"index": 0
}
]
]
},
"Check Video Status": {
"main": [
[
{
"node": "Is Video Ready?",
"type": "main",
"index": 0
}
]
]
},
"Is Video Ready?": {
"main": [
[
{
"node": "Get Video Content",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait Before Retry",
"type": "main",
"index": 0
}
]
]
},
"Wait Before Retry": {
"main": [
[
{
"node": "Check Video Status",
"type": "main",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "Create Video Request",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "e20775ca-dac7-4ed4-a236-54e32cd1a99d",
"meta": {
"templateId": "2605",
"templateCredsSetupCompleted": true,
"instanceId": "9622f2c93ad62f58d649d22206e9307de9de2cdac0c7993ee74f7a36882d6cab"
},
"id": "utzKQPrdahMRoTbK",
"tags": []
}

