Перейти к основному содержанию

Documentation Index

Fetch the complete documentation index at: https://docs.runblob.io/llms.txt

Use this file to discover all available pages before exploring further.

Webhooks доставляют события завершения, ошибки и таймаута прямо на ваш эндпоинт — без polling.

Руководство по настройке

1

Создайте webhook-эндпоинт

Поднимите HTTPS-эндпоинт, принимающий POST-запросы.
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/webhook/o3-video', methods=['POST'])
def handle_webhook():
    data = request.json
    
    if data['status'] == 'completed':
        print(f"Video ready: {data['video_url']}")
        # Process the completed video
    else:
        print(f"Generation failed: {data['message']}")
        # Handle the error
        
    return jsonify({'status': 'received'}), 200
2

Передайте URL webhook

Укажите URL вашего webhook при создании задачи.
curl -X POST https://platform.runblob.io/v1/kling/o3-video/generate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Dragon flying over mountains",
    "duration": "10",
    "mode": "pro",
    "callback_url": "https://your-app.com/webhook/o3-video"
  }'
3

Обработайте уведомления

Ваш эндпоинт получит мгновенное уведомление по готовности задачи.

Структура payload

Отправляется при успешной генерации.
{
  "generation_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "video_url": "https://cdn.example.com/videos/550e8400.mp4",
  "model": "kling-o3-video-10s-pro",
  "message": null
}
status
string
Всегда "completed" при успехе
generation_id
string
UUID завершённой задачи
video_url
string
Прямая ссылка для скачивания видео
model
string
Использованная конфигурация модели (например, kling-o3-video-10s-pro)
message
null
Всегда null при успехе

Коды ошибок

Типичные коды, приходящие через webhooks:
КодОписаниеДействие
CONTENT_POLICY_VIOLATIONКонтент нарушает правилаИзмените промпт
IMAGE_INACCESSIBLEURL изображения вернул 404/403Проверьте URL
INVALID_IMAGEФормат изображения невалиденИспользуйте JPEG/PNG
TIMEOUTГенерация превысила 15 минутКредиты возвращены
TASK_FAILEDОбщая системная ошибкаКредиты возвращены, повтор
MAINTENANCEСервис временно недоступенПовторите позже
Полный справочник ошибок: Коды ошибок

Возможности надёжности

Политика повторов: до 5 попыток с интервалом 30 секундСтратегия задержки: линейнаяОбработка отказа: после 5 попыток webhook помечается как failed
Тайм-аут запроса: 30 секундТайм-аут соединения: 10 секундРекомендация: быстро отвечайте кодом 200, обрабатывайте асинхронно
HTTPS обязателен: URL webhook должен использовать HTTPSIP allowlist: рассмотрите ограничение по IP RunBlobВалидация: всегда проверяйте generation_id

Примеры реализации

from flask import Flask, request, jsonify
import logging

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)

@app.route('/webhook/o3-video', methods=['POST'])
def o3_video_webhook():
    try:
        data = request.json
        generation_id = data.get('generation_id')
        
        if data.get('status') == 'completed':
            video_url = data.get('video_url')
            model = data.get('model')
            logging.info(f"Video ready for {generation_id}: {video_url} ({model})")
            
            # Process successful generation
            process_video(generation_id, video_url, model)
        else:
            error_code = data.get('message')
            logging.error(f"Generation failed for {generation_id}: {error_code}")
            
            # Handle failure
            handle_failure(generation_id, error_code)
        
        return jsonify({'status': 'received'}), 200
    except Exception as e:
        logging.error(f"Webhook error: {str(e)}")
        return jsonify({'error': 'Internal error'}), 500

def process_video(generation_id, video_url, model):
    """Process completed video - download, store, notify user"""
    # Download video to your storage
    # Update database
    # Notify user via email/push notification
    pass

def handle_failure(generation_id, error_code):
    """Handle failed generation - log, refund, notify"""
    # Log error for analytics
    # Update database with failure reason
    # Notify user of failure
    pass

if __name__ == '__main__':
    app.run(port=3000)

Лучшие практики

Всегда сразу возвращайте 200 OK. Тяжёлую обработку делайте асинхронно:
app.post('/webhook', async (req, res) => {
  // Acknowledge receipt immediately
  res.status(200).json({ status: 'received' });
  
  // Process asynchronously
  processWebhookAsync(req.body).catch(console.error);
});
Храните ID генераций в базе, чтобы избежать повторной обработки:
def handle_webhook(data):
    generation_id = data['generation_id']
    
    # Check if already processed
    if db.is_processed(generation_id):
        return  # Skip duplicate
    
    # Mark as processed
    db.mark_processed(generation_id)
    
    # Process the video
    process_video(data)
Всегда проверяйте payload перед обработкой:
function validateWebhook(payload) {
  if (!payload.generation_id || !payload.status) {
    throw new Error('Invalid webhook payload');
  }
  
  if (payload.status === 'completed' && !payload.video_url) {
    throw new Error('Missing video_url for completed generation');
  }
  
  return true;
}
Важно: всегда быстро возвращайте код 200, чтобы подтвердить получение. Тяжёлую обработку выполняйте асинхронно.