REST API · v1
Blipix API
Make faceless videos from your own code. Send a topic, a voice and an art style: Blipix writes the script, records the voice-over, generates the scene images and renders an MP4 you can download.
Works on every paid plan. The API creates and reads videos; it can't post to TikTok, YouTube or Instagram, and it can't create series.
- Base URL
https://app.blipix.pro/api/v1- Auth
- Bearer key, starts with
blx_ - Rate limit
- 60 requests a minute per account
- Plans
- Any paid plan
Quickstart
From API key to MP4
Copy your key, start a video, then check on it until the render is done. The examples read the key from an environment variable so it stays out of your code.
- 1
Copy your key
Sign in on a paid plan, open Settings in the app and copy the key under API Key. It starts with
blx_.export BLIPIX_API_KEY="blx_your_api_key" - 2
Start a video
A prompt and a voice are enough; every other field has a default. The call answers once the script, voice-over and images exist and the render has been requested, so it can stay open for a while.
curl https://app.blipix.pro/api/v1/videos/create \ -X POST \ -H "Authorization: Bearer $BLIPIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Five surprising facts about octopuses", "voice": "alloy" }'const BASE = "https://app.blipix.pro/api/v1"; const key = process.env.BLIPIX_API_KEY; const res = await fetch(`${BASE}/videos/create`, { method: "POST", headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json", }, body: JSON.stringify({ prompt: "Five surprising facts about octopuses", voice: "alloy", }), }); const video = await res.json(); console.log(video.id); // keep this id to pollimport os import requests BASE = "https://app.blipix.pro/api/v1" KEY = os.environ["BLIPIX_API_KEY"] res = requests.post( f"{BASE}/videos/create", headers={"Authorization": f"Bearer {KEY}"}, json={ "prompt": "Five surprising facts about octopuses", "voice": "alloy", }, ) video = res.json() print(video["id"]) # keep this id to poll<?php $base = "https://app.blipix.pro/api/v1"; $key = getenv("BLIPIX_API_KEY"); $ch = curl_init("$base/videos/create"); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer $key", "Content-Type: application/json", ]); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ "prompt" => "Five surprising facts about octopuses", "voice" => "alloy", ])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $video = json_decode(curl_exec($ch), true); echo $video["id"]; // keep this id to poll - 3
Check until the MP4 is ready
Ask for the video once a minute. When
renderStatusiscompleted,videoUrlholds the MP4.# Checks once a minute. Needs jq. while true; do video=$(curl -s https://app.blipix.pro/api/v1/videos/VIDEO_ID \ -H "Authorization: Bearer $BLIPIX_API_KEY") render=$(echo "$video" | jq -r .renderStatus) echo "$render $(echo "$video" | jq -r .renderProgress)%" case "$render" in completed|failed|cancelled) break ;; esac sleep 60 done echo "$video" | jq -r .videoUrlconst BASE = "https://app.blipix.pro/api/v1"; const headers = { Authorization: `Bearer ${process.env.BLIPIX_API_KEY}` }; const wait = (s) => new Promise((r) => setTimeout(r, s * 1000)); async function waitForVideo(id) { while (true) { const res = await fetch(`${BASE}/videos/${id}`, { headers }); if (res.status === 429) { await wait(Number(res.headers.get("Retry-After")) || 60); continue; } const video = await res.json(); if (!res.ok) throw new Error(video.error); if (video.renderStatus === "completed") return video.videoUrl; if (["error", "failed"].includes(video.status) || ["failed", "cancelled"].includes(video.renderStatus)) { throw new Error(`Stopped: ${video.status}, ${video.renderStatus}`); } await wait(60); } } console.log(await waitForVideo("VIDEO_ID"));import os import time import requests BASE = "https://app.blipix.pro/api/v1" HEADERS = {"Authorization": f"Bearer {os.environ['BLIPIX_API_KEY']}"} def wait_for_video(video_id): while True: res = requests.get(f"{BASE}/videos/{video_id}", headers=HEADERS) if res.status_code == 429: time.sleep(int(res.headers.get("Retry-After", 60))) continue res.raise_for_status() video = res.json() if video["renderStatus"] == "completed": return video["videoUrl"] stopped = video["status"] in ("error", "failed") stopped = stopped or video["renderStatus"] in ("failed", "cancelled") if stopped: raise RuntimeError("Generation or render stopped") time.sleep(60) print(wait_for_video("VIDEO_ID"))<?php $base = "https://app.blipix.pro/api/v1"; $key = getenv("BLIPIX_API_KEY"); while (true) { $ch = curl_init("$base/videos/VIDEO_ID"); curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer $key"]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $video = json_decode(curl_exec($ch), true); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($code === 429) { sleep(60); continue; } if ($code !== 200) throw new RuntimeException($video["error"]); if ($video["renderStatus"] === "completed") break; if (in_array($video["renderStatus"], ["failed", "cancelled"], true) || in_array($video["status"], ["error", "failed"], true)) { throw new RuntimeException("Generation or render stopped"); } sleep(60); } echo $video["videoUrl"];
Start here
Authentication
Send your key as a Bearer token in the Authorization header of every request.
Authorization: Bearer blx_your_api_key- Where to find it
- In the app under Settings, API Key. Each account has one key, created the first time that page opens.
- Who can use it
- Accounts on any paid plan. A key from an account on the free plan gets
403, and a key stops working if the subscription ends. - Keep it private
- Anyone holding the key can spend your credits. Call the API from your server, never from code that runs in a browser.
Start here
Requests and responses
- Base URL
https://app.blipix.pro/api/v1- Request bodies
- JSON, sent with
Content-Type: application/json. A JSON body sent without that header isn't parsed, and the call fails with400. - Responses
- Always JSON. An error has one
errorfield with a message, next to the HTTP status. - Timestamps
- ISO 8601 strings in UTC, such as
2026-10-18T09:30:00.000Z. - Methods
- Each path takes one method. Any other method returns
405before your key is checked.
Start here
Rate limits
Two limits apply, and both answer with 429 once you go over.
| Limit | Counted per | Window | Over the limit |
|---|---|---|---|
| 60 requests | Account (your API key) | 1 minute | 429 with a Retry-After header giving the seconds to wait |
| 20 requests | IP address. Every request counts, including ones with a wrong key. | 15 minutes | 429 with the message Too many requests. Try again later. |
Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining for the per-account limit. Because of the per-IP limit, check on a video once a minute rather than every few seconds.
Start here
Errors
A failed call returns the matching HTTP status and a JSON body with the reason.
{
"error": "Invalid API key"
}{
"error": "Insufficient credits",
"credits": {
"used": 595,
"total": 600,
"remaining": 5
}
}| Status | Meaning | Messages you may see |
|---|---|---|
| 400 | A required field is missing or a value isn't allowed (POST /videos/create) | "prompt" is required (e.g., "Top 5 AI Tools in 2026") "voice" is required (e.g., "alloy", "nova") Invalid aspectRatio. Valid options: 9:16, 16:9, 1:1 Invalid duration. Valid options: 30-60, 60-90, ... |
| 401 | The key is missing, malformed or unknown. A token that doesn't start with blx_ is read as an app session and gets the last message. | Missing or invalid Authorization header. Use: Bearer YOUR_API_KEY Invalid API key format Invalid API key Invalid or expired session. Sign in again. |
| 402 | Not enough credits for the requested length. The body also has a credits object. | Insufficient credits |
| 403 | The account or the voice can't be used | API access requires a paid plan. Upgrade at https://app.blipix.pro/upgrade Account is blocked This voice is not available on your account. |
| 404 | No video with that id on your account | Video not found |
| 405 | Wrong HTTP method for the path | Method not allowed |
| 429 | A rate limit was reached (see above) | Rate limit exceeded. Max 60 requests per minute. Too many requests. Try again later. |
| 500 | Something failed on the Blipix side | Failed to create video Failed to fetch videos and the same pattern for other lists |
POST /videos/create also passes on errors from the generation step with their own status, for example 408 when generation runs past 35 minutes. The credits taken for that call are refunded.
Retrieve your account
Your profile, plan and credit balance. A quick way to check that a key works before you spend credits.
Response fields
| Field | Description |
|---|---|
| id | Your account id. |
| firstName, lastName | As set in the app. Empty string when not set. |
| The email on the account. | |
| plan | Plan key, such as STARTER, CREATOR, PRO, PREMIUM or ULTRA. |
| country | Two-letter country code, or an empty string. |
| credits.used | Credits spent since the plan last renewed. |
| credits.total | Plan credits plus any top-up credits. |
| credits.remaining | Total minus used, never below 0. |
Example request
curl https://app.blipix.pro/api/v1/me \
-H "Authorization: Bearer $BLIPIX_API_KEY"const BASE = "https://app.blipix.pro/api/v1";
const key = process.env.BLIPIX_API_KEY;
const res = await fetch(`${BASE}/me`, {
headers: { Authorization: `Bearer ${key}` },
});
const account = await res.json();
console.log(account.plan, account.credits.remaining);import os
import requests
BASE = "https://app.blipix.pro/api/v1"
KEY = os.environ["BLIPIX_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}
res = requests.get(f"{BASE}/me", headers=HEADERS)
account = res.json()
print(account["plan"], account["credits"]["remaining"])<?php
$base = "https://app.blipix.pro/api/v1";
$key = getenv("BLIPIX_API_KEY");
$ch = curl_init("$base/me");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $key",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$account = json_decode(curl_exec($ch), true);
echo $account["credits"]["remaining"];Example response
{
"id": "USER_ID",
"firstName": "Jane",
"lastName": "Doe",
"email": "you@example.com",
"plan": "CREATOR",
"country": "US",
"credits": {
"used": 130,
"total": 600,
"remaining": 470
}
}List art styles
Every art style you can pass as style when you create a video, sorted by name. The style gallery shows what each one looks like.
Response fields
| Field | Description |
|---|---|
| count | How many styles are in the list. |
| styles[].id | Style id. |
| styles[].name | The value to send as style. |
| styles[].thumbnail | URL of a sample image. |
| styles[].categories | Tags such as realistic, story or history. |
| styles[].bestFor | Short note on the topics the style suits. |
| styles[].isNew, trending | Labels the app shows in its style picker. |
Example request
curl https://app.blipix.pro/api/v1/styles \
-H "Authorization: Bearer $BLIPIX_API_KEY"const BASE = "https://app.blipix.pro/api/v1";
const key = process.env.BLIPIX_API_KEY;
const res = await fetch(`${BASE}/styles`, {
headers: { Authorization: `Bearer ${key}` },
});
const { styles } = await res.json();
console.log(styles.map((s) => s.name));import os
import requests
BASE = "https://app.blipix.pro/api/v1"
KEY = os.environ["BLIPIX_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}
res = requests.get(f"{BASE}/styles", headers=HEADERS)
styles = res.json()["styles"]
print([s["name"] for s in styles])<?php
$base = "https://app.blipix.pro/api/v1";
$key = getenv("BLIPIX_API_KEY");
$ch = curl_init("$base/styles");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $key",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$styles = json_decode(curl_exec($ch), true)["styles"];
echo implode(", ", array_column($styles, "name"));Example response shortened to two styles
{
"count": 2,
"styles": [
{
"id": "STYLE_ID_1",
"name": "Blipix",
"thumbnail": "https://...",
"categories": ["realistic", "history"],
"bestFor": "true crime, history & realistic storytelling",
"isNew": false,
"trending": false
},
{
"id": "STYLE_ID_2",
"name": "Cinematic",
"thumbnail": "https://...",
"categories": ["realistic", "story", "history"],
"bestFor": "movie-style stories, history & documentaries",
"isNew": false,
"trending": false
}
]
}List voices
The narrator voices your account can use, sorted by name: the Blipix voices plus any voice you cloned. Send voiceId as voice when you create a video.
Response fields
| Field | Description |
|---|---|
| count | How many voices are in the list. |
| voices[].voiceId | The value to send as voice. |
| voices[].id | Id of the voice record (not the value to send). |
| voices[].name | Display name. |
| voices[].language | Language code. en when none is set. |
| voices[].gender, age, accent, useCase | The labels the app filters voices by. |
| voices[].preview | URL of an audio sample. |
| voices[].avatarUrl, design | Picture and CSS gradient the app shows for the voice. |
| voices[].custom | true for a voice you cloned. Cloned voices are only listed for their owner. |
| voices[].free, freeDefault, main, isNew | Flags the app uses to offer, preselect and label voices. |
Example request
curl https://app.blipix.pro/api/v1/voices \
-H "Authorization: Bearer $BLIPIX_API_KEY"const BASE = "https://app.blipix.pro/api/v1";
const key = process.env.BLIPIX_API_KEY;
const res = await fetch(`${BASE}/voices`, {
headers: { Authorization: `Bearer ${key}` },
});
const { voices } = await res.json();
const english = voices.filter((v) => v.language === "en");
console.log(english.map((v) => v.voiceId));import os
import requests
BASE = "https://app.blipix.pro/api/v1"
KEY = os.environ["BLIPIX_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}
res = requests.get(f"{BASE}/voices", headers=HEADERS)
voices = res.json()["voices"]
print([v["voiceId"] for v in voices if v["language"] == "en"])<?php
$base = "https://app.blipix.pro/api/v1";
$key = getenv("BLIPIX_API_KEY");
$ch = curl_init("$base/voices");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $key",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$voices = json_decode(curl_exec($ch), true)["voices"];
echo implode(", ", array_column($voices, "voiceId"));Example response shortened to two voices
{
"count": 2,
"voices": [
{
"id": "SPEAKER_ID_1",
"voiceId": "alloy",
"name": "Alloy",
"language": "en",
"gender": "male",
"age": "young",
"accent": "american",
"useCase": "Narration, General",
"avatarUrl": "https://...",
"design": null,
"preview": "https://...",
"free": false,
"freeDefault": false,
"main": false,
"isNew": false,
"custom": false
},
{
"id": "SPEAKER_ID_2",
"voiceId": "YOUR_CLONED_VOICE_ID",
"name": "My narrator",
"language": "en",
"gender": null,
"age": null,
"accent": null,
"useCase": null,
"avatarUrl": null,
"design": null,
"preview": "https://...",
"free": false,
"freeDefault": false,
"main": false,
"isNew": false,
"custom": true
}
]
}Create a video
Starts a video from a prompt. The AI writes a script in your language, Blipix records the voice-over with the voice you chose, generates an image for each scene in your art style, then queues the MP4 render. The credits for the length are taken when the call starts.
A long request
The connection stays open while the script, voice-over and images are generated, and the 201 comes back as soon as the MP4 render is requested. Give your HTTP client a long timeout. If it gives up before an answer comes back, look at GET /videos before you retry: a second call starts, and charges for, a second video.
Body parameters
| Parameter | Description |
|---|---|
| prompt | What the video is about, in plain words. The AI writes the script from it. |
| voice | A voiceId from GET /voices. An id that matches no voice falls back to the default narrator instead of failing. |
| styledefault Blipix | A style name from GET /styles, in any letter case. An unknown name falls back to Blipix. |
| durationdefault 30-60 | One of the length ranges below. It sets the script length and the credit cost. |
| aspectRatiodefault 9:16 | 9:16, 16:9 or 1:1. |
| languagedefault en | Language of the script and the narration, as a code from the list below. The value isn’t validated, so stick to these codes. |
Lengths and credits
| duration | Length | Credits |
|---|---|---|
30-60 | 30 to 60 seconds | 10 |
60-90 | 1 to 1.5 minutes | 10 |
90-120 | 1.5 to 2 minutes | 20 |
120-150 | 2 to 2.5 minutes | 20 |
150-180 | 2.5 to 3 minutes | 30 |
180-210 | 3 to 3.5 minutes | 30 |
210-300 | 3.5 to 5 minutes | 50 |
300-420 | 5 to 7 minutes | 70 |
420-600 | 7 to 10 minutes | 100 |
600-720 | 10 to 12 minutes | 120 |
720-900 | 12 to 15 minutes | 150 |
Language codes
- Arabic
ar - Bulgarian
bg - Chinese
zh - Croatian
hr - Czech
cs - Danish
da - Dutch
nl - English
en - Finnish
fi - Filipino
fil - French
fr - German
de - Greek
el - Hindi
hi - Hungarian
hu - Indonesian
id - Italian
it - Japanese
ja - Korean
ko - Malay
ms - Norwegian
no - Polish
pl - Portuguese
pt - Romanian
ro - Russian
ru - Slovak
sk - Spanish
es - Swedish
sv - Tamil
ta - Turkish
tr - Ukrainian
uk - Vietnamese
vi
What happens after the call
While the request is open
status: "processing"Once the script and voice-over exist, the video shows up in GET /videos while its scene images are generated.
After the 201
status: "ready"renderStatus: "queued"The render has been requested. Once it is picked up,
renderStatusreadsqueued(it can benulljust before) andrenderProgresson GET /videos/:id counts from 0 to 100.Done
renderStatus: "completed"videoUrlholds the MP4. The video is also in your Blipix account, where you can open it in the editor.
If generation fails, the call returns an error, the video's status becomes error and the credits are refunded. If the render fails, renderStatus becomes failed; open the video in the app to render it again.
Example request
curl https://app.blipix.pro/api/v1/videos/create \
-X POST \
-H "Authorization: Bearer $BLIPIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Five surprising facts about octopuses",
"voice": "alloy",
"style": "Cinematic",
"duration": "30-60",
"aspectRatio": "9:16",
"language": "en"
}'const BASE = "https://app.blipix.pro/api/v1";
const key = process.env.BLIPIX_API_KEY;
const res = await fetch(`${BASE}/videos/create`, {
method: "POST",
headers: {
Authorization: `Bearer ${key}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
prompt: "Five surprising facts about octopuses",
voice: "alloy",
style: "Cinematic",
duration: "30-60",
aspectRatio: "9:16",
language: "en",
}),
});
const video = await res.json();
console.log(video.id); // keep this id to pollimport os
import requests
BASE = "https://app.blipix.pro/api/v1"
KEY = os.environ["BLIPIX_API_KEY"]
res = requests.post(
f"{BASE}/videos/create",
headers={"Authorization": f"Bearer {KEY}"},
json={
"prompt": "Five surprising facts about octopuses",
"voice": "alloy",
"style": "Cinematic",
"duration": "30-60",
"aspectRatio": "9:16",
"language": "en",
},
)
video = res.json()
print(video["id"]) # keep this id to poll<?php
$base = "https://app.blipix.pro/api/v1";
$key = getenv("BLIPIX_API_KEY");
$ch = curl_init("$base/videos/create");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $key",
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"prompt" => "Five surprising facts about octopuses",
"voice" => "alloy",
"style" => "Cinematic",
"duration" => "30-60",
"aspectRatio" => "9:16",
"language" => "en",
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$video = json_decode(curl_exec($ch), true);
echo $video["id"]; // keep this id to pollExample response
{
"id": "VIDEO_ID",
"status": "processing",
"message": "Video generation started. Poll GET /api/v1/videos/:id to check status.",
"creditsCost": 10
}status in this response is always processing. Read the real state from GET /videos/:id.
Retrieve a video
One video by id, with its script, voice-over audio and render progress. This is the call to repeat after you create a video.
Path parameter
| Parameter | Description |
|---|---|
| id | The id returned by POST /videos/create or listed by GET /videos. Ids from another account return 404. |
Response fields
| Field | Description |
|---|---|
| id, title, description | Title and description are written by the AI with the script. |
| script | The narrated text. |
| status | Generation state. Values below. |
| type | The template behind the video. Videos made with this API are prompt; app videos can be standard, script, pov, asmr, gaming, brainrot, ugc, music, documentary, anatomy, talking_avatar and others. |
| duration | Narration length, counted as seconds (52.4 is just under a minute). |
| aspectRatio | 9:16, 16:9 or 1:1. |
| renderStatus | MP4 render state. Values below. |
| renderProgress | 0 to 100 while a render runs, 100 once completed, otherwise null. |
| videoUrl | The MP4, once renderStatus is completed. |
| audioUrl | The voice-over audio file. |
| thumbnailUrl | A stored thumbnail image. Usually null for videos made with the API. |
| hashtags | Hashtags written with the script. |
| createdAt | When the video record was created, ISO 8601 UTC. |
status values
processing- Images are still being generated.
ready- Generation finished. Check
renderStatusfor the MP4. error- Generation failed.
failed- Used by Talking Avatar videos made in the app when the avatar step fails.
renderStatus values
null- No render has started.
queued- Queued or rendering; see
renderProgress. completed- The MP4 is at
videoUrl. failed- The render stopped with an error.
cancelled- The render was cancelled in the app.
Example request
curl https://app.blipix.pro/api/v1/videos/VIDEO_ID \
-H "Authorization: Bearer $BLIPIX_API_KEY"const BASE = "https://app.blipix.pro/api/v1";
const key = process.env.BLIPIX_API_KEY;
const res = await fetch(`${BASE}/videos/VIDEO_ID`, {
headers: { Authorization: `Bearer ${key}` },
});
const video = await res.json();
console.log(video.renderStatus, video.renderProgress);import os
import requests
BASE = "https://app.blipix.pro/api/v1"
KEY = os.environ["BLIPIX_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}
res = requests.get(f"{BASE}/videos/VIDEO_ID", headers=HEADERS)
video = res.json()
print(video["renderStatus"], video["renderProgress"])<?php
$base = "https://app.blipix.pro/api/v1";
$key = getenv("BLIPIX_API_KEY");
$ch = curl_init("$base/videos/VIDEO_ID");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $key",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$video = json_decode(curl_exec($ch), true);
echo $video["renderStatus"];Example response
{
"id": "VIDEO_ID",
"title": "Five Surprising Facts About Octopuses",
"description": "Three hearts, blue blood and suckers that can taste...",
"script": "An octopus has three hearts...",
"status": "ready",
"type": "prompt",
"duration": 52.4,
"aspectRatio": "9:16",
"renderStatus": "completed",
"renderProgress": 100,
"videoUrl": "https://...",
"thumbnailUrl": null,
"audioUrl": "https://...",
"hashtags": ["#octopus", "#animalfacts"],
"createdAt": "2026-10-18T09:30:00.000Z"
}List videos
Your videos, newest first, including the ones you made in the app. Items have the same fields as GET /videos/:id, minus script, renderProgress and audioUrl.
Query parameters
| Parameter | Description |
|---|---|
| limitdefault 20 | How many videos to return, from 1 to 100. Larger values are capped at 100. |
| status | Only videos with this exact status: processing, ready, error or failed. Leave it out to get all of them. |
Response fields
| Field | Description |
|---|---|
| count | Number of items in videos. |
| videos | The videos, newest first. |
Example request
curl -G https://app.blipix.pro/api/v1/videos \
-d status=ready -d limit=10 \
-H "Authorization: Bearer $BLIPIX_API_KEY"const BASE = "https://app.blipix.pro/api/v1";
const key = process.env.BLIPIX_API_KEY;
const res = await fetch(`${BASE}/videos?status=ready&limit=10`, {
headers: { Authorization: `Bearer ${key}` },
});
const { videos } = await res.json();
console.log(videos.map((v) => v.title));import os
import requests
BASE = "https://app.blipix.pro/api/v1"
KEY = os.environ["BLIPIX_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}
res = requests.get(
f"{BASE}/videos",
params={"status": "ready", "limit": 10},
headers=HEADERS,
)
videos = res.json()["videos"]
print([v["title"] for v in videos])<?php
$base = "https://app.blipix.pro/api/v1";
$key = getenv("BLIPIX_API_KEY");
$ch = curl_init("$base/videos?status=ready&limit=10");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $key",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$videos = json_decode(curl_exec($ch), true)["videos"];
echo count($videos);Example response
{
"count": 2,
"videos": [
{
"id": "VIDEO_ID_1",
"title": "Five Surprising Facts About Octopuses",
"description": "Three hearts, blue blood and suckers that can taste...",
"status": "ready",
"type": "prompt",
"duration": 52.4,
"aspectRatio": "9:16",
"renderStatus": "completed",
"videoUrl": "https://...",
"thumbnailUrl": null,
"hashtags": ["#octopus", "#animalfacts"],
"createdAt": "2026-10-18T09:30:00.000Z"
},
{
"id": "VIDEO_ID_2",
"title": "The Lighthouse Keeper's Last Night",
"description": "...",
"status": "ready",
"type": "standard",
"duration": 58.1,
"aspectRatio": "9:16",
"renderStatus": null,
"videoUrl": null,
"thumbnailUrl": null,
"hashtags": ["#history"],
"createdAt": "2026-10-16T17:05:12.000Z"
}
]
}List series
A read-only view of the series you set up in the app, newest first. Connected accounts appear only as platform names; their details and tokens are never returned.
Query parameters
| Parameter | Description |
|---|---|
| limitdefault 20 | How many series to return, from 1 to 100. Larger values are capped at 100. |
| status | active or paused. Any other value is ignored. |
Response fields
| Field | Description |
|---|---|
| count, total | count is how many came back after limit; total is how many matched the filter. |
| series[].status | active when the series is enabled and passed its health check, otherwise paused. |
| series[].disabledReason | Why a series stopped, when known, such as Not enough credits, Paused manually or Last video was deleted. |
| series[].workerStatus | Where the scheduler is: processed, processing, rendering, failed or stopped. |
| series[].frequency | label, perPeriod and period, for example 3 per week. |
| series[].days, times, timezone | Posting days in week order and times as you set them, both in the series’ time zone. |
| series[].nextPublishAt | Next scheduled run, ISO 8601 UTC. A paused series keeps the last scheduled time, which may be in the past. |
| series[].niche, language, duration, aspectRatio | The video settings each episode uses. |
| series[].creditsPerVideo | Credits one episode costs. |
| series[].channelCount, platforms | How many accounts the series posts to, and which platforms: youtube, tiktok, instagram. |
| series[].lastVideoId | The latest episode. Pass it to GET /videos/:id. |
| series[].lastCompletedAt, createdAt | ISO 8601 UTC. |
Example request
curl -G https://app.blipix.pro/api/v1/series \
-d status=active \
-H "Authorization: Bearer $BLIPIX_API_KEY"const BASE = "https://app.blipix.pro/api/v1";
const key = process.env.BLIPIX_API_KEY;
const res = await fetch(`${BASE}/series?status=active`, {
headers: { Authorization: `Bearer ${key}` },
});
const { series } = await res.json();
console.log(series.map((s) => s.nextPublishAt));import os
import requests
BASE = "https://app.blipix.pro/api/v1"
KEY = os.environ["BLIPIX_API_KEY"]
HEADERS = {"Authorization": f"Bearer {KEY}"}
res = requests.get(
f"{BASE}/series",
params={"status": "active"},
headers=HEADERS,
)
series = res.json()["series"]
print([s["nextPublishAt"] for s in series])<?php
$base = "https://app.blipix.pro/api/v1";
$key = getenv("BLIPIX_API_KEY");
$ch = curl_init("$base/series?status=active");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $key",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$series = json_decode(curl_exec($ch), true)["series"];
echo count($series);Example response
{
"count": 1,
"total": 1,
"series": [
{
"id": "SERIES_ID",
"name": "Daily history facts",
"status": "active",
"workerStatus": "processed",
"disabledReason": null,
"frequency": {
"label": "3 times a week",
"perPeriod": 3,
"period": "week"
},
"days": ["Monday", "Wednesday", "Friday"],
"times": ["9:00 AM"],
"timezone": "America/New_York",
"nextPublishAt": "2026-10-19T13:00:00.000Z",
"niche": "Interesting History",
"language": "en",
"duration": "30-60",
"aspectRatio": "9:16",
"creditsPerVideo": 10,
"channelCount": 2,
"platforms": ["youtube", "tiktok"],
"lastVideoId": "VIDEO_ID",
"lastCompletedAt": "2026-10-16T13:04:11.000Z",
"createdAt": "2026-09-02T18:20:00.000Z"
}
]
}Limits
What the API doesn't do
Worth knowing before you build. The API covers making videos and reading your account; the rest happens in the app.
- Post to social accounts. Videos can't be published to TikTok, YouTube or Instagram through the API. Download the MP4 from
videoUrl, or post from the app. - Create or change series. GET /series only reads them. Setting up, pausing and editing series happens in the app.
- Use another template or your own script. Every API video starts from a prompt, and the AI writes the script.
- Set captions, music or effects. API videos use default settings. Open one in the app's editor to change them.
- Call you back. There are no webhooks. Repeat GET /videos/:id until the render completes.
- Delete videos. There is no delete endpoint.
Need something that isn't here?
Tell us what you are building and which endpoint would help. API access comes with every paid plan.
