Skip to main content
Callback webhooks allow Agent Loops to send results to external systems when execution completes. Use callbacks to integrate agent workflows with your applications, trigger subsequent actions, or deliver reports.

Overview

A callback is an HTTP POST request sent to your specified endpoint when an Agent Loop finishes:
Agent Loop Executes → Completes Task → Sends POST to Your Webhook
Your webhook receives the agent’s output and can process it however needed.

Configuring Callbacks

1

Create/Edit Agent Loop

Open the agent loop you want to configure.
2

Find Callback Section

Scroll to the Callback Webhook configuration section.
3

Enter Webhook URL

Provide your webhook endpoint:
https://your-domain.com/agent-results
4

Add Headers (Optional)

Include authentication or custom headers:
Authorization: Bearer YOUR_TOKEN
X-Custom-Header: value
5

Save

Click Save to enable callbacks.

Callback Payload

Your webhook receives a POST request with this JSON structure:
{
  "agent_loop_id": "loop_abc123",
  "agent_loop_name": "Daily Sales Report",
  "execution_id": "exec_xyz789",
  "status": "completed",
  "result": {
    "output": "Sales Report for January 15, 2024\n\nTotal Revenue: $12,450...",
    "iterations_used": 5,
    "tool_calls": 3
  },
  "metadata": {
    "started_at": "2024-01-15T10:00:00Z",
    "completed_at": "2024-01-15T10:02:30Z",
    "duration_seconds": 150,
    "model": "gpt-4",
    "tokens_used": 1250
  },
  "error": null
}

Payload Fields

FieldTypeDescription
agent_loop_idstringUnique agent loop identifier
agent_loop_namestringDisplay name of the agent loop
execution_idstringUnique execution identifier
statusstringcompleted, failed, or timeout
result.outputstringThe agent’s final response
result.iterations_usednumberReasoning steps taken
result.tool_callsnumberTools used during execution
metadataobjectExecution timing and stats
errorstring/nullError message if failed

Status Values

completed: Agent successfully finished the task
{
  "status": "completed",
  "result": { "output": "..." },
  "error": null
}
failed: Agent encountered an error
{
  "status": "failed",
  "result": null,
  "error": "Tool call failed: HTTP 500 from API"
}
timeout: Execution exceeded time limit
{
  "status": "timeout",
  "result": { "output": "Partial result..." },
  "error": "Execution timeout after 300 seconds"
}

Implementing a Callback Webhook

Example: Node.js/Express

const express = require('express');
const app = express();
app.use(express.json());

app.post('/agent-results', (req, res) => {
  const {
    agent_loop_id,
    agent_loop_name,
    status,
    result,
    error
  } = req.body;

  console.log(`Agent Loop "${agent_loop_name}" ${status}`);

  if (status === 'completed') {
    // Process successful result
    const output = result.output;

    // Example: Send to Slack
    sendToSlack({
      text: `Agent Report:\n\n${output}`
    });

    // Example: Save to database
    database.saveReport({
      agent_loop_id,
      output,
      created_at: new Date()
    });

  } else if (status === 'failed') {
    // Handle error
    console.error(`Agent failed: ${error}`);

    // Send alert
    sendAlert({
      title: 'Agent Loop Failed',
      message: error
    });
  }

  // Acknowledge receipt
  res.json({ received: true });
});

app.listen(3000);

Example: Python/Flask

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

@app.route('/agent-results', methods=['POST'])
def agent_callback():
    data = request.json

    agent_name = data['agent_loop_name']
    status = data['status']

    if status == 'completed':
        output = data['result']['output']

        # Send to Slack
        slack_webhook_url = 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL'
        requests.post(slack_webhook_url, json={
            'text': f'Agent Report from {agent_name}:\n\n{output}'
        })

        # Log to file
        with open('agent_reports.txt', 'a') as f:
            f.write(f'\n\n=== {agent_name} ===\n{output}\n')

    elif status == 'failed':
        error = data['error']
        print(f'Agent {agent_name} failed: {error}')

    return jsonify({'received': True})

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

Response Expected

