Overview

Callbacks provide an efficient way to receive notifications when your Runway Alpeh video generation tasks complete. Instead of repeatedly polling the API, your application can receive instant notifications via webhooks when videos are ready.
Callbacks are the recommended approach for production applications as they reduce API calls, improve response times, and provide immediate notification of task completion.

How Callbacks Work

1

Submit Generation Request

Include a callBackUrl parameter in your video generation request:
{
  "prompt": "Transform into a dreamy watercolor painting style with soft flowing movements",
  "videoUrl": "https://example.com/input-video.mp4",
  "callBackUrl": "https://your-app.com/webhook/aleph-callback"
}
2

Receive Task ID

The API immediately returns a task ID while processing begins:
{
  "code": 200,
  "msg": "success",
  "data": {
    "taskId": "ee603959-debb-48d1-98c4-a6d1c717eba6"
  }
}
3

Process Callback

When generation completes, our system sends a POST request to your callback URL with the results.

Callback Payload

When video generation completes, you’ll receive a POST request with the following payload:

Success Callback

{
  "code": 200,
  "msg": "success",
  "data": {
    "result_video_url": "https://file.com/k/xxxxxxx.mp4",
    "result_image_url": "https://file.com/m/xxxxxxxx.png"
  },
  "taskId": "ee603959-debb-48d1-98c4-a6d1c717eba6"
}
code
integer
Status code indicating the result
  • 200: Video generated successfully
  • 400: Generation failed due to content policy or technical issues
msg
string
Human-readable message describing the result
data
object
Video generation results
taskId
string
The original task ID from your generation request

Error Callback

{
  "code": 400,
  "msg": "Your prompt was caught by our AI moderator. Please adjust it and try again!",
  "data": null,
  "taskId": "ee603959-debb-48d1-98c4-a6d1c717eba6"
}

Implementing Callback Endpoints

Node.js/Express Example

const express = require('express');
const app = express();

// Middleware to parse JSON
app.use(express.json());

// Callback endpoint for Aleph video generation
app.post('/webhook/aleph-callback', (req, res) => {
  try {
    const { code, msg, data, taskId } = req.body;
    
    console.log(`Received callback for task: ${taskId}`);
    
    if (code === 200) {
      // Success - video generated
      console.log('Video generated successfully!');
      console.log('Video URL:', data.result_video_url);
      console.log('Thumbnail URL:', data.result_image_url);
      
      // Process the successful generation
      handleSuccessfulGeneration(taskId, data);
      
    } else {
      // Error occurred during generation
      console.error('Generation failed:', msg);
      
      // Handle the error
      handleGenerationError(taskId, msg);
    }
    
    // Always respond with 200 to acknowledge receipt
    res.status(200).json({ 
      code: 200, 
      msg: 'Callback received successfully' 
    });
    
  } catch (error) {
    console.error('Error processing callback:', error);
    res.status(500).json({ 
      code: 500, 
      msg: 'Error processing callback' 
    });
  }
});

async function handleSuccessfulGeneration(data) {
  try {
    // Update database with video information
    await updateTaskStatus(data.task_id, 'completed', {
      videoUrl: data.video_url,
      thumbnailUrl: data.image_url,
      videoId: data.video_id
    });
    
    // Optionally download and store the video
    await downloadAndStoreVideo(data.video_url, data.task_id);
    
    // Notify user or trigger next step in workflow
    await notifyUser(data.task_id, 'Video generation completed!');
    
  } catch (error) {
    console.error('Error handling successful generation:', error);
  }
}

async function handleGenerationError(taskId, errorMessage) {
  try {
    // Update database with error status
    await updateTaskStatus(taskId, 'failed', { error: errorMessage });
    
    // Notify user of the failure
    await notifyUser(taskId, `Video generation failed: ${errorMessage}`);
    
  } catch (error) {
    console.error('Error handling generation error:', error);
  }
}

app.listen(3000, () => {
  console.log('Webhook server listening on port 3000');
});

Python/Flask Example

from flask import Flask, request, jsonify
import logging
import requests
from datetime import datetime

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

@app.route('/webhook/aleph-callback', methods=['POST'])
def aleph_callback():
    try:
        data = request.get_json()
        
        if not data:
            return jsonify({'code': 400, 'msg': 'Invalid JSON payload'}), 400
        
        code = data.get('code')
        msg = data.get('msg', '')
        callback_data = data.get('data', {})
        task_id = data.get('taskId')
        
        logging.info(f"Received callback for task: {task_id}")
        
        if code == 200:
            # Success - video generated
            video_url = callback_data.get('result_video_url')
            image_url = callback_data.get('result_image_url')
            
            logging.info(f"Video generated successfully: {video_url}")
            
            # Process successful generation
            handle_successful_generation(task_id, callback_data)
            
        else:
            # Error occurred during generation
            logging.error(f"Generation failed for task {task_id}: {msg}")
            handle_generation_error(task_id, msg)
        
        # Always return 200 to acknowledge receipt
        return jsonify({'code': 200, 'msg': 'Callback received successfully'})
        
    except Exception as e:
        logging.error(f"Error processing callback: {str(e)}")
        return jsonify({'code': 500, 'msg': 'Error processing callback'}), 500

