HTTP API examples
Create a project
A project holds the videos of one job. This page creates a project, lists the projects, reads one project and changes it.
Before you start
Put your API key in place of <your API key>. The Quickstart shows how to make a key.
CAPTIONBOB_URL is the default address of the server. Change it when your server listens on another host or port. The code of each step runs after this first code. The curl code runs in bash and reads values from the answers with jq. The Python code uses the package requests. The JavaScript code runs in Node.js 22 or later as an ES module, such as a file example.mjs.
The answers on this page are real answers of a captionbob server, recorded on 2026-10-28. Your ids, names and times are different.
curl
CAPTIONBOB_URL="http://127.0.0.1:9400"
CAPTIONBOB_KEY="<your API key>"
Python
import requests
CAPTIONBOB_URL = "http://127.0.0.1:9400"
HEADERS = {"Authorization": "Bearer <your API key>"}
JavaScript
const CAPTIONBOB_URL = "http://127.0.0.1:9400";
const HEADERS = { Authorization: "Bearer <your API key>" };
let response;
let answer;
Step 1: Create a project
Give the new project a name. A new project is active.
curl
ANSWER=$(curl -s -X POST "$CAPTIONBOB_URL/api/projects" \
-H "Authorization: Bearer $CAPTIONBOB_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Product demos"}')
echo "$ANSWER"
PROJECT_ID=$(echo "$ANSWER" | jq -r '.project.id')
Python
response = requests.post(
f"{CAPTIONBOB_URL}/api/projects",
headers=HEADERS,
json={"name": "Product demos"},
)
if not response.ok:
raise RuntimeError(response.text)
answer = response.json()
print(answer)
project_id = answer["project"]["id"]
JavaScript
response = await fetch(`${CAPTIONBOB_URL}/api/projects`, {
method: "POST",
headers: { ...HEADERS, "Content-Type": "application/json" },
body: JSON.stringify({ name: "Product demos" }),
});
if (!response.ok) {
throw new Error(await response.text());
}
answer = await response.json();
console.log(JSON.stringify(answer, null, 2));
const projectId = answer.project.id;
Answer: status 201.
{
"project": {
"id": 2,
"name": "Product demos",
"state": "active",
"createdBy": "editor",
"createdAt": "2026-10-28T01:34:08.742Z",
"updatedAt": "2026-10-28T01:34:08.742Z",
"videoCount": 0
}
}
Step 2: List the projects
The list holds all projects of all users, the last changed first.
curl
curl -s "$CAPTIONBOB_URL/api/projects" \
-H "Authorization: Bearer $CAPTIONBOB_KEY"
Python
response = requests.get(
f"{CAPTIONBOB_URL}/api/projects",
headers=HEADERS,
)
if not response.ok:
raise RuntimeError(response.text)
answer = response.json()
print(answer)
JavaScript
response = await fetch(`${CAPTIONBOB_URL}/api/projects`, { headers: HEADERS });
if (!response.ok) {
throw new Error(await response.text());
}
answer = await response.json();
console.log(JSON.stringify(answer, null, 2));
Answer: status 200.
{
"projects": [
{
"id": 2,
"name": "Product demos",
"state": "active",
"createdBy": "editor",
"createdAt": "2026-10-28T01:34:08.742Z",
"updatedAt": "2026-10-28T01:34:08.742Z",
"videoCount": 0
},
{
"id": 1,
"name": "Launch videos",
"state": "active",
"createdBy": "editor",
"createdAt": "2026-10-28T01:33:12.066Z",
"updatedAt": "2026-10-28T01:33:13.076Z",
"videoCount": 1
}
]
}
Step 3: Get one project
The answer holds the project and its videos, the newest first. Each video has its newest render, which gives its status. A new project has no videos.
curl
curl -s "$CAPTIONBOB_URL/api/projects/$PROJECT_ID" \
-H "Authorization: Bearer $CAPTIONBOB_KEY"
Python
response = requests.get(
f"{CAPTIONBOB_URL}/api/projects/{project_id}",
headers=HEADERS,
)
if not response.ok:
raise RuntimeError(response.text)
answer = response.json()
print(answer)
JavaScript
response = await fetch(`${CAPTIONBOB_URL}/api/projects/${projectId}`, { headers: HEADERS });
if (!response.ok) {
throw new Error(await response.text());
}
answer = await response.json();
console.log(JSON.stringify(answer, null, 2));
Answer: status 200.
{
"project": {
"id": 2,
"name": "Product demos",
"state": "active",
"createdBy": "editor",
"createdAt": "2026-10-28T01:34:08.742Z",
"updatedAt": "2026-10-28T01:34:08.742Z",
"videoCount": 0
},
"videos": []
}
Step 4: Rename the project
Send the new name in name.
curl
curl -s -X PATCH "$CAPTIONBOB_URL/api/projects/$PROJECT_ID" \
-H "Authorization: Bearer $CAPTIONBOB_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Product demos 2026"}'
Python
response = requests.patch(
f"{CAPTIONBOB_URL}/api/projects/{project_id}",
headers=HEADERS,
json={"name": "Product demos 2026"},
)
if not response.ok:
raise RuntimeError(response.text)
answer = response.json()
print(answer)
JavaScript
response = await fetch(`${CAPTIONBOB_URL}/api/projects/${projectId}`, {
method: "PATCH",
headers: { ...HEADERS, "Content-Type": "application/json" },
body: JSON.stringify({ name: "Product demos 2026" }),
});
if (!response.ok) {
throw new Error(await response.text());
}
answer = await response.json();
console.log(JSON.stringify(answer, null, 2));
Answer: status 200.
{
"project": {
"id": 2,
"name": "Product demos 2026",
"state": "active",
"createdBy": "editor",
"createdAt": "2026-10-28T01:34:08.742Z",
"updatedAt": "2026-10-28T01:34:08.748Z",
"videoCount": 0
}
}
Step 5: Archive the project
The state archived moves the project to the Archive tab of the dashboard.
curl
curl -s -X PATCH "$CAPTIONBOB_URL/api/projects/$PROJECT_ID" \
-H "Authorization: Bearer $CAPTIONBOB_KEY" \
-H "Content-Type: application/json" \
-d '{"state": "archived"}'
Python
response = requests.patch(
f"{CAPTIONBOB_URL}/api/projects/{project_id}",
headers=HEADERS,
json={"state": "archived"},
)
if not response.ok:
raise RuntimeError(response.text)
answer = response.json()
print(answer)
JavaScript
response = await fetch(`${CAPTIONBOB_URL}/api/projects/${projectId}`, {
method: "PATCH",
headers: { ...HEADERS, "Content-Type": "application/json" },
body: JSON.stringify({ state: "archived" }),
});
if (!response.ok) {
throw new Error(await response.text());
}
answer = await response.json();
console.log(JSON.stringify(answer, null, 2));
Answer: status 200.
{
"project": {
"id": 2,
"name": "Product demos 2026",
"state": "archived",
"createdBy": "editor",
"createdAt": "2026-10-28T01:34:08.742Z",
"updatedAt": "2026-10-28T01:34:08.754Z",
"videoCount": 0
}
}
Step 6: Make the project active again
The state active moves the project back.
curl
curl -s -X PATCH "$CAPTIONBOB_URL/api/projects/$PROJECT_ID" \
-H "Authorization: Bearer $CAPTIONBOB_KEY" \
-H "Content-Type: application/json" \
-d '{"state": "active"}'
Python
response = requests.patch(
f"{CAPTIONBOB_URL}/api/projects/{project_id}",
headers=HEADERS,
json={"state": "active"},
)
if not response.ok:
raise RuntimeError(response.text)
answer = response.json()
print(answer)
JavaScript
response = await fetch(`${CAPTIONBOB_URL}/api/projects/${projectId}`, {
method: "PATCH",
headers: { ...HEADERS, "Content-Type": "application/json" },
body: JSON.stringify({ state: "active" }),
});
if (!response.ok) {
throw new Error(await response.text());
}
answer = await response.json();
console.log(JSON.stringify(answer, null, 2));
Answer: status 200.
{
"project": {
"id": 2,
"name": "Product demos 2026",
"state": "active",
"createdBy": "editor",
"createdAt": "2026-10-28T01:34:08.742Z",
"updatedAt": "2026-10-28T01:34:08.759Z",
"videoCount": 0
}
}