Ana içeriğe geç

REST API’yi kullanın

API anahtarı oluşturun, video yükleyin, altyazı projesi oluşturup tamamlanan çıktıyı indirin.

Entegrasyonlar Max aboneliklerinde kullanılabilir. Video işleme mevcut dakikalarınızı ve plan sınırlarınızı kullanır.
Entegrasyon ayarlarını aç

API anahtarı oluşturun

Entegrasyonlar Max aboneliklerinde kullanılabilir. Ayarlar → Entegrasyonlar altında API anahtarı oluştur seçin, ad ve izinleri belirtin.

Yalnız gereken izinleri verin. Okuma, yazma ve dışa aktarma varsayılan seçilidir. İlerleme veya sonuçlar için okuma iznini koruyun.

| Ayarlardaki izin | Scope | Kullanım | | --- | --- | --- | | Projeleri oku | projects:read | Hesap, stiller, ön ayarlar, projeler, işlemler ve sonuçlar | | Proje oluştur ve yönet | projects:write | Yükleme, oluşturma, iptal ve yeniden deneme | | Projeleri dışa aktar | exports:write | Dışa aktarma, otomatik dışa aktarma ve yeniden denemeleri | | Webhooks yönet | webhooks:manage | Uç noktalar ve teslimatlar; isteğe bağlı, varsayılan seçilmez |

Anahtarlar varsayılan 90 günde sona erer. 1–365 gün veya süresiz seçilebilir. Kullanılmayanları iptal edin. Yeni istekler engellenir, kabul edilmiş işler iptal edilmez.

İlk isteği doğrulayın

Temel URL https://api.captionbolt.com. Anahtarı sunucudan veya yerel betikten Authorization başlığında gönderin. Tarayıcı koduna, URL’ye veya AI konuşmalarına koymayın. Oturum çerezleri kabul edilmez.

Bash’te anahtarı geçmişe kaydetmeden girin:

read -r -s -p 'CaptionBolt API key: ' CAPTIONBOLT_API_KEY
export CAPTIONBOLT_API_KEY
printf '\n'

curl --fail-with-body https://api.captionbolt.com/v1/account \
  -H "Authorization: Bearer $CAPTIONBOLT_API_KEY"

Yanıt bakiye, yükleme sınırları, çıktı biçimleri ve erişim süresini verir. Bakiye saniyedir; dakika için 60’a bölün. Başlamadan credits.availableCreditsSec kontrol edin.

Stiller için GET /v1/styles, kaydedilen ön ayarlar için GET /v1/presets kullanın. Listeler search, limit (1–100, varsayılan 50) ve offset kabul eder.

Videonuzu yükleyin

Proje oluşturmadan MP4, MOV, WebM veya AVI baytlarını yükleyin. Video URL’si kabul edilmez:

  1. Gerçek dosya metadatası ve Idempotency-Key ile POST /v1/uploads çağırın.
  2. İşlemi sorgulayın. completed olduğunda son resourceId yükleme ID’sidir. failed durumunda durun.
  3. Parça boyutu, sayısı ve yüklenen parçalar için GET /v1/uploads/{uploadId} okuyun.
  4. POST /v1/uploads/{uploadId}/parts ve {"partNumbers":[1]} ile URL isteyin; en fazla 32 parça.
  5. Eksik parçaları tam bayt uzunluğuyla URL’lerine PUT gönderin. Bu URL’lere API anahtarı göndermeyin.
  6. POST /v1/uploads/{uploadId}/complete adresine {} gönderip uploaded doğrulayın.

Ölçülen süreyi durationSec olarak verin. Vermezseniz planın en uzun video süresi ayrılır; düşük bakiye kısa videoyu bile engelleyebilir. İşlemeden önce gerçek süre kontrol edilir.

Yükleme ve proje oluşturma örneği

Node.js 24 örneği çok parçalı yükleme yapıp review projesi oluşturur. upload-and-create.mjs olarak kaydedin. Tüm videoyu belleğe almadan parça parça okur. Çalışırken dosyayı değiştirmeyin.