def handle_successful_generation(task_id, data):
    """Handle successful video generation"""
    try:
        # Update database
        update_task_status(task_id, 'completed', {
            'video_url': data['result_video_url'],
            'image_url': data['result_image_url'],
            'completed_at': datetime.utcnow()
        })
        
        # Download video if needed
        # download_video(video_url, task_id)
        
        # Send notification
        notify_user(task_id, 'Your Aleph video is ready!')
        
    except Exception as e:
        logging.error(f"Error handling successful generation: {str(e)}")

def handle_generation_error(task_id, error_message):
    """Handle generation error"""
    try:
        # Update database
        update_task_status(task_id, 'failed', {
            'error_message': error_message,
            'failed_at': datetime.utcnow()
        })
        
        # Send error notification
        notify_user(task_id, f'Video generation failed: {error_message}')
        
    except Exception as e:
        logging.error(f"Error handling generation error: {str(e)}")

def update_task_status(task_id, status, additional_data=None):
    """Update task status in database"""
    # Implement your database update logic here
    logging.info(f"Updating task {task_id} status to {status}")

def notify_user(task_id, message):
    """Send notification to user"""
    # Implement your notification logic here
    logging.info(f"Notifying user for task {task_id}: {message}")

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=False)

PHP Example

<?php
header('Content-Type: application/json');

// Enable error logging
error_reporting(E_ALL);
ini_set('log_errors', 1);
ini_set('error_log', 'callback_errors.log');

try {
    // Get JSON input
    $input = file_get_contents('php://input');
    $data = json_decode($input, true);
    
    if (!$data) {
        http_response_code(400);
        echo json_encode(['code' => 400, 'msg' => 'Invalid JSON payload']);
        exit;
    }
    
    $code = $data['code'] ?? null;
    $msg = $data['msg'] ?? '';
    $callbackData = $data['data'] ?? [];
    $taskId = $callbackData['task_id'] ?? null;
    
    error_log("Received callback for task: " . $taskId);
    
    if ($code === 200) {
        // Success - video generated
        $videoUrl = $callbackData['video_url'] ?? '';
        $imageUrl = $callbackData['image_url'] ?? '';
        $videoId = $callbackData['video_id'] ?? '';
        
        error_log("Video generated successfully: " . $videoUrl);
        
        handleSuccessfulGeneration($taskId, $videoUrl, $imageUrl, $videoId);
        
    } else {
        // Error occurred
        error_log("Generation failed for task $taskId: " . $msg);
        handleGenerationError($taskId, $msg);
    }
    
    // Always return 200 to acknowledge receipt
    http_response_code(200);
    echo json_encode(['code' => 200, 'msg' => 'Callback received successfully']);
    
} catch (Exception $e) {
    error_log("Error processing callback: " . $e->getMessage());
    http_response_code(500);
    echo json_encode(['code' => 500, 'msg' => 'Error processing callback']);
}

function handleSuccessfulGeneration($taskId, $videoUrl, $imageUrl, $videoId) {
    try {
        // Update database
        updateTaskStatus($taskId, 'completed', [
            'video_url' => $videoUrl,
            'image_url' => $imageUrl,
            'video_id' => $videoId,
            'completed_at' => date('Y-m-d H:i:s')
        ]);
        
        // Send notification
        notifyUser($taskId, 'Your Aleph video is ready!');
        
    } catch (Exception $e) {
        error_log("Error handling successful generation: " . $e->getMessage());
    }
}

function handleGenerationError($taskId, $errorMessage) {
    try {
        // Update database
        updateTaskStatus($taskId, 'failed', [
            'error_message' => $errorMessage,
            'failed_at' => date('Y-m-d H:i:s')
        ]);
        
        // Send notification
        notifyUser($taskId, "Video generation failed: $errorMessage");
        
    } catch (Exception $e) {
        error_log("Error handling generation error: " . $e->getMessage());
    }
}

function updateTaskStatus($taskId, $status, $additionalData = []) {
    // Implement your database update logic here
    error_log("Updating task $taskId status to $status");
    
    // Example using PDO:
    /*
    $pdo = new PDO($dsn, $username, $password);
    $stmt = $pdo->prepare("UPDATE tasks SET status = ?, updated_at = NOW() WHERE task_id = ?");
    $stmt->execute([$status, $taskId]);
    */
}

function notifyUser($taskId, $message) {
    // Implement your notification logic here
    error_log("Notifying user for task $taskId: $message");
    
    // Example: Send email, push notification, etc.
}
?>

Security Best Practices

Testing Callbacks

Local Development

For local testing, use tools like ngrok to expose your local server:
# Install ngrok
npm install -g ngrok

# Expose local port 3000
ngrok http 3000

# Use the provided HTTPS URL as your callback URL
# Example: https://abc123.ngrok.io/webhook/aleph-callback

Webhook Testing Tools

Troubleshooting


Need Help? Contact our support team at support@kie.ai for assistance with callback implementation.