Video Transcription API Documentation

Transcribe social media videos programmatically with a single API call.

Last updated: February 2026

Base URL

https://soscripted.com/api/public

Authentication

All API requests require a Bearer token in the Authorization header. You can generate an API key from your API Keys dashboard.

Header
Authorization: Bearer sk_your_api_key_here

POST /transcribe

Submit a video URL for transcription. The API will process the video and return the transcript. Each request costs 1 credit.

Request Body

FieldTypeDescription
urlstringVideo URL from a supported platform (YouTube, TikTok, Instagram, Facebook, Twitter/X, LinkedIn, Pinterest)
Example Request
POST /api/public/transcribe HTTP/1.1
Host: soscripted.com
Authorization: Bearer sk_your_api_key_here
Content-Type: application/json

{
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
}

Response (JSON)

By default, the API blocks until transcription completes and returns a JSON response.

Success Response (200)
{
  "ok": true,
  "caption": {
    "text": "Full transcript text here...",
    "segments": [
      { "start": 0.0, "end": 2.5, "text": "Hello world" },
      { "start": 2.5, "end": 5.0, "text": "This is a transcript" }
    ]
  }
}
Error Response (4xx/5xx)
{
  "error": "Error description"
}

Response (SSE Streaming)

To receive real-time progress updates, include Accept: text/event-stream in your request headers.

SSE Events
event: progress
data: {"stage":"downloading","pct":10}

event: progress
data: {"stage":"transcribing","pct":50}

event: final
data: {"ok":true,"caption":{"text":"...","segments":[...]}}

event: done
data: {"ok":true}

Status Codes

CodeDescription
200Transcription completed successfully
400Bad request (missing URL or unsupported platform)
401Unauthorized (missing or invalid API key)
402Insufficient credits
500Transcription failed
504Timeout (transcription took too long)

Library API

Access your saved transcripts programmatically. Save transcripts from the dashboard, then retrieve them via the API for your AI agents, knowledge bases, or workflows.

GET /library

List saved transcripts with search, pagination, and collection filtering.

ParameterTypeDescription
searchstringFull-text search across titles and content
collectionIdstringFilter by collection
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20, max: 100)
formatstring"summary" (default) or "full" (includes segments)
Example
curl "https://soscripted.com/api/public/library?search=marketing&limit=10" \
  -H "Authorization: Bearer sk_your_api_key_here"

GET /library/:id

Get a single saved transcript. Use the format query parameter to get different output formats.

FormatDescription
(default)JSON with segments, timestamps, and plain text
txtPlain text (all segments joined)
srtSRT subtitle format
vttWebVTT subtitle format
jsonStructured JSON with parsed timestamps
timestampsText with [MM:SS] prefixes
Example
# Get full JSON
curl "https://soscripted.com/api/public/library/clx123abc" \
  -H "Authorization: Bearer sk_your_api_key_here"

# Get plain text only
curl "https://soscripted.com/api/public/library/clx123abc?format=txt" \
  -H "Authorization: Bearer sk_your_api_key_here"

# Get SRT subtitles
curl "https://soscripted.com/api/public/library/clx123abc?format=srt" \
  -H "Authorization: Bearer sk_your_api_key_here"

Batch Import API

Import entire channels, playlists, or profiles in a single request. Videos are transcribed in the background and credits are reserved upfront.

POST /batch-import

Start a batch import from a channel, playlist, or profile URL. Credits are reserved based on the estimated number of videos.

FieldTypeDescription
urlstringChannel, playlist, or profile URL
collectionIdstring?Save transcripts to this collection
maxVideosnumber?Limit the number of videos to import
autoSaveboolean?Automatically save transcripts to library (default: true)
Example Request
POST /api/public/batch-import HTTP/1.1
Host: soscripted.com
Authorization: Bearer sk_your_api_key_here
Content-Type: application/json

{
  "url": "https://www.youtube.com/@MrBeast",
  "collectionId": "clx456def",
  "maxVideos": 50,
  "autoSave": true
}
Success Response (201)
{
  "ok": true,
  "data": {
    "id": "batch_abc123",
    "sourceType": "youtube_channel",
    "sourceName": "MrBeast",
    "estimatedVideos": 50,
    "creditsReserved": 50,
    "status": "processing",
    "createdAt": "2026-02-24T12:00:00Z"
  }
}

GET /batch-import

