Overview
Webhooks provide a push-based mechanism for receiving automation task results in real-time. Instead of continuously polling for task status, Narada Cloud automatically sends the response to your specified endpoint when the task completes.
Real-time Updates Receive results immediately when tasks complete, eliminating polling delays
Reduced Load Lower server load and API usage compared to continuous polling
Scalable Handle high-volume automation workflows efficiently
Efficient Process automation results without continuous API polling
How Webhooks Work
When you submit an automation task via the Remote Dispatch API , you can provide a callbackUrl. Once the task completes, Narada Cloud sends an HTTP POST request to your endpoint with the complete task results.
Submit Task with Webhook
Include callbackUrl when creating a remote dispatch request
Task Executes
Narada Cloud processes your automation task asynchronously
Receive Callback
When complete, Narada Cloud POSTs the results to your callback URL
Process Results
Your endpoint receives and processes the webhook payload
Webhooks are recommended for production applications where real-time notifications and scalability are important.
Configuration
Setting Up a Webhook Endpoint
Configure webhooks by providing the callbackUrl parameter when creating a remote dispatch request:
curl -X POST 'https://api.narada.ai/fast/v2/remote-dispatch' \
-H 'Content-Type: application/json' \
-H 'x-api-key: YOUR_API_KEY' \
-d '{
"prompt": "/Operator search for software engineering jobs and count the results",
"browserWindowId": "your-browser-window-id",
"callbackUrl": "https://your-domain.com/api/narada/webhook",
"callbackHeaders": {
"Authorization": "Bearer YOUR_WEBHOOK_TOKEN"
},
"callbackSecret": "your-secret-key-here"
}'
Configuration Parameters
The HTTPS URL where Narada Cloud will send the webhook POST request. Must be a publicly accessible endpoint that accepts POST requests.
Optional. HTTP headers to include when sending the webhook POST request. These headers are sent with the webhook notification, allowing you to authenticate or customize the request.{
"callbackUrl" : "https://example.com/webhook" ,
"callbackHeaders" : {
"Authorization" : "Bearer <token>" ,
"X-Custom-Header" : "value"
}
}
callbackHeaders is optional and only needed if your webhook endpoint requires authentication or custom headers. If your endpoint doesn’t require any special headers, you can omit this parameter.
Use callbackHeaders to send authentication tokens, API keys, or custom headers with your webhook requests. This is particularly useful when your webhook endpoint requires authentication.
Optional secret key included in the webhook payload body for verification. Use this to validate that webhook requests are genuinely from Narada Cloud.
HTTPS Required : Your callback URL must use HTTPS to ensure your callbackSecret, callbackHeaders, and webhook data are encrypted in transit.
When you provide callbackHeaders (or callback_headers in Python), Narada Cloud stores these headers and includes them in the HTTP POST request when sending the webhook notification. This allows you to:
Authenticate webhook requests using Bearer tokens, API keys, or custom authentication headers
Customize webhook delivery with custom headers required by your endpoint
Integrate with existing systems that require specific header formats
Webhook Payload
When an automation task completes, Narada Cloud sends a POST request to your callbackUrl with the following JSON payload:
Payload Structure
The unique identifier for the automation task. Use this to correlate webhook notifications with your original requests.
The callbackSecret you provided when creating the task. Returns null if no secret was specified.
Current status of the automation task. Possible values:
"input-required" - Task requires additional user input
"success" - Task completed successfully
"error" - Task failed with an error
The browser window ID where the task was executed. Returns null if not applicable.
The automation task response data containing the results. Show Response Object Properties
The main response text from the automation task.
ISO 8601 timestamp when the task was initially created.
ISO 8601 timestamp when the task completed.
Usage statistics for the automation task. Returns null if not available. Show Usage Object Properties
Number of actions performed during the automation task.
Number of credits consumed by the task.
Example Payloads
Success
Error
Input Required
Structured Output
{
"requestId" : "req_abc123def456" ,
"secret" : "your-secret-key-here" ,
"status" : "success" ,
"browserWindowId" : "window_xyz789" ,
"response" : {
"text" : "Found 1,234 software engineering job listings in the search results."
},
"createdAt" : "2024-11-21T10:00:00.000000+00:00" ,
"completedAt" : "2024-11-21T10:00:45.000000+00:00" ,
"usage" : {
"actions" : 12 ,
"credits" : 5
}
}
{
"requestId" : "req_abc123def456" ,
"secret" : "your-secret-key-here" ,
"status" : "error" ,
"browserWindowId" : "window_xyz789" ,
"response" : {
"text" : "Failed to complete the task due to network timeout."
},
"createdAt" : "2024-11-21T10:00:00.000000+00:00" ,
"completedAt" : "2024-11-21T10:02:30.000000+00:00" ,
"usage" : {
"actions" : 8 ,
"credits" : 3
}
}
{
"requestId" : "req_abc123def456" ,
"secret" : "your-secret-key-here" ,
"status" : "input-required" ,
"browserWindowId" : "window_xyz789" ,
"response" : {
"text" : "The task requires authentication. Please log in to continue."
},
"createdAt" : "2024-11-21T10:00:00.000000+00:00" ,
"completedAt" : "2024-11-21T10:00:15.000000+00:00" ,
"usage" : {
"actions" : 3 ,
"credits" : 1
}
}
{
"requestId" : "req_abc123def456" ,
"secret" : "your-secret-key-here" ,
"status" : "success" ,
"browserWindowId" : "window_xyz789" ,
"response" : {
"text" : "Successfully extracted job information." ,
"structuredOutput" : {
"title" : "Senior Software Engineer" ,
"company" : "TechCorp Inc." ,
"location" : "San Francisco, CA" ,
"salary" : "$150,000 - $200,000" ,
"remote" : true
}
},
"createdAt" : "2024-11-21T10:00:00.000000+00:00" ,
"completedAt" : "2024-11-21T10:00:52.000000+00:00" ,
"usage" : {
"actions" : 15 ,
"credits" : 6
}
}
Implementing a Webhook Endpoint
Basic Implementation
Create an endpoint that receives and processes webhook notifications:
Node.js (Express)
Python (FastAPI)
const express = require ( 'express' );
const app = express ();
app . use ( express . json ());
app . post ( '/api/narada/webhook' , ( req , res ) => {
const payload = req . body ;
// Verify authentication - check Authorization header from callbackHeaders
const authHeader = req . headers . authorization ;
if ( authHeader && authHeader !== `Bearer ${ process . env . WEBHOOK_TOKEN } ` ) {
return res . status ( 401 ). json ({ error: 'Invalid authorization header' });
}
// Also verify the secret if provided
if ( payload . secret && payload . secret !== process . env . NARADA_CALLBACK_SECRET ) {
return res . status ( 401 ). json ({ error: 'Invalid secret' });
}
// Process the webhook payload
console . log ( `Task ${ payload . requestId } completed with status: ${ payload . status } ` );
if ( payload . status === 'success' ) {
console . log ( 'Response:' , payload . response . text );
// Handle successful completion
handleSuccess ( payload );
} else if ( payload . status === 'error' ) {
console . error ( 'Task failed:' , payload . response . text );
// Handle error
handleError ( payload );
} else if ( payload . status === 'input-required' ) {
console . log ( 'Input required:' , payload . response . text );
// Handle input requirement
handleInputRequired ( payload );
}
// Always respond with 200 to acknowledge receipt
res . status ( 200 ). json ({ received: true });
});
function handleSuccess ( payload ) {
// Your success handling logic
// Store results, trigger next steps, etc.
}
function handleError ( payload ) {
// Your error handling logic
// Log errors, retry tasks, send alerts, etc.
}
function handleInputRequired ( payload ) {
// Your input handling logic
// Notify users, pause workflows, etc.
}
app . listen ( 3000 , () => {
console . log ( 'Webhook endpoint listening on port 3000' );
});
from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel
from typing import Any, Literal, Mapping
import os
app = FastAPI()
class RemoteDispatchUsage ( BaseModel ):
actions: int
credits : int
class WebhookPayload ( BaseModel ):
requestId: str
secret: str | None
status: Literal[ "input-required" , "success" , "error" ]
browserWindowId: str | None
response: Mapping[ str , Any]
createdAt: str
completedAt: str
usage: RemoteDispatchUsage | None
@app.post ( "/api/narada/webhook" )
async def handle_webhook ( request : Request, payload : WebhookPayload):
# Verify authentication - check Authorization header from callback_headers
auth_header = request.headers.get( "authorization" )
expected_token = os.getenv( 'WEBHOOK_TOKEN' )
if auth_header and expected_token:
if auth_header != f "Bearer { expected_token } " :
raise HTTPException( status_code = 401 , detail = "Invalid authorization header" )
# Also verify the secret if provided
expected_secret = os.getenv( 'NARADA_CALLBACK_SECRET' )
if expected_secret and payload.secret != expected_secret:
raise HTTPException( status_code = 401 , detail = "Invalid secret" )
# Process the webhook payload
print ( f "Task { payload.requestId } completed with status: { payload.status } " )
if payload.status == "success" :
print ( f "Response: { payload.response.get( 'text' ) } " )
handle_success(payload)
elif payload.status == "error" :
print ( f "Task failed: { payload.response.get( 'text' ) } " )
handle_error(payload)
elif payload.status == "input-required" :
print ( f "Input required: { payload.response.get( 'text' ) } " )
handle_input_required(payload)
# Always respond with 200 to acknowledge receipt
return { "received" : True }
def handle_success ( payload : WebhookPayload):
# Your success handling logic
pass
def handle_error ( payload : WebhookPayload):
# Your error handling logic
pass
def handle_input_required ( payload : WebhookPayload):
# Your input handling logic
pass
Response Requirements
Your webhook endpoint must:
Accept POST Requests
Configure your endpoint to accept HTTP POST requests with JSON payloads.
Respond Quickly
Return a 200 OK response promptly to acknowledge receipt. Perform long-running operations asynchronously.
Security Best Practices
1. Use HTTPS
Always use HTTPS endpoints to ensure your callbackSecret and webhook data are encrypted in transit.
# ✅ Good
https://api.yourdomain.com/webhook
# ❌ Bad
http://api.yourdomain.com/webhook
2. Verify Authentication
You can authenticate webhook requests using either callbackHeaders or callbackSecret:
Using callbackHeaders (Recommended for API-based auth):
// Verify Authorization header from callbackHeaders
const authHeader = req . headers . authorization ;
if ( authHeader !== `Bearer ${ process . env . WEBHOOK_TOKEN } ` ) {
return res . status ( 401 ). json ({ error: 'Unauthorized' });
}
Using callbackSecret:
// Verify secret from payload body
if ( payload . secret !== process . env . NARADA_CALLBACK_SECRET ) {
return res . status ( 401 ). json ({ error: 'Unauthorized' });
}
Using both (Maximum security):
// Verify both header and secret
const authHeader = req . headers . authorization ;
const isValidHeader = authHeader === `Bearer ${ process . env . WEBHOOK_TOKEN } ` ;
const isValidSecret = payload . secret === process . env . NARADA_CALLBACK_SECRET ;
if ( ! isValidHeader || ! isValidSecret ) {
return res . status ( 401 ). json ({ error: 'Unauthorized' });
}
Store your authentication tokens and secrets in environment variables, never in your code or version control. Use callbackHeaders for API-based authentication and callbackSecret for payload-based verification.
Common Issues
Possible causes:
Callback URL is not publicly accessible
Firewall blocking incoming requests
HTTPS certificate issues
Server is down or not responding
Solutions:
Verify your endpoint is publicly accessible
Check firewall and security group settings
Ensure valid SSL certificate
Monitor server uptime and health
Comparison: Webhooks vs Polling
Feature Webhooks Polling Response Time Immediate Delayed by poll interval Server Load Low Higher (active requests) Implementation Moderate complexity Simple Firewall Friendly Requires open ports Yes Scalability Excellent Limited Real-time Updates Yes No API Efficiency High Lower Production Ready Yes (recommended) Yes
Use webhooks for production applications where real-time notifications are important. Use polling via Get Task Status when webhook setup is not feasible.
Best Practices Summary
Respond Quickly Return 200 OK promptly and process long-running tasks asynchronously
Validate Authentication Verify webhooks using callbackHeaders or callbackSecret to ensure requests are from Narada Cloud
Monitor & Log Maintain comprehensive logs for debugging and monitoring webhook delivery
Secure Your Endpoint Use HTTPS to protect your callbackHeaders, callbackSecret, and webhook data in transit
Next Steps
Production Checklist : Before deploying, ensure you have HTTPS enabled, secret validation implemented, and comprehensive logging.