Add Captions
curl --request POST \
--url https://api.hooked.so/v1/project/create/add-captions \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"media": "media_abc123",
"caption": {
"preset": "beast",
"alignment": "bottom"
},
"addStickers": true,
"musicId": "upbeat_001"
}
'import requests
url = "https://api.hooked.so/v1/project/create/add-captions"
payload = {
"media": "media_abc123",
"caption": {
"preset": "beast",
"alignment": "bottom"
},
"addStickers": True,
"musicId": "upbeat_001"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
media: 'media_abc123',
caption: {preset: 'beast', alignment: 'bottom'},
addStickers: true,
musicId: 'upbeat_001'
})
};
fetch('https://api.hooked.so/v1/project/create/add-captions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.hooked.so/v1/project/create/add-captions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'media' => 'media_abc123',
'caption' => [
'preset' => 'beast',
'alignment' => 'bottom'
],
'addStickers' => true,
'musicId' => 'upbeat_001'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.hooked.so/v1/project/create/add-captions"
payload := strings.NewReader("{\n \"media\": \"media_abc123\",\n \"caption\": {\n \"preset\": \"beast\",\n \"alignment\": \"bottom\"\n },\n \"addStickers\": true,\n \"musicId\": \"upbeat_001\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.hooked.so/v1/project/create/add-captions")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"media\": \"media_abc123\",\n \"caption\": {\n \"preset\": \"beast\",\n \"alignment\": \"bottom\"\n },\n \"addStickers\": true,\n \"musicId\": \"upbeat_001\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hooked.so/v1/project/create/add-captions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"media\": \"media_abc123\",\n \"caption\": {\n \"preset\": \"beast\",\n \"alignment\": \"bottom\"\n },\n \"addStickers\": true,\n \"musicId\": \"upbeat_001\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"videoId": "vid_caption_abc123xyz",
"projectId": "proj_caption_abc123xyz",
"status": "STARTED"
}
}
{
"success": false,
"message": "media: Media ID is required"
}
{
"success": false,
"message": "media: Media not found"
}
{
"success": false,
"message": "musicId: Music \"invalid_music\" not found."
}
Videos
Add Captions
Add automatic captions to your videos with customizable styles and positioning
POST
/
v1
/
project
/
create
/
add-captions
Add Captions
curl --request POST \
--url https://api.hooked.so/v1/project/create/add-captions \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"media": "media_abc123",
"caption": {
"preset": "beast",
"alignment": "bottom"
},
"addStickers": true,
"musicId": "upbeat_001"
}
'import requests
url = "https://api.hooked.so/v1/project/create/add-captions"
payload = {
"media": "media_abc123",
"caption": {
"preset": "beast",
"alignment": "bottom"
},
"addStickers": True,
"musicId": "upbeat_001"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
media: 'media_abc123',
caption: {preset: 'beast', alignment: 'bottom'},
addStickers: true,
musicId: 'upbeat_001'
})
};
fetch('https://api.hooked.so/v1/project/create/add-captions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.hooked.so/v1/project/create/add-captions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'media' => 'media_abc123',
'caption' => [
'preset' => 'beast',
'alignment' => 'bottom'
],
'addStickers' => true,
'musicId' => 'upbeat_001'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.hooked.so/v1/project/create/add-captions"
payload := strings.NewReader("{\n \"media\": \"media_abc123\",\n \"caption\": {\n \"preset\": \"beast\",\n \"alignment\": \"bottom\"\n },\n \"addStickers\": true,\n \"musicId\": \"upbeat_001\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.hooked.so/v1/project/create/add-captions")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"media\": \"media_abc123\",\n \"caption\": {\n \"preset\": \"beast\",\n \"alignment\": \"bottom\"\n },\n \"addStickers\": true,\n \"musicId\": \"upbeat_001\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.hooked.so/v1/project/create/add-captions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"media\": \"media_abc123\",\n \"caption\": {\n \"preset\": \"beast\",\n \"alignment\": \"bottom\"\n },\n \"addStickers\": true,\n \"musicId\": \"upbeat_001\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"videoId": "vid_caption_abc123xyz",
"projectId": "proj_caption_abc123xyz",
"status": "STARTED"
}
}
{
"success": false,
"message": "media: Media ID is required"
}
{
"success": false,
"message": "media: Media not found"
}
{
"success": false,
"message": "musicId: Music \"invalid_music\" not found."
}
Try it out! Use the API playground on the right to test the Add Captions endpoint directly.
Overview
Add Captions automatically transcribes your video and adds professional-looking captions with customizable styles. Perfect for:- Social media content (TikTok, Instagram Reels, YouTube Shorts)
- Accessibility compliance
- Increasing video engagement
- Multi-language content
- Educational videos
Captions are automatically synced with your video’s audio and support multiple styling presets.
Endpoint
POST /v1/project/create/add-captions
Required Fields
string
required
Media ID of the video to add captions to (as a string)
Optional Fields
string
Custom name for the project (max 100 characters). If not provided, a name will be auto-generated.
string
Background music ID from
/v1/music/list (max 30 characters)object
Caption settings for the video
Show Caption Object
Show Caption Object
string
default:"classic"
Caption preset style. Available presets:
default, beast, umi, tiktok, wrap1, wrap2, ariel, hooked, classic, active, bubble, glass, comic, glow, pastel, neon, retroTV, red, marker, modern, blue, vivid.string
default:"bottom"
Caption position on the video:
top, middle, or bottomstring
Webhook URL for status notifications (max 500 characters, must be HTTPS)
object
Custom metadata object (max 5KB JSON)
Request Examples
Basic Caption Addition
const response = await fetch('https://api.hooked.so/v1/project/create/add-captions', {
method: 'POST',
headers: {
'x-api-key': process.env.HOOKED_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
media: 'media_abc123'
})
});
const data = await response.json();
console.log('Video ID:', data.data.videoId);
console.log('Project ID:', data.data.projectId);
Advanced with Custom Styling
const addCaptionsAdvanced = async () => {
const response = await fetch('https://api.hooked.so/v1/project/create/add-captions', {
method: 'POST',
headers: {
'x-api-key': process.env.HOOKED_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Social Media Captioned Video',
media: 'media_xyz789',
caption: {
preset: 'modern',
alignment: 'bottom'
},
addStickers: false,
musicId: 'upbeat_background_001',
webhook: 'https://yoursite.com/webhook',
metadata: {
campaignId: 'social-media-2024',
platform: 'tiktok'
}
})
});
return await response.json();
};
With Background Music
const addCaptionsWithMusic = async () => {
const response = await fetch('https://api.hooked.so/v1/project/create/add-captions', {
method: 'POST',
headers: {
'x-api-key': process.env.HOOKED_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Product Demo with Captions',
media: 'media_product_demo',
addStickers: false,
caption: {
preset: 'modern',
alignment: 'bottom'
},
musicId: 'calm_background_music'
})
});
return await response.json();
};
Response
{
"success": true,
"data": {
"videoId": "vid_caption_abc123xyz",
"projectId": "proj_caption_abc123xyz",
"status": "STARTED"
}
}
{
"success": false,
"message": "media: Media ID is required"
}
{
"success": false,
"message": "media: Media not found"
}
{
"success": false,
"message": "musicId: Music \"invalid_music\" not found."
}
Webhook Notification
When your captioned video is ready, we’ll POST to your webhook URL (if configured):Webhook Payload
{
"status": "COMPLETED",
"data": {
"videoId": "vid_caption_abc123xyz",
"status": "COMPLETED",
"url": "https://cdn.hooked.so/videos/abc123xyz.mp4",
"shareUrl": "https://cdn.hooked.so/shared/abc123xyz.mp4",
"metadata": {
"projectId": "proj_caption_abc123xyz"
}
},
"message": "Video completed"
}
Caption Presets
Available caption presets for thecaption.preset field:
| Preset | Description |
|---|---|
default | Default caption style with bold text and shadow effects |
beast | Bold uppercase style with Komika font |
umi | Yellow glowing text style |
tiktok | Viral & trendy style, perfect for social media |
wrap1 | Wrapped style with red background highlight |
wrap2 | Wrapped style with blue background highlight (uppercase) |
ariel | Bold uppercase style with purple highlight |
hooked | Brand style with purple background |
classic | Clean, simple captions with black background (Default) |
active | Green background with bold text |
bubble | White background bubble style |
glass | Glassmorphic transparency effect |
comic | Comic Sans font with colorful style |
glow | Pink and orange glow effects |
pastel | Soft pastel pink background |
neon | Green neon glow effect |
retroTV | Retro TV style with cyan glow |
red | Red glow effect with white text |
marker | Yellow marker/highlighter style |
modern | Contemporary white background style |
blue | Blue background style |
vivid | Vibrant pink background with uppercase text |
Best Practices
Clear Audio
Ensure your video has clear audio for accurate transcription
Style Selection
Choose caption styles that match your content and brand
Positioning
Bottom alignment works best for most social media content
Error Handling
| Error | Description | Solution |
|---|---|---|
media: Media ID is required | Missing media ID | Provide a valid media ID string |
media: Media not found | Invalid media ID | Ensure the media ID exists and is correct |
media: Media is not a video | Media is not a video type | Ensure the media ID points to a video, not an image |
musicId: Music "X" not found | Invalid music ID | Use valid music ID from /v1/music/list |
caption.alignment: Invalid enum value | Invalid alignment | Use bottom, middle, or top |
webhook: Must be a valid HTTPS URL | Invalid webhook URL | Ensure webhook URL uses HTTPS |
Not enough credits | Insufficient credits | Top up your account credits |
Next Steps
List Videos
View all your created videos
Video Details
Check your video processing status
Music Library
Browse available background music
Webhooks Guide
Learn how to handle webhook notifications
Authorizations
Body
application/json
Media ID from uploaded video
Custom name for the project
Maximum string length:
100Caption styling and positioning settings
Show child attributes
Show child attributes
Add AI-generated stickers to enhance video engagement
Background music ID from /v1/music/list
Maximum string length:
30HTTPS URL for status notifications (max 500 characters)
Maximum string length:
500Custom metadata object (max 5KB)