List your batch imports with pagination.

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20, max: 100)
Example
curl "https://soscripted.com/api/public/batch-import?page=1&limit=20" \
  -H "Authorization: Bearer sk_your_api_key_here"

GET /batch-import/:id

Get details of a specific batch import, including individual item statuses.

Example
curl "https://soscripted.com/api/public/batch-import/batch_abc123" \
  -H "Authorization: Bearer sk_your_api_key_here"
Success Response (200)
{
  "ok": true,
  "data": {
    "id": "batch_abc123",
    "sourceType": "youtube_channel",
    "sourceName": "MrBeast",
    "estimatedVideos": 50,
    "completedVideos": 32,
    "failedVideos": 1,
    "creditsReserved": 50,
    "creditsUsed": 32,
    "status": "processing",
    "items": [
      {
        "id": "item_001",
        "videoUrl": "https://youtube.com/watch?v=abc",
        "title": "Video Title",
        "status": "completed",
        "transcriptId": "clx789ghi"
      },
      {
        "id": "item_002",
        "videoUrl": "https://youtube.com/watch?v=def",
        "title": "Another Video",
        "status": "processing",
        "transcriptId": null
      }
    ]
  }
}

Webhooks API

Receive real-time notifications when events occur in your account. Register webhook endpoints and SoScripted will send HTTP POST requests with event payloads to your URL.

POST /webhooks

Register a new webhook endpoint. The response includes the full signing secret -- store it securely, as it will not be shown again.

FieldTypeDescription
urlstringHTTPS endpoint URL to receive events
eventsstring[]Event types to subscribe to
secretstring?Custom signing secret (auto-generated if omitted)

Available Events

EventDescription
transcript.completedA transcription finished successfully
transcript.failedA transcription failed
batch.completedA batch import finished (all items processed)
monitor.new_videoA monitored channel published a new video
Example Request
POST /api/public/webhooks HTTP/1.1
Host: soscripted.com
Authorization: Bearer sk_your_api_key_here
Content-Type: application/json

{
  "url": "https://your-app.com/webhooks/soscripted",
  "events": ["transcript.completed", "batch.completed"]
}
Success Response (201)
{
  "ok": true,
  "webhook": {
    "id": "wh_abc123",
    "url": "https://your-app.com/webhooks/soscripted",
    "events": ["transcript.completed", "batch.completed"],
    "secret": "whsec_a1b2c3d4e5f6...",
    "active": true,
    "createdAt": "2026-02-24T12:00:00Z"
  }
}

GET /webhooks

List all registered webhooks for your account.

Example
curl "https://soscripted.com/api/public/webhooks" \
  -H "Authorization: Bearer sk_your_api_key_here"
Success Response (200)
{
  "ok": true,
  "webhooks": [
    {
      "id": "wh_abc123",
      "url": "https://your-app.com/webhooks/soscripted",
      "events": ["transcript.completed", "batch.completed"],
      "active": true,
      "createdAt": "2026-02-24T12:00:00Z"
    }
  ]
}

PATCH /webhooks/:id

Update a webhook endpoint. All fields are optional -- only include the fields you want to change.

FieldTypeDescription
urlstring?New endpoint URL
eventsstring[]?Replace subscribed events
activeboolean?Enable or disable the webhook
Example
curl -X PATCH "https://soscripted.com/api/public/webhooks/wh_abc123" \
  -H "Authorization: Bearer sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"active": false}'

DELETE /webhooks/:id

Permanently delete a webhook endpoint.

Example
curl -X DELETE "https://soscripted.com/api/public/webhooks/wh_abc123" \
  -H "Authorization: Bearer sk_your_api_key_here"

POST /webhooks/:id/test

Send a test event to your webhook endpoint to verify it is reachable and correctly configured.

Example
curl -X POST "https://soscripted.com/api/public/webhooks/wh_abc123/test" \
  -H "Authorization: Bearer sk_your_api_key_here"
Success Response (200)
{
  "ok": true,
  "deliveryId": "del_xyz789",
  "statusCode": 200
}

GET /webhooks/:id/deliveries

View recent delivery attempts for a webhook, including response status codes and timestamps. Useful for debugging failed deliveries.

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20, max: 100)
Example
curl "https://soscripted.com/api/public/webhooks/wh_abc123/deliveries?page=1&limit=20" \
  -H "Authorization: Bearer sk_your_api_key_here"
