Overview
Webhooks enable your application to receive real-time notifications when tasks complete. Instead of polling for results, configure a webhook endpoint to receive data automatically when the AI agent finishes its work.
Use cases:
Automated data pipelines that trigger on task completion
Real-time notifications to downstream systems
Integration with third-party services and APIs
Event-driven architectures without polling overhead
Configuration
Add a webhook object to your session or task request to enable webhook notifications.
Webhook Parameters
Parameter Type Required Description namestringYes Identifier for this webhook (useful for logging) urlstringYes HTTPS endpoint URL to receive the webhook authstringNo Authorization header value sent with the request submittedDatastringYes Specifies what data to include in the payload
submittedData Options
Value Description Best For "ai_response"The response from the AI (text, structured_json, or structured_csv) — only the results/output from the LLM Production data pipelines "full_response"Full body response that includes the usage info Debugging, audit logging "just_ping"Just a ping notification, no data payload Triggering external workflows
Basic Example
const session = await fetch ( "https://connect.webrun.ai/start/start-session" , {
method: "POST" ,
headers: {
"Content-Type" : "application/json" ,
"Authorization" : `Bearer ${ API_KEY } `
},
body: JSON . stringify ({
mode: "default" ,
initialTask: {
taskDetails: "Extract the main headline from the page" ,
startingPoint: "https://news.ycombinator.com" ,
webhook: {
name: "HN Headlines" ,
url: "https://api.yoursite.com/webhooks/headlines" ,
auth: "Bearer your-secret-token" ,
submittedData: "full_response"
}
}
})
}). then ( r => r . json ());
With Structured Output
Combine webhooks with structured output for validated JSON delivered directly to your endpoint.
const session = await fetch ( "https://connect.webrun.ai/start/start-session" , {
method: "POST" ,
headers: {
"Content-Type" : "application/json" ,
"Authorization" : `Bearer ${ API_KEY } `
},
body: JSON . stringify ({
mode: "default" ,
initialTask: {
taskDetails: "Extract product information from the page" ,
startingPoint: "https://example.com/product" ,
maxDuration: 300000 ,
outputType: "structured_json" ,
outputSchema: {
type: "object" ,
properties: {
title: { type: "string" },
price: { type: "number" },
inStock: { type: "boolean" },
description: { type: "string" }
},
required: [ "title" , "price" ],
additionalProperties: false
},
webhook: {
name: "Product Webhook" ,
url: "https://api.mysite.com/products" ,
auth: "Bearer token123" ,
submittedData: "ai_response"
}
}
})
}). then ( r => r . json ());
Use submittedData: "ai_response" to receive only the AI’s output (text, structured_json, or structured_csv), reducing payload size and simplifying your webhook handler.
Webhook Payload
The payload sent to your endpoint depends on the submittedData setting.
full_response Payload
{
"type" : "task_completed" ,
"sessionId" : "sess_abc123" ,
"taskId" : "task_xyz789" ,
"data" : {
"message" : "{ \" title \" : \" Product Name \" , \" price \" :29.99}" ,
"prompt_tokens" : 8500 ,
"completion_tokens" : 2300 ,
"total_tokens" : 10800 ,
"completion_time" : 12.5
},
"usage" : {
"inputTokens" : 8500 ,
"outputTokens" : 2300 ,
"computeTime" : 12.5 ,
"cost" : 0.0124
},
"completedAt" : "2024-01-15T10:30:00.000Z"
}
ai_response Payload
{
"title" : "Product Name" ,
"price" : 29.99 ,
"inStock" : true ,
"description" : "A great product"
}
just_ping Payload
{
"event" : "task_completed" ,
"sessionId" : "sess_abc123" ,
"taskId" : "task_xyz789" ,
"completedAt" : "2024-01-15T10:30:00.000Z"
}
Receiving Webhooks
Your webhook endpoint should:
Accept POST requests with JSON body
Return a 2xx status code to acknowledge receipt
Process the webhook asynchronously if needed
Example Webhook Handler (Node.js/Express)
const express = require ( 'express' );
const app = express ();
app . use ( express . json ());
app . post ( '/webhooks/products' , ( req , res ) => {
// Verify authorization (recommended)
const authHeader = req . headers [ 'authorization' ];
if ( authHeader !== 'Bearer your-secret-token' ) {
return res . status ( 401 ). json ({ error: 'Unauthorized' });
}
// Process the webhook payload
const productData = req . body ;
console . log ( 'Received product data:' , productData );
// Store in database, trigger workflows, etc.
saveToDatabase ( productData );
// Acknowledge receipt
res . status ( 200 ). json ({ received: true });
});
app . listen ( 3000 );
Example Webhook Handler (Python/Flask)
from flask import Flask, request, jsonify
app = Flask( __name__ )
@app.route ( '/webhooks/products' , methods = [ 'POST' ])
def receive_webhook ():
# Verify authorization (recommended)
auth_header = request.headers.get( 'Authorization' )
if auth_header != 'Bearer your-secret-token' :
return jsonify({ 'error' : 'Unauthorized' }), 401
# Process the webhook payload
product_data = request.json
print ( 'Received product data:' , product_data)
# Store in database, trigger workflows, etc.
save_to_database(product_data)
# Acknowledge receipt
return jsonify({ 'received' : True }), 200
if __name__ == '__main__' :
app.run( port = 3000 )
Security Best Practices
1. Use HTTPS
Always use HTTPS endpoints for webhooks to encrypt data in transit.
{
"webhook" : {
"url" : "https://api.yoursite.com/webhooks/data"
}
}
2. Verify Authorization
Include an auth token and verify it in your webhook handler.
{
"webhook" : {
"auth" : "Bearer your-secret-token"
}
}
3. Validate Payload Structure
Validate incoming data matches your expected schema before processing.
const { z } = require ( 'zod' );
const ProductSchema = z . object ({
title: z . string (),
price: z . number (),
inStock: z . boolean (). optional ()
});
app . post ( '/webhooks/products' , ( req , res ) => {
try {
const validated = ProductSchema . parse ( req . body );
processProduct ( validated );
res . status ( 200 ). json ({ received: true });
} catch ( error ) {
console . error ( 'Invalid payload:' , error );
res . status ( 400 ). json ({ error: 'Invalid payload' });
}
});
4. Use Unique Tokens Per Webhook
Generate unique tokens for different webhook endpoints to limit exposure if one is compromised.
Error Handling
If your webhook endpoint fails to respond or returns an error, the webhook delivery will not be retried. Ensure your endpoint is reliable and returns quickly.
Webhook deliveries are not retried on failure. Design your endpoint to be highly available and respond within 30 seconds.
Recommended Approach
Acknowledge receipt immediately with a 200 status
Process the data asynchronously
Implement your own retry logic if needed
app . post ( '/webhooks/products' , async ( req , res ) => {
// Acknowledge immediately
res . status ( 200 ). json ({ received: true });
// Process asynchronously
try {
await processProductAsync ( req . body );
} catch ( error ) {
console . error ( 'Processing failed:' , error );
// Queue for retry in your own system
await queueForRetry ( req . body );
}
});
Use Cases
Data Pipeline Automation
Automatically ingest extracted data into your database or data warehouse.
{
taskDetails : "Extract all product listings from the category page" ,
outputType : "structured" ,
outputSchema : {
type : "object" ,
properties : {
products : {
type : "array" ,
items : {
type : "object" ,
properties : {
sku : { type : "string" },
name : { type : "string" },
price : { type : "number" }
}
}
}
}
},
webhook : {
name : "Product Ingestion" ,
url : "https://api.yoursite.com/ingest/products" ,
auth : "Bearer ingestion-token" ,
submittedData : "ai_response"
}
}
Notification Systems
Trigger alerts or notifications when tasks complete.
{
taskDetails : "Monitor the page for price changes" ,
webhook : {
name : "Price Alert" ,
url : "https://api.yoursite.com/alerts/price-change" ,
auth : "Bearer alert-token" ,
submittedData : "just_ping"
}
}
Third-Party Integrations
Send data directly to external services like Zapier, Make, or n8n.
{
taskDetails : "Extract contact information from the page" ,
outputType : "structured" ,
outputSchema : {
type : "object" ,
properties : {
name : { type : "string" },
email : { type : "string" },
phone : { type : "string" }
}
},
webhook : {
name : "Zapier Integration" ,
url : "https://hooks.zapier.com/hooks/catch/123456/abcdef" ,
submittedData : "ai_response"
}
}