Skip to main content

What is the Webhook Approval Step?

The Webhook Approval Step enables you to pause your agent’s execution and wait for approval from an external system before continuing. This is perfect for workflows that require human review, compliance checks, or integration with your existing approval processes.

Common Use Cases

  • Financial Approvals: Pause before processing transactions above a certain threshold
  • Compliance Reviews: Get legal team approval before sending sensitive communications
  • Quality Gates: Integrate with your CI/CD pipeline for deployment approvals
  • Customer Onboarding: Route high-value leads through your CRM approval workflow
  • IT Operations: Require manager approval before executing infrastructure changes

How It Works

Agent Execution → Reaches Approval Step → Sends Webhook → External System → Approval/Denial → Agent Continues
  1. Agent pauses: When the agent reaches this step, execution pauses automatically
  2. Webhook sent: Airia sends a POST request to your configured URL with execution details
  3. You decide: Your system receives the request and applies your business logic
  4. Send response: Your system calls back to Airia with “Approved” or “Denied”
  5. Agent continues: Based on your decision, the agent follows the appropriate path

Configuration Guide

1. Webhook URL

What it is: The endpoint where Airia will send approval requests. Requirements:
  • Must be a publicly accessible HTTPS URL
  • Must accept POST requests
  • Must return a 2xx status code to confirm receipt
Examples:
✅ https://api.yourcompany.com/airia/approve
✅ https://approvals.yourcompany.com/webhook
✅ https://your-app.herokuapp.com/webhook/airia

❌ http://localhost:3000/approve (not public)
❌ http://api.yourcompany.com/approve (not HTTPS)
Tips:
  • Use a dedicated endpoint for Airia approvals
  • Ensure the URL is stable and won’t change
  • Test accessibility from external networks
  • For development, use tools like ngrok to expose local servers

2. Authentication

What it is: Security method to verify requests are coming from Airia. Options:

None

No authentication required. Only use for internal testing.

API Key

Airia will include your API key in the X-API-Key header. When to use: Simple authentication for internal systems. Configuration:
{
  "authenticationType": "ApiKey",
  "authenticationConfig": {
    "apiKey": "your-secret-key-here"
  }
}
Your endpoint should verify:
if request.headers.get('X-API-Key') != 'your-secret-key-here':
    return 401

Bearer Token

Airia will include your token in the Authorization: Bearer header. When to use: Standard OAuth-style authentication. Configuration:
{
  "authenticationType": "BearerToken",
  "authenticationConfig": {
    "token": "your-bearer-token"
  }
}

Basic Auth

Airia will include username and password in the Authorization: Basic header. When to use: Legacy systems requiring basic authentication. Configuration:
{
  "authenticationType": "BasicAuth",
  "authenticationConfig": {
    "username": "your-username",
    "password": "your-password"
  }
}

Custom Header

Airia will include a custom header with your specified name and value. When to use: Your system uses non-standard authentication headers. Configuration:
{
  "authenticationType": "CustomHeader",
  "authenticationConfig": {
    "headerName": "X-Custom-Auth",
    "headerValue": "your-custom-value"
  }
}
🔒 Security Tip: Always use authentication in production environments.

3. Advanced Settings

Timeout (seconds)

Default: 300 (5 minutes) What it is: Maximum time Airia will wait for your endpoint to respond. Recommendations:
  • Fast APIs: 30-60 seconds
  • Standard processing: 300 seconds (default)
  • Complex workflows: 600 seconds (10 minutes)
Important: This is just for the initial webhook delivery, not the approval decision. Your system can take as long as needed to send the approval/denial callback.

Max Retry Attempts

Default: 3 What it is: How many times Airia will retry if your endpoint is unavailable. How it works:
  • Retry 1: After 2 seconds
  • Retry 2: After 4 seconds
  • Retry 3: After 8 seconds
  • (Exponential backoff)
Recommendations:
  • Reliable endpoints: 1-2 retries
  • Less reliable: 3-5 retries
  • Development/testing: 1 retry
Cost consideration: Each retry counts as a separate request, so set appropriately based on your endpoint reliability.

4. Message

What it is: Optional custom message included in the webhook payload to provide context. Examples:
"Please review this high-value customer onboarding request"
"Approval required: Transaction amount exceeds $10,000"
"Compliance review needed before sending communication"
"Manager approval required for infrastructure change"
Tips:
  • Keep it concise (under 500 characters recommended)
  • Include context that helps the approver make a decision
  • Use dynamic variables if your system supports them
  • Can be left blank if your webhook URL is specific enough

Setting Up Your Webhook Endpoint

What You’ll Receive

When your agent reaches the Webhook Approval step, Airia will POST this to your endpoint:
{
  "agentExecutionWebhookApprovalId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "executionId": "7b8c9d10-1234-5678-9abc-def012345678",
  "agentId": "a1b2c3d4-5678-90ef-1234-567890abcdef",
  "agentName": "Customer Onboarding Agent",
  "projectId": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
  "message": "Please review this high-value customer",
  "stepInput": "Customer: Acme Corp, Value: $50,000",
  "previousResults": {
    "step-1": { "Value": "Credit check passed" },
    "step-2": { "Value": "Documents verified" }
  },
  "callbackId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "callbackToken": "abc123xyz789..."
}
Key Fields:
  • callbackId: Unique ID for this approval (you’ll need this to respond)
  • callbackToken: Security token (REQUIRED to respond - store this securely!)
  • agentName: Name of the agent requesting approval
  • message: Your custom message from configuration
  • stepInput: Data passed into this step
  • previousResults: Results from all previous steps in the workflow

How to Respond

Your system must call this endpoint to approve or deny: Endpoint: POST https://api.airia.com/v1/AgentExecutionWebhookApproval/callback Request Body:
{
  "callbackId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "callbackToken": "abc123xyz789...",
  "status": "Approved",
  "comment": "Approved by John Doe - All checks passed"
}
Required Fields:
  • callbackId: From the webhook you received
  • callbackToken: From the webhook you received (MUST match exactly)
  • status: Must be exactly "Approved" or "Denied" (case-sensitive)
Optional Fields:
  • comment: Explanation for the decision (visible in execution logs)

Quick Start Examples

Example 1: Simple Python Webhook

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

# Store these securely in production
PENDING_APPROVALS = {}

@app.route('/webhook/approve', methods=['POST'])
def receive_approval_request():
    """Receive approval request from Airia"""
    data = request.json

    # Validate authentication (if configured)
    if request.headers.get('X-API-Key') != 'your-secret-key':
        return jsonify({'error': 'Unauthorized'}), 401

    # Store the approval for processing
    approval_id = data['callbackId']
    PENDING_APPROVALS[approval_id] = {
        'token': data['callbackToken'],
        'agent': data['agentName'],
        'message': data['message'],
        'input': data['stepInput']
    }

    print(f"Received approval request: {data['message']}")

    # Return 200 immediately - process asynchronously
    return jsonify({'received': True}), 200

def approve_request(approval_id, approved, comment):
    """Send approval decision back to Airia"""
    approval = PENDING_APPROVALS.get(approval_id)
    if not approval:
        print(f"Approval {approval_id} not found")
        return

    callback_url = "https://api.airia.com/v1/AgentExecutionWebhookApproval/callback"

    response = requests.post(callback_url, json={
        'callbackId': approval_id,
        'callbackToken': approval['token'],
        'status': 'Approved' if approved else 'Denied',
        'comment': comment
    })

    if response.status_code == 200:
        print(f"Successfully sent approval decision: {approved}")
        del PENDING_APPROVALS[approval_id]
    else:
        print(f"Failed to send approval: {response.text}")

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)