Success Response (200)
{
  "ok": true,
  "deliveries": [
    {
      "id": "del_xyz789",
      "event": "transcript.completed",
      "statusCode": 200,
      "success": true,
      "attemptedAt": "2026-02-24T12:05:00Z"
    },
    {
      "id": "del_xyz790",
      "event": "batch.completed",
      "statusCode": 500,
      "success": false,
      "attemptedAt": "2026-02-24T12:03:00Z",
      "nextRetryAt": "2026-02-24T12:08:00Z"
    }
  ],
  "pagination": { "page": 1, "limit": 20, "total": 2 }
}

Channel Monitors API

Automatically watch channels for new videos and transcribe them as they are published. Set a monthly credit budget to control costs.

POST /monitors

Create a new channel monitor. The monitor will periodically check the channel for new videos and auto-transcribe them.

FieldTypeDescription
channelUrlstringChannel or profile URL to monitor
collectionIdstring?Save new transcripts to this collection
checkIntervalstring?How often to check: "hourly", "daily" (default), or "weekly"
videoTypesstring[]?Filter by type: "video", "short", "live", "reel", "story"
monthlyBudgetnumber?Max credits to spend per month on this monitor
Example Request
POST /api/public/monitors HTTP/1.1
Host: soscripted.com
Authorization: Bearer sk_your_api_key_here
Content-Type: application/json

{
  "channelUrl": "https://www.youtube.com/@mkbhd",
  "collectionId": "clx456def",
  "checkInterval": "daily",
  "videoTypes": ["video"],
  "monthlyBudget": 30
}
Success Response (201)
{
  "ok": true,
  "data": {
    "id": "mon_abc123",
    "channelUrl": "https://www.youtube.com/@mkbhd",
    "channelName": "MKBHD",
    "platform": "youtube",
    "collectionId": "clx456def",
    "checkInterval": "daily",
    "videoTypes": ["video"],
    "monthlyBudget": 30,
    "creditsUsedThisMonth": 0,
    "autoTranscribe": true,
    "active": true,
    "lastCheckedAt": null,
    "createdAt": "2026-02-24T12:00:00Z"
  }
}

GET /monitors

List all your channel monitors with pagination.

ParameterTypeDescription
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20, max: 100)
Example
curl "https://soscripted.com/api/public/monitors?page=1&limit=20" \
  -H "Authorization: Bearer sk_your_api_key_here"
Success Response (200)
{
  "ok": true,
  "data": [
    {
      "id": "mon_abc123",
      "channelUrl": "https://www.youtube.com/@mkbhd",
      "channelName": "MKBHD",
      "platform": "youtube",
      "checkInterval": "daily",
      "monthlyBudget": 30,
      "creditsUsedThisMonth": 12,
      "active": true,
      "lastCheckedAt": "2026-02-24T06:00:00Z"
    }
  ],
  "pagination": { "page": 1, "limit": 20, "total": 1 }
}

PATCH /monitors/:id

Update a channel monitor. All fields are optional -- only include the fields you want to change.

FieldTypeDescription
activeboolean?Enable or pause the monitor
checkIntervalstring?"hourly", "daily", or "weekly"
collectionIdstring?Change the target collection
videoTypesstring[]?Update the video type filter
monthlyBudgetnumber?Update the monthly credit budget
autoTranscribeboolean?Auto-transcribe new videos or just notify
Example
curl -X PATCH "https://soscripted.com/api/public/monitors/mon_abc123" \
  -H "Authorization: Bearer sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"checkInterval": "hourly", "monthlyBudget": 50}'

DELETE /monitors/:id

Permanently delete a channel monitor. Previously transcribed videos are not affected.

Example
curl -X DELETE "https://soscripted.com/api/public/monitors/mon_abc123" \
  -H "Authorization: Bearer sk_your_api_key_here"

Webhook Payloads & Verification

All webhook deliveries include a signature header for verification. The payload is signed with your webhook secret using HMAC-SHA256.

Signature Verification

Each delivery includes an X-SoScripted-Signature header containing the HMAC-SHA256 hex digest of the raw request body.

Node.js Verification
import crypto from "crypto";

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body, "utf-8")
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler:
app.post("/webhooks/soscripted", (req, res) => {
  const signature = req.headers["x-soscripted-signature"];
  const isValid = verifyWebhook(req.rawBody, signature, WEBHOOK_SECRET);

  if (!isValid) {
    return res.status(401).json({ error: "Invalid signature" });
  }

  const event = req.body;
  console.log("Event type:", event.event);
  // Handle the event...

  res.status(200).json({ received: true });
});
Python Verification
import hmac
import hashlib

