POST a topic or a script. Get back a narrated, captioned video you can publish. Three endpoints, one bearer key, and a webhook so you never have to poll.
This is the same API the app itself uses, and the same one behind the Claude connector. If you are wiring this into Make, Zapier, n8n or your own backend, everything you need is on this page.
Every request carries an API key as a bearer token:
Authorization: Bearer hawk_live_xxxxxxxx_xxxxxxxxxxxxxxxxxxxx
Create a key in the app under Integrations & automation → API keys. Keys are shown once and stored
only as a SHA-256 hash — we cannot recover one for you, so if you lose it, revoke and issue
a new one. A key carries scopes; video:create is required to create or re-cut.
curl -X POST https://automatedvideoapp.com/api/videos \
-H "Authorization: Bearer $HAWK_KEY" \
-H "Content-Type: application/json" \
-d '{
"topic": "Three stretches for desk workers",
"lang": "en",
"visual_mode": "stills",
"image_source": "ai_stills",
"target_seconds": 60,
"webhook_url": "https://example.com/hooks/video-done"
}'
| Field | Type | Notes |
|---|---|---|
topic | string | What the video is about. The scenes and narration are written for you. Provide this or script. |
script | string | Your own narration, verbatim. Scenes are cut to match it. |
title | string | Optional. Defaults to the topic. |
lang | string | One of en fr es de it pt ru nl pl ar hi ja zh ko. Default en. |
visual_mode | string | stills (default), video_hybrid, video_full, avatar. See the table below. |
image_source | string | ai_stills (default) generates with AI and uses your Pollen — the only still source that costs anything. stock_footage uses real video clips, stock_photo real photographs, stock alternates between them; all three are free. Applies to still scenes only. |
target_seconds | integer | 15–180. Default 60. Treated as a target, not a hard cut. |
brand_mode | string | expert (default) uses your branding. |
voice | string | male (default), female, or English-only warm, narrator, british_male, british_female. A specific edge-TTS name such as en-US-JennyNeural also works, but one whose language does not match lang is rejected rather than used. |
visual_style | string | editorial (default), cinematic, documentary, bright, bold, warm. Affects generated visuals only — stock footage is unchanged. |
aspect | string | 16:9 (default, YouTube), 9:16 (Shorts, TikTok, Reels), 1:1 (square feed). See Frames. |
still_quality | string | standard (default) uses the gateway's free model at a modest size — what a free Pollinations tier authorises. high and max use the premium flux model at larger sizes and need a tier that permits them; a balance alone is not enough. A refused request returns 402 upstream and the scene falls back to stock. |
user_images | array | Your own pictures, used instead of AI or stock. See Using your own images. |
webhook_url | string | We POST here when the render finishes. Strongly preferred over polling. |
Pick by where the video will be watched, not by preference — a 16:9 video posted as a Short is letterboxed on both sides.
aspect | Size | For |
|---|---|---|
16:9 | 1280×720 | YouTube, embeds, anything landscape. The default; omitting the field is identical to sending it. |
9:16 | 720×1280 | YouTube Shorts, TikTok, Instagram and Facebook Reels. Captions sit at 16% of the height rather than a fixed 60px, so the platform's own buttons do not cover them. |
1:1 | 720×720 | Square feed posts. |
In a non-landscape frame, wide stock footage fills the frame over a blurred copy of itself rather than sitting in black bars. A wide photo is centre-cropped to fill — that loses the sides, and there is no way around it.
Two steps: get a signed upload URL, PUT the file straight to storage, then name the key when you create the video. The file never passes through the API — a function body caps around 6 MB and base64 inflates a payload by a third, so an ordinary phone photo would fail.
# 1. ask for a signed upload (JPEG, PNG or WebP; 12MB each, 12 at a time)
curl -X POST https://automatedvideoapp.com/.netlify/functions/uploads \
-H "authorization: Bearer $TOKEN" -H "content-type: application/json" \
-d '{"files":[{"name":"team.jpg","type":"image/jpeg","bytes":842113}]}'
# -> { "files": [ { "key": "pending/uploads/<tenant>/...-team.jpg", "put_url": "https://..." } ] }
# 2. PUT the file to put_url with the SAME content-type you declared
curl -X PUT "$PUT_URL" -H "content-type: image/jpeg" --data-binary @team.jpg
# 3. create the video, naming the key
curl -X POST https://automatedvideoapp.com/api/videos \
-H "authorization: Bearer $API_KEY" -H "content-type: application/json" \
-d '{"topic":"our new workshop","aspect":"9:16",
"user_images":[{"key":"pending/uploads/<tenant>/...-team.jpg","role":"scene","scene_index":0}]}'
role | What happens |
|---|---|
scene | Your picture becomes that scene's visual, with the usual slow zoom, narration and captions. No generation, no cost. Needs scene_index. |
animate | Your picture is the first frame of a generated clip, so the motion starts from it. Needs scene_index. Uses your Pollen like any AI motion. |
auto | The app places it: matched to a scene by the words in label, and otherwise dropped into the first free scene in order. The least precise of the three — give it a real label or expect sequential placement. |
Uploads are not a library. They live with the pending video under the same one-day rule as an unpublished render and go when it does. The finished video keeps its scenes, so nothing you have made is affected.
There is no "fetch this image URL" option, deliberately. Accepting a URL would have the render worker fetch arbitrary caller-supplied addresses, including ones inside its own network. If you need images from elsewhere, download them yourself and upload them through step 1.
HEIC is not accepted. It is what iPhones shoot by default, so export as JPEG first, or set Settings → Camera → Formats to "Most Compatible".
| Mode | What you get | Cost |
|---|---|---|
stills | Still visuals with motion applied — AI-generated or real stock footage/photos, per image_source. | Free with a stock source. AI stills draw down your Pollen balance and will fail with 402 once it is exhausted. |
video_hybrid | Generated motion on the hero scenes, stills elsewhere. | Metered, or your own Pollen. |
video_full | Image-to-video on every scene, each clip seeded from that scene's own still. | Pro plan, or your own Pollen. |
avatar | A presenter reads the script. Runs on your own HeyGen key. | Your HeyGen account. |
202 Accepted
{ "job_id": "8f3c…", "status": "queued",
"status_url": "https://automatedvideoapp.com/api/videos?id=8f3c…" }
| Code | Meaning |
|---|---|
400 | Neither topic nor script given, or malformed JSON. |
401 | Missing or invalid API key. |
402 | no_allowance — out of metered credits. Connect your own Pollen key to remove the meter. |
403 | Key lacks video:create, or pro_required for video_full. |
502 | enqueue_failed — the job could not be queued. It is marked failed and any credit is refunded. |
curl -H "Authorization: Bearer $HAWK_KEY" \
"https://automatedvideoapp.com/api/videos?id=8f3c…"
{
"id": "8f3c…",
"status": "done", // queued | rendering | done | failed
"progress": 100,
"stage": "finished",
"output_url": "https://…/video.mp4",
"output_url_nocard": "https://…/video-nocard.mp4",
"thumbnail_url": "https://…/thumb.jpg",
"duration_seconds": 62.4,
"editable": true,
"scenes": [
{ "index": 0, "kept": true, "start": 0.0, "duration": 6.4,
"source": "ai_still", "narration": "…", "thumbnail_url": "https://…" }
]
}
If you must poll, poll no faster than every 10 seconds. A typical 60-second video finishes in one to three minutes depending on the visual mode.
Every video is kept as separate scene clips, each carrying its own picture and its own
narration. Dropping a scene is a stream-copy re-stitch plus a caption rebuild from stored
word timings: seconds, and no generation cost. Removed clips are retained, so pass the index
back in keep_scenes later and the scene returns.
curl -X POST https://automatedvideoapp.com/api/recut \
-H "Authorization: Bearer $HAWK_KEY" \
-H "Content-Type: application/json" \
-d '{ "job_id": "8f3c…", "keep_scenes": [0,1,3,4],
"end_card": { "title": "Book a session", "subtitle": "example.com" } }'
| Field | Notes |
|---|---|
job_id | Required. Must be a finished video you own. |
keep_scenes | Array of scene indexes to keep, in any order. Omit to keep every scene and only change the end card. |
end_card | false removes it; { "title", "subtitle" } sets custom text; omit to leave it as-is. |
Returns 200 with the new keep_scenes and removed_scenes,
and re-queues the job. Notable errors: 409 video not ready,
409 recut_in_progress, 403 not your job.
Set webhook_url on the request, or save a default one in the app under
Integrations & automation → Website automation. When the render finishes we POST:
POST your-url
X-HAW-Event: video.completed
X-HAW-Signature: <hex HMAC-SHA256 of the raw body, if a webhook secret is set>
Content-Type: application/json
{ "event": "video.completed", "job_id": "8f3c…",
"tenant_id": "…", "status": "done",
"output_url": "https://…", "thumbnail_url": "https://…" }
Verify the signature before trusting the payload: compute
HMAC-SHA256(secret, raw_body) and compare in constant time. Respond
2xx quickly and do your work asynchronously.
A failed render fires the same way with X-HAW-Event: video.failed and an
error field instead of an output URL, so a scenario can branch on it rather
than hanging.
Rendered files live in temporary storage and are cleaned up on a schedule. If your
automation needs to keep the file, fetch output_url as soon as the webhook
fires and store it yourself, or publish it to a connected channel. Do not treat
output_url as a permanent CDN link.
The pattern is the same in Make, Zapier, n8n or Power Automate:
POST /api/videos with your topic, bearer key in the header.webhook_url at the tool's inbound webhook URL, and continue the scenario when it arrives. Cleaner and cheaper than a polling loop.output_url — upload it, attach it, post it, store it.If your tool cannot receive webhooks, poll GET /api/videos?id= on a 10–30
second interval instead and stop when status is done or
failed.
There is no published hard rate limit; renders are queued and processed in order. Sustained abusive volume will get a key throttled, and we will email you before that happens. Content must satisfy the acceptable-use policy — in particular, no non-consensual likenesses and no unqualified medical, legal or financial claims.