import { createHash } from "node:crypto";
import { openAsBlob } from "node:fs";
import { stat } from "node:fs/promises";
import { basename, extname } from "node:path";
import { setTimeout as sleep } from "node:timers/promises";

const apiKey = process.env.CAPTIONBOLT_API_KEY;
const uploadKey = process.env.CAPTIONBOLT_UPLOAD_KEY;
const createKey = process.env.CAPTIONBOLT_CREATE_KEY;
const [filePath, durationText] = process.argv.slice(2);
const durationSec = Number(durationText);
if (!apiKey || !uploadKey || !createKey || !filePath || !Number.isFinite(durationSec) || durationSec <= 0) {
  throw new Error("Set the API key and action keys, then supply a file and measured duration in seconds.");
}

async function api(method, path, input, idempotencyKey) {
  const response = await fetch(`https://api.captionbolt.com${path}`, {
    method,
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
      ...(idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}),
    },
    ...(input === undefined ? {} : { body: JSON.stringify(input) }),
    redirect: "error",
    signal: AbortSignal.timeout(30000),
  });
  if (!response.ok) {
    const error = await response.json().catch(() => null);
    const detail = error?.message ?? error?.code ?? "Request failed";
    throw new Error(`API HTTP ${response.status}: ${detail}; Retry-After: ${response.headers.get("retry-after") ?? "none"}`);
  }
  return response.json();
}

async function waitForOperation(operation) {
  console.log("Operation ID:", operation.id);
  const deadline = Date.now() + 120000;
  while (operation.state !== "completed") {
    if (operation.state === "failed") throw new Error(operation.error ?? "Action failed");
    if (Date.now() >= deadline) throw new Error(`Continue polling operation ${operation.id}; do not start a new action.`);
    await sleep(Math.max(1, operation.pollAfterSeconds) * 1000);
    operation = await api("GET", `/v1/operations/${operation.id}`);
  }
  return operation;
}

const contentType = {
  ".mp4": "video/mp4", ".mov": "video/quicktime",
  ".webm": "video/webm", ".avi": "video/x-msvideo",
}[extname(filePath).toLowerCase()];
if (!contentType) throw new Error("Choose an MP4, MOV, WebM or AVI file.");
const metadata = await stat(filePath);
if (!metadata.isFile()) throw new Error("Choose a regular video file.");
const video = await openAsBlob(filePath, { type: contentType });
const fileName = basename(filePath);
const lastModifiedMs = Math.trunc(metadata.mtimeMs);
const fingerprint = createHash("sha256")
  .update(`captionbolt-upload-v1\0${fileName}\0${video.size}\0${lastModifiedMs}\0${contentType}`)
  .update(Buffer.from(await video.slice(0, 65536).arrayBuffer()))
  .update(Buffer.from(await video.slice(Math.max(65536, video.size - 65536)).arrayBuffer()))
  .digest("hex");

const uploaded = await waitForOperation(await api("POST", "/v1/uploads", {
  fileName, fileSize: video.size, lastModifiedMs, contentType, fingerprint, durationSec,
}, uploadKey));
const uploadId = uploaded.resourceId;
console.log("Upload ID:", uploadId);
let upload = await api("GET", `/v1/uploads/${uploadId}`);
if (upload.status === "uploading" || upload.status === "completing") {
  upload = await api("POST", `/v1/uploads/${uploadId}/resume`, {});
}
if (upload.status === "completing") {
  throw new Error("Upload completion is still in progress. Wait, then rerun with the same action keys.");
}
if (upload.status === "expired" || upload.status === "aborted") {
  throw new Error(`Upload is ${upload.status}. Start a new upload with new action keys.`);
}
if (upload.status !== "uploaded" && upload.status !== "consumed") {
  const completed = new Set(upload.completedPartNumbers);
  for (let number = 1; number <= upload.partCount; number++) {
    if (completed.has(number)) continue;
    const signed = await api("POST", `/v1/uploads/${uploadId}/parts`, { partNumbers: [number] });
    for (const part of signed.signedParts) {
      const start = (part.partNumber - 1) * upload.partSize;
      const bytes = video.slice(start, start + part.contentLength);
      if (bytes.size !== part.contentLength) throw new Error("File part length changed.");
      const response = await fetch(part.url, {
        method: "PUT", body: bytes,
        headers: { "Content-Length": String(part.contentLength) },
        redirect: "error", signal: AbortSignal.timeout(120000),
      });
      if (!response.ok) throw new Error(`Part ${part.partNumber}: HTTP ${response.status}`);
    }
  }
  const finished = await api("POST", `/v1/uploads/${uploadId}/complete`, {});
  if (finished.status !== "uploaded") throw new Error("Upload is not ready for project creation.");
}

