Daftarkan mediaWebhookUrl, terima POST saat job selesai, polling GET /api/media/jobs/{id}, tangani kode error, dan pahami penagihan serta batas idempotensi.
Panduan operasional untuk job media asinkron: pendaftaran webhook, status, polling, kode error, biaya, dan batas idempotensi — sepenuhnya sesuai implementasi saat ini di dalam kode.
Siklus hidup job
POST /api/media/generate — saat berhasil 202 dan { ok: true, jobId, status: "processing" }. Tidak ada status queued / running terpisah di API: sampai job selesai, klien melihat processing.
Upstream dapat melewati tahap internal (waiting, generating) — ini tidak tercermin di API publik; selama polling, job tetap processing.
Status terminal: success (memiliki resultUrls, dikenai biaya saat berhasil) atau fail (tanpa biaya).
Penyelesaian dicatat sekali: melalui callback upstream atau pada polling lazy di GET /api/media/jobs/{id}.
Polling: GET /api/media/jobs/{id}
GEThttps://getvibeapi.com/api/media/jobs/{id}
Parameter
Tipe
Deskripsi
status
string
submitting | processing | success | fail. submitting + media_submission_uncertain is non-terminal; within about 10–15 minutes such a submission is closed as fail (media_submission_not_started) without a charge — create a new task.
resultUrls
string[]
URL bertanda tangan /api/media/file/{id}/{idx}?sig=… (tanpa kunci API).
priceRub
number
Jumlah biaya dalam USD (0 jika gagal atau sebelum selesai).
failMsg
string | null
Pesan aman saat gagal atau media_submission_uncertain non-terminal.
errorCode
string | null
Kode error (media_generation_failed) atau media_submission_uncertain non-terminal.
retryGuidance
string | null
Pada media_submission_uncertain: instruksi aman untuk melakukan polling ke jobId yang sama nanti dan tidak membuat duplikat secara otomatis.
# 2. poll the job until it is ready
curl https://getvibeapi.com/api/media/jobs/JOB_ID \
-H "Authorization: Bearer $GETVIBE_API_KEY"
# → {"status":"success","resultUrls":["https://..."],"priceRub":...}
Interval polling yang direkomendasikan: 3–5 s, dengan exponential backoff hingga 30 s. Timeout di sisi klien sesuai SLA aplikasi Anda (pembuatan video dapat memakan waktu beberapa menit).
Pendaftaran webhook
GEThttps://getvibeapi.com/api/webhooks
PATCHhttps://getvibeapi.com/api/webhooks
Satu URL per akun: mediaWebhookUrl. Dikonfigurasi di dashboard → Webhooks atau melalui API dengan sesi akun (cookie setelah login). Endpoint tidak menerima sk-pv-… — hanya sesi yang terautentikasi.
# Example (a dashboard session is required, not an API key)
curl -X PATCH https://getvibeapi.com/api/webhooks \
-H "Content-Type: application/json" \
-b "session=YOUR_SESSION" \
-d '{"mediaWebhookUrl":"https://example.com/webhooks/media"}'
# Clear the URL
curl -X PATCH https://getvibeapi.com/api/webhooks \
-H "Content-Type: application/json" \
-b "session=YOUR_SESSION" \
-d '{"mediaWebhookUrl":null}'
Persyaratan URL
Parameter
Tipe
Deskripsi
mediaWebhookUrl
URL HTTPS
Alamat HTTPS publik; alamat privat/loopback dan domain kami sendiri ditolak (perlindungan SSRF), dan alamat tersebut diperiksa ulang sebelum setiap pengiriman. String kosong atau null akan meresetnya.
balanceWebhookUrl
URL HTTPS
Webhook terpisah untuk saldo rendah (bukan media), ditandatangani dengan secret akun yang sama, x-pv-event: balance.low. Ambangnya adalah balanceWebhookThresholdRub.
Pengiriman webhook saat pekerjaan selesai
Saat pekerjaan mencapai status terminal, GetVibe membuat satu peristiwa logis dan mengirimkannya melalui POST ke mediaWebhookUrl yang terdaftar. Pengiriman dibatasi: layanan melakukan hingga 5 percobaan total. Payload yang sama dapat tiba lebih dari sekali.
// POST to your mediaWebhookUrl when a job finishes
{
"jobId": "...",
"status": "success", // or "fail"
"model": "veo-3.1",
"kind": "video", // image | video | audio | music | 3d
"resultUrls": ["https://getvibeapi.com/api/media/file/..."],
"failMsg": null,
"createdAt": "2026-06-17T10:00:00.000Z"
}
Perilaku pengiriman (sesuai kode)
Parameter
Tipe
Deskripsi
Signature / auth
—
Setiap pengiriman ditandatangani dengan Standard Webhooks: header webhook-id, webhook-timestamp, dan webhook-signature (v1, HMAC-SHA256 dalam base64 dari “id.timestamp.body”). Secret akun ditampilkan di dasbor → Webhooks dan dikembalikan ke kunci API sebagai accountSecret oleh GET /api/media/webhook-secret; pengiriman ke webhook_url per permintaan ditandatangani dengan secret kunci tersebut (field secret). Tolak permintaan dengan signature yang salah atau timestamp yang lebih lama dari 5 menit.
Retries
outbox
Hingga 5 percobaan total; interval setelah kegagalan: 1, 2, 4, 8 menit. Setelah percobaan habis, event berpindah ke FAILED dan tidak lagi dikirimkan secara otomatis. Polling GET /api/media/jobs/{id} tetap menjadi sumber status.
Receiver dedup
required
Deduplikasi berdasarkan pasangan jobId + status dan buat handler Anda idempoten. Jangan gunakan webhook sebagai satu-satunya sumber status.
Content-Type
application/json
Body berupa JSON dengan field jobId, status, model, kind, resultUrls, failMsg, createdAt.
Error POST /api/media/generate
HTTP
Kapan
Biaya
Retry
202
Job diterima (ok: true, jobId)
Tidak (hanya setelah berhasil)
—
400
JSON / body permintaan tidak valid
Tidak
Perbaiki permintaan
401
Kunci API tidak ada atau tidak valid
Tidak
Periksa Authorization
402
Saldo tidak cukup (admission)
Tidak
Isi ulang saldo
422
Model tidak dikenal, opts tidak valid, ok: false dari fasad
Tidak
Fix model/opts
502
media_submit_failed — upstream tidak tersedia
Tidak
Retry with backoff
503
priceUnavailable, routing guard, VIDEO_DISABLED, veo tanpa harga
Tidak
Model lain / versi lebih baru
Error polling dan kegagalan terminal
HTTP / status
Arti
Biaya
404
job tidak ditemukan atau jobId milik pihak lain
Tidak
processing
Job masih berjalan
Tidak
success
Selesai, resultUrls terisi
Ya — priceRub dalam respons
fail
Pembuatan gagal
No (priceRub = 0)
Penagihan dan idempotensi
Ditagih sekali saat berhasil. Di finalizeJob transisi processing → success|fail bersifat atomik: callback atau poll yang berulang tidak menciptakan tagihan kedua.
fail — gratis. Tidak ada pendebitan yang dilakukan pada status fail.
Kutipan penerimaan. Jika kutipan disimpan saat pembuatan, tepat itulah yang ditagih saat berhasil (tidak pernah lebih dari metering upstream yang sebenarnya).
Idempotensi create — melalui header. POST berulang ke /api/media/generate tanpa header tersebut akan membuat job baru dan tagihan baru saat berhasil. Kirim Idempotency-Key (hingga 255 karakter ASCII): percobaan ulang dengan key dan body yang sama dalam 24 jam mengembalikan jobId yang sama tanpa job baru; key yang sama dengan body berbeda menghasilkan 422, dan 409 selama permintaan pertama masih diproses. jobId dari generasi berbayar juga ditampilkan di GET /v1/generations (field job_id).
Webhook dibatasi maksimal lima percobaan. Satu event logis dibuat per transisi terminal, tetapi percobaan pengiriman bisa berulang. Setelah lima kegagalan, event mendapat status FAILED . Handler di sisi klien harus melakukan deduplikasi terhadap pasangan jobId + status.