Your webhook should return a JSON response with HTTP 200 status:
{
  "received": true
}
Optional fields:
{
  "received": true,
  "processed": true,
  "message": "Report saved successfully"
}
If your webhook returns an error status (4xx or 5xx), the callback will be retried (coming soon).

Use Cases

Send to Messaging Platforms

Forward agent results to Slack, Teams, or Discord:
async function sendToSlack(output) {
  await fetch(process.env.SLACK_WEBHOOK_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      text: output,
      username: 'Agent Bot',
      icon_emoji: ':robot_face:'
    })
  });
}

Save to Database

Store results for historical tracking:
async function saveToDatabase(data) {
  await db.agentResults.insert({
    agent_loop_id: data.agent_loop_id,
    execution_id: data.execution_id,
    output: data.result.output,
    status: data.status,
    created_at: new Date(data.metadata.completed_at)
  });
}

Trigger Workflows

Start additional workflows based on results:
if (result.output.includes('ERROR')) {
  // Trigger incident response
  await createIncident({
    title: 'Agent Loop Error Detected',
    description: result.output
  });
}

Send Emails

Email reports to stakeholders:
if (status === 'completed') {
  await sendEmail({
    to: 'team@company.com',
    subject: `Daily Report from ${agent_loop_name}`,
    body: result.output
  });
}

Security

Use HTTPS

Always use HTTPS endpoints for callbacks

Authenticate Requests

Verify requests come from Chatbot Platform

Validate Payload

Check payload structure before processing

Rate Limiting

Implement rate limits on your endpoint

Authenticating Callbacks

Add a secret token to callback headers: Agent Loop Configuration:
Callback URL: https://your-domain.com/agent-results
Headers:
  X-Webhook-Secret: your-secret-token-here
Your Webhook:
app.post('/agent-results', (req, res) => {
  const secret = req.headers['x-webhook-secret'];

  if (secret !== process.env.WEBHOOK_SECRET) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  // Process callback...
});

Request Signature (Coming Soon)

Future support for HMAC-SHA256 signature verification:
X-Signature: sha256=abc123...
Your webhook would verify the signature matches the payload.

Testing Callbacks

Manual Testing

Use a service like webhook.site:
1

Create Test Endpoint

Go to webhook.site and copy your unique URL.
2

Configure Agent Loop

Set the webhook.site URL as your callback URL.
3

Run Agent Loop

Execute the agent loop manually.
4

View Request

Check webhook.site to see the callback payload.

Local Testing with Ngrok

Test with your local development server:
1

Start Ngrok

ngrok http 3000
2

Use Ngrok URL

Configure agent loop with the ngrok URL:
https://abc123.ngrok.io/agent-results
3

Run Agent

Execute and receive callback on your local server.

Troubleshooting

Callback Not Received

Check:
  • Callback URL is correct and accessible
  • Your endpoint is running
  • Firewall allows incoming requests
  • Agent loop completed successfully

Callback Failed

Check:
  • Endpoint returns 200 status
  • Response is valid JSON
  • No timeout on your endpoint
  • Check execution logs for details

Duplicate Callbacks

If you receive multiple callbacks:
  • Check for retry logic (future feature)
  • Verify webhook is not called multiple times in your code
  • Use execution_id to deduplicate

Best Practices

Always respond with HTTP 200 status quickly. Process the callback data asynchronously if it takes time.
Do:
  • Return 200 immediately
  • Process data in background jobs
  • Log all callbacks for debugging
  • Validate payload structure
  • Handle errors gracefully
Don’t:
  • Perform long operations synchronously
  • Return errors for non-critical issues
  • Skip authentication
  • Assume payload structure won’t change

Async Processing Pattern

app.post('/agent-results', async (req, res) => {
  const data = req.body;

  // Immediately acknowledge
  res.json({ received: true });

  // Process asynchronously
  processCallback(data).catch(err => {
    console.error('Callback processing failed:', err);
  });
});

async function processCallback(data) {
  // Long-running operations here
  await saveToDatabase(data);
  await sendNotifications(data);
  await triggerWorkflows(data);
}

Next Steps

Getting Started

Create your first agent loop

MCP Servers

Add tools to your agents