const created = await waitForOperation(await api("POST", "/v1/projects", {
  uploadSessionId: uploadId, mode: "review",
}, createKey));
console.log("Project ID:", created.resourceId);

Yükleme ve proje oluşturma için işlem anahtarlarını bir kez üretin. Aynı istekleri yinelemek için koruyun; farklı video veya işlemde yeni anahtar kullanın.

export CAPTIONBOLT_UPLOAD_KEY="$(node -e 'console.log(crypto.randomUUID())')"
export CAPTIONBOLT_CREATE_KEY="$(node -e 'console.log(crypto.randomUUID())')"
node upload-and-create.mjs /absolute/path/lesson.mp4 60

Yolu ve 60 değerini dosyanız ve ölçülen saniyeyle değiştirin. FFprobe gibi araç kullanın; dosya boyutundan tahmin etmeyin. Betik kurtarma için işlem ID’lerini, ardından yükleme ve proje ID’lerini gösterir.

SHA-256 parmak izi, gösterilen UTF-8 metadata önekini ve ilk/son 64 KiB’yi örtüşen baytları tekrarlamadan kullanır. Devam ederken ad, boyut, değiştirme zamanı ve MIME aynı kalmalıdır.

Projeyi izleyin

PROJECT_ID değerini gösterilen ID’ye ayarlayın:

export PROJECT_ID='<project-id>'
curl --fail-with-body "https://api.captionbolt.com/v1/projects/$PROJECT_ID" \
  -H "Authorization: Bearer $CAPTIONBOLT_API_KEY"

status okuyup pollAfterSeconds aralığını izleyin:

| Durum | Yapılacak işlem | | --- | --- | | processing | Video hazırlığı ve altyazıları bekleyin | | ready | CaptionBolt’ta inceleyip kaydedin, sonra dışa aktarın | | exporting | Dışa aktarmayı bekleyin | | completed | Sonucu alıp dosyaları indirin | | failed | error okuyun, nedeni düzeltip açıkça yeniden deneyin | | cancelled | Sorgulamayı durdurun; bu çalışma iptal edildi |

İşlemin completed olması video bitti demek değildir. İşlem eylemi, proje durumu videoyu anlatır. GET /v1/operations/{id} sorgulayın; failed olursa durup error okuyun.

Oluştururken language ve listelerden styleId veya presetId verebilirsiniz. İkisini de vermemek varsayılan stili seçer. mode: "auto-export" işlem sonrası MP4 üretir ve ayrıca exports:write ister. ready durumunda kalırsa autoExport işlemini inceleyin.

Kaydedilen değişiklikleri dışa aktarın

review projesini CaptionBolt editöründe inceleyip kaydedin. Dışa aktarma anahtarını bir kez üretip isteği gönderin:

export CAPTIONBOLT_EXPORT_KEY="$(node -e 'console.log(crypto.randomUUID())')"
curl --fail-with-body "https://api.captionbolt.com/v1/projects/$PROJECT_ID/export" \
  -H "Authorization: Bearer $CAPTIONBOLT_API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $CAPTIONBOLT_EXPORT_KEY" \
  --data '{"outputFormats":["mp4"]}'

Önce işlemi, sonra projeyi completed olana dek sorgulayın; biri başarısızsa durun. Yalnız son kaydedilen değişiklikler alınır. outputFormats, plana göre mp4, srt, vtt, ass, txt içerebilir. Varsayılan MP4’tür.

Dosyaları indirin

Proje completed olduğunda:

curl --fail-with-body "https://api.captionbolt.com/v1/projects/$PROJECT_ID/result" \
  -H "Authorization: Bearer $CAPTIONBOLT_API_KEY"

Yanıt files içinde format ve url, ayrıca linkler için expiresAt döndürür. Dosya URL’lerine anahtar göndermeden indirin.

Linkler en fazla on dakika geçerlidir. Oluşturulmasından itibaren 14 günlük proje erişimi içinde yenileyin; yenileme erişimi uzatmaz. Projenin expiresAt alanı erişim, sonucunki link sonudur.

Tamamlanan projeler mevcut çıktıyı korur. Yeniden düzenlemek için CaptionBolt’ta düzenlenebilir kopya oluşturun.

Hatalardan kurtulun

| Yanıt | Sonraki adım | | --- | --- | | 400 | Alanları ve gerekli idempotency başlıklarını kontrol edin | | 401 | Anahtar geçerli, süresi dolmamış ve iptal edilmemiş olmalı | | 403 | İzinleri ve sınırları kontrol edin; yazma, ilerlemeyi okumaya yetmez | | 404 | ID ve hesabı kontrol edin; silinmiş veya süresi dolmuş projeler erişilemez | | 409 | Durumu veya aynı anahtarın farklı veriyle kullanımını kontrol edin | | 429 | Retry-After varsa bekleyip hatayı okuyun; istek sıklığı veya yükleme/iş kapasitesi sınırlı olabilir. REST ve MCP hesap başına dakikada 120 isteği paylaşır | | 503 veya zaman aşımı | Bekleyin, bilinen işlemi sorgulayın veya aynı eylemi özgün anahtarla tekrarlayın |

HTTP başarısı sonradan başarısız olacak bir işlemi kabul edebilir. operation.state ve operation.error kontrol edin. PAYMENT_REQUIRED yetersiz kullanılabilir dakika demektir; aktif işler dakika ayırmış olabilir. PAYLOAD_TOO_LARGE dosyanın güncel sınırı aştığını belirtir. GET /v1/account kontrol edip düzeltin. Önceki işlem kesin başarısız olduktan sonra yeni anahtarla yeni işlem başlatın; eski anahtar aynı başarısız işlemi döndürür.

Yükleme ve proje oluşturma, dışa aktarma, yeniden deneme ve iptal için Idempotency-Key gerekir: boşluksuz 1–128 yazdırılabilir ASCII karakteri. Yeni işlem yeni anahtar ister. Zaman aşımında özgün anahtarı ve veriyi koruyun; yanıt kaybı başarısızlık kanıtı değildir.

Devam etmek için metadata ve parmak izini GET /v1/uploads/{uploadId} ile karşılaştırıp POST /v1/uploads/{uploadId}/resume çağırın. Dönen durum ve parça listesini kullanın. completing sürerse bekleyin; uploading iken eksikleri yükleyip tamamlayın. expired veya aborted yeni yükleme ister. DELETE /v1/uploads/{uploadId} tüketilmemiş yüklemeyi iptal eder, oluşturulmuş projeyi değil.

Açık yeniden deneme veya iptal için POST /v1/projects/{projectId}/retry ya da /cancel adresine boş JSON ve işlem anahtarını gönderin. Dışa aktarma yeniden denemesi ayrıca exports:write ister.

Anahtarsız GET /health/integrations, hazırsa 200, kullanılamıyorsa 503 verir. Kimlik bilgilerini veya video tamamlanmasını kontrol etmez.

Tüm şemalar API referansında (yeni bir pencerede açılır) ve OpenAPI’dedir. Düzenli sorgulama yerine aşama bildirimi için Webhooks kullanın.

Tercihleri hatırlamak, site performansını ölçmek ve CaptionBolt’u geliştirmek için çerezleri kullanıyoruz.