def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# In your webhook handler (Flask example):
@app.route("/webhooks/soscripted", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-SoScripted-Signature", "")
    if not verify_webhook(request.data, signature, WEBHOOK_SECRET):
        return {"error": "Invalid signature"}, 401

    event = request.json
    print("Event type:", event["event"])
    # Handle the event...

    return {"received": True}, 200

transcript.completed

Fired when a transcription completes successfully, whether from a single request, batch import, or channel monitor.

Payload
{
  "event": "transcript.completed",
  "timestamp": "2026-02-24T12:05:00Z",
  "data": {
    "jobId": "job_abc123",
    "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "title": "Video Title",
    "platform": "youtube",
    "transcriptId": "clx789ghi",
    "duration": 245,
    "wordCount": 1830,
    "source": "api",
    "batchId": null,
    "monitorId": null
  }
}

transcript.failed

Fired when a transcription fails after all retry attempts are exhausted.

Payload
{
  "event": "transcript.failed",
  "timestamp": "2026-02-24T12:05:00Z",
  "data": {
    "jobId": "job_def456",
    "url": "https://www.youtube.com/watch?v=invalid",
    "platform": "youtube",
    "error": "Video not found or is private",
    "source": "api",
    "batchId": null,
    "monitorId": null
  }
}

batch.completed

Fired when all items in a batch import have been processed (completed or failed).

Payload
{
  "event": "batch.completed",
  "timestamp": "2026-02-24T14:30:00Z",
  "data": {
    "batchId": "batch_abc123",
    "sourceType": "youtube_channel",
    "sourceName": "MrBeast",
    "totalVideos": 50,
    "completedVideos": 48,
    "failedVideos": 2,
    "creditsUsed": 48
  }
}

monitor.new_video

Fired when a monitored channel publishes a new video. If autoTranscribe is enabled, a transcription job is started automatically.

Payload
{
  "event": "monitor.new_video",
  "timestamp": "2026-02-24T15:00:00Z",
  "data": {
    "monitorId": "mon_abc123",
    "channelName": "MKBHD",
    "platform": "youtube",
    "videoUrl": "https://www.youtube.com/watch?v=newvideo",
    "videoTitle": "New Video Title",
    "publishedAt": "2026-02-24T14:55:00Z",
    "autoTranscribe": true,
    "jobId": "job_ghi789"
  }
}

Code Examples

JavaScript (JSON response)

fetch
const response = await fetch("https://soscripted.com/api/public/transcribe", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_your_api_key_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  }),
});

const data = await response.json();

if (data.ok) {
  console.log("Transcript:", data.caption.text);
} else {
  console.error("Error:", data.error);
}

JavaScript (SSE streaming)

EventSource via fetch
const response = await fetch("https://soscripted.com/api/public/transcribe", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_your_api_key_here",
    "Content-Type": "application/json",
    "Accept": "text/event-stream",
  },
  body: JSON.stringify({
    url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  }),
});

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });
  const lines = buffer.split("\n");
  buffer = lines.pop() || "";

  for (const line of lines) {
    if (line.startsWith("data: ")) {
      const data = JSON.parse(line.slice(6));
      console.log("Event:", data);
    }
  }
}

Python (JSON response)

requests
import requests

response = requests.post(
    "https://soscripted.com/api/public/transcribe",
    headers={
        "Authorization": "Bearer sk_your_api_key_here",
        "Content-Type": "application/json",
    },
    json={"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"},
    timeout=600,
)

data = response.json()

if data.get("ok"):
    print("Transcript:", data["caption"]["text"])
else:
    print("Error:", data.get("error"))

Python (SSE streaming)

requests + sseclient
import requests
import json

response = requests.post(
    "https://soscripted.com/api/public/transcribe",
    headers={
        "Authorization": "Bearer sk_your_api_key_here",
        "Content-Type": "application/json",
        "Accept": "text/event-stream",
    },
    json={"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"},
    stream=True,
)

for line in response.iter_lines(decode_unicode=True):
    if line.startswith("data: "):
        data = json.loads(line[6:])
        print("Event:", data)
        if "caption" in data:
            print("Transcript:", data["caption"]["text"])

Supported Platforms

YouTube
TikTok
Instagram
Facebook
Twitter / X
LinkedIn
Pinterest

Related Resources

Start building with the API

Free account includes 3 credits. Generate an API key from your dashboard and start transcribing in seconds.