Skip to main content

Webhooks API

Receive real-time notifications when events occur in your FAOS workspace. Webhooks allow you to build integrations that react to agent actions, workflow executions, and other system events.

Base URL​

https://api.faosx.ai/v1/webhooks

How Webhooks Work​

sequenceDiagram
participant E as FAOS Event
participant S as FAOS Server
participant Y as Your Server

E->>S: Event occurs (e.g., agent completes task)
S->>S: Find subscribed webhooks
S->>Y: POST event payload
Y-->>S: 200 OK
Note over S,Y: Success - event delivered

When an event occurs, FAOS sends an HTTP POST request to your configured endpoint with event details.

Webhook Object​

interface Webhook {
id: string; // Unique identifier (e.g., "hook_abc123")
workspace_id: string; // Parent workspace
url: string; // Destination URL
events: string[]; // Subscribed event types
status: WebhookStatus; // active, paused, failed

// Security
secret: string; // Signing secret for verification

// Configuration
settings: {
retry_policy: RetryPolicy;
timeout_seconds: number;
};

// Metadata
created_at: string;
updated_at: string;
last_triggered_at: string;

// Statistics
stats: {
total_deliveries: number;
success_rate: number;
last_failure_at: string;
};
}

type WebhookStatus = "active" | "paused" | "failed";

interface RetryPolicy {
max_attempts: number;
backoff_multiplier: number;
}

Create Webhook​

Register a new webhook endpoint.

POST /v1/webhooks

Request Body​

{
"url": "https://api.yourdomain.com/webhooks/faos",
"events": [
"agent.execution.completed",
"workflow.execution.completed",
"agent.execution.awaiting_approval"
],
"settings": {
"retry_policy": {
"max_attempts": 3,
"backoff_multiplier": 2
},
"timeout_seconds": 30
}
}

Response​

{
"data": {
"id": "hook_abc123",
"workspace_id": "ws_xyz789",
"url": "https://api.yourdomain.com/webhooks/faos",
"events": [
"agent.execution.completed",
"workflow.execution.completed",
"agent.execution.awaiting_approval"
],
"status": "active",
"secret": "whsec_abc123xyz...",
"settings": {
"retry_policy": {
"max_attempts": 3,
"backoff_multiplier": 2
},
"timeout_seconds": 30
},
"created_at": "2025-12-21T10:00:00Z",
"updated_at": "2025-12-21T10:00:00Z",
"last_triggered_at": null,
"stats": {
"total_deliveries": 0,
"success_rate": 0,
"last_failure_at": null
}
}
}
Secret Protection

Save the secret value immediately. You'll need it to verify webhook signatures. It's only shown once.

Retrieve Webhook​

Get details of a specific webhook.

GET /v1/webhooks/{webhook_id}

Example Request​

curl https://api.faosx.ai/v1/webhooks/hook_abc123 \
-H "Authorization: Bearer sk_live_abc123..."

List Webhooks​

List all webhooks in your workspace.

GET /v1/webhooks

Query Parameters​

ParameterTypeDescription
statusstringFilter by status: active, paused, failed
limitintegerResults per page (default: 20, max: 100)

Example Request​

curl "https://api.faosx.ai/v1/webhooks?status=active" \
-H "Authorization: Bearer sk_live_abc123..."

Update Webhook​

Update an existing webhook.

PATCH /v1/webhooks/{webhook_id}

Request Body​

{
"events": [
"agent.execution.completed",
"workflow.execution.completed",
"workflow.execution.failed"
],
"status": "active"
}

Delete Webhook​

Delete a webhook subscription.

DELETE /v1/webhooks/{webhook_id}

Example Request​

curl -X DELETE https://api.faosx.ai/v1/webhooks/hook_abc123 \
-H "Authorization: Bearer sk_live_abc123..."

Webhook Events​

Agent Events​

EventDescriptionPayload
agent.createdNew agent createdAgent object
agent.updatedAgent configuration changedAgent object
agent.deletedAgent deletedAgent ID
agent.execution.startedAgent begins taskExecution object
agent.execution.completedAgent completes taskExecution object with result
agent.execution.failedAgent task failedExecution object with error
agent.execution.awaiting_approvalAgent needs approval (L2)Execution object

Workflow Events​

EventDescriptionPayload
workflow.createdNew workflow createdWorkflow object
workflow.updatedWorkflow modifiedWorkflow object
workflow.deletedWorkflow deletedWorkflow ID
workflow.execution.startedWorkflow beginsExecution object
workflow.execution.completedWorkflow completesExecution object with result
workflow.execution.failedWorkflow failsExecution object with error
workflow.execution.step_completedStep finishesStep result

Integration Events​

EventDescriptionPayload
integration.connectedNew integration addedIntegration object
integration.disconnectedIntegration removedIntegration ID
integration.errorIntegration failureError details

Event Payload Structure​

All webhook events follow this structure:

{
"id": "evt_abc123",
"type": "agent.execution.completed",
"created_at": "2025-12-21T10:30:00Z",
"workspace_id": "ws_xyz789",

"data": {
// Event-specific data
}
}

Example: Agent Execution Completed​

{
"id": "evt_abc123",
"type": "agent.execution.completed",
"created_at": "2025-12-21T10:30:00Z",
"workspace_id": "ws_xyz789",

"data": {
"execution_id": "exec_abc123",
"agent_id": "agt_def456",
"agent_name": "Customer Support Agent",
"status": "completed",
"result": {
"action": "refund_processing",
"output": "Refund of $45.00 processed successfully",
"confidence": 0.98
},
"execution_time_ms": 342,
"created_at": "2025-12-21T10:29:59Z",
"completed_at": "2025-12-21T10:30:00.342Z"
}
}

Example: Workflow Execution Failed​

{
"id": "evt_def456",
"type": "workflow.execution.failed",
"created_at": "2025-12-21T11:00:00Z",
"workspace_id": "ws_xyz789",

"data": {
"execution_id": "wex_abc123",
"workflow_id": "wfl_xyz789",
"workflow_name": "Customer Onboarding",
"status": "failed",
"failed_step": "step_3",
"error": {
"code": "external_api_error",
"message": "CRM API returned 503",
"details": {
"step_id": "step_3",
"agent_id": "agt_operations"
}
},
"steps_completed": 2,
"steps_total": 5,
"created_at": "2025-12-21T10:55:00Z",
"failed_at": "2025-12-21T11:00:00Z"
}
}

Verifying Webhook Signatures​

FAOS signs all webhook requests so you can verify they're authentic.

Signature Header​

Each webhook request includes a signature in the X-FAOS-Signature header:

X-FAOS-Signature: t=1703168400,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

Format: t=<timestamp>,v1=<signature>

Verification Steps​

  1. Extract timestamp and signature from header
  2. Construct signed payload: {timestamp}.{request_body}
  3. Compute HMAC-SHA256 with your webhook secret
  4. Compare computed signature with received signature
  5. Verify timestamp is recent (within 5 minutes)

Code Examples​

Node.js​

const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
// Parse signature header
const parts = signature.split(',');
const timestamp = parts[0].split('=')[1];
const sig = parts[1].split('=')[1];

// Verify timestamp is recent (5 minutes)
const now = Math.floor(Date.now() / 1000);
if (now - parseInt(timestamp) > 300) {
throw new Error('Webhook timestamp too old');
}

// Compute signature
const signedPayload = `${timestamp}.${payload}`;
const expectedSig = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');

// Compare signatures
if (sig !== expectedSig) {
throw new Error('Invalid signature');
}

return true;
}

// Express.js example
app.post('/webhooks/faos', (req, res) => {
const signature = req.headers['x-faos-signature'];
const payload = JSON.stringify(req.body);
const secret = process.env.FAOS_WEBHOOK_SECRET;

try {
verifyWebhook(payload, signature, secret);

// Process webhook event
const event = req.body;
console.log('Received event:', event.type);

res.sendStatus(200);
} catch (err) {
console.error('Webhook verification failed:', err);
res.sendStatus(400);
}
});

Python​

import hmac
import hashlib
import time

def verify_webhook(payload: str, signature: str, secret: str) -> bool:
# Parse signature header
parts = dict(part.split('=') for part in signature.split(','))
timestamp = parts['t']
sig = parts['v1']

# Verify timestamp is recent (5 minutes)
now = int(time.time())
if now - int(timestamp) > 300:
raise ValueError('Webhook timestamp too old')

# Compute signature
signed_payload = f"{timestamp}.{payload}"
expected_sig = hmac.new(
secret.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()

# Compare signatures
if not hmac.compare_digest(sig, expected_sig):
raise ValueError('Invalid signature')

return True

# Flask example
from flask import Flask, request

app = Flask(__name__)

@app.route('/webhooks/faos', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-FAOS-Signature')
payload = request.get_data(as_text=True)
secret = os.environ['FAOS_WEBHOOK_SECRET']

try:
verify_webhook(payload, signature, secret)

# Process webhook event
event = request.json
print(f"Received event: {event['type']}")

return '', 200
except ValueError as e:
print(f"Webhook verification failed: {e}")
return '', 400

Retry Behavior​

If your endpoint returns a non-2xx status code or times out, FAOS will retry the webhook.

Retry Schedule​

AttemptDelay
1stImmediate
2nd1 minute
3rd5 minutes
4th15 minutes
5th1 hour

After max attempts, the webhook is marked as failed and retries stop.

Idempotency​

Webhooks may be delivered more than once. Use the event id to deduplicate:

const processedEvents = new Set();

app.post('/webhooks/faos', (req, res) => {
const event = req.body;

// Check if already processed
if (processedEvents.has(event.id)) {
console.log('Duplicate event, skipping');
return res.sendStatus(200);
}

// Process event
processEvent(event);

// Mark as processed
processedEvents.add(event.id);

res.sendStatus(200);
});

Testing Webhooks​

Test your webhook endpoint before going live.

Send Test Event​

POST /v1/webhooks/{webhook_id}/test

Request Body​

{
"event_type": "agent.execution.completed"
}

This sends a sample event to your endpoint.

Response​

{
"data": {
"status": "delivered",
"http_status": 200,
"response_time_ms": 145,
"delivered_at": "2025-12-21T10:30:00Z"
}
}

Webhook Deliveries​

View delivery history for a webhook.

GET /v1/webhooks/{webhook_id}/deliveries

Response​

{
"data": [
{
"id": "del_abc123",
"event_id": "evt_abc123",
"event_type": "agent.execution.completed",
"status": "delivered",
"http_status": 200,
"attempts": 1,
"response_time_ms": 145,
"created_at": "2025-12-21T10:30:00Z",
"delivered_at": "2025-12-21T10:30:00.145Z"
},
{
"id": "del_def456",
"event_id": "evt_def456",
"event_type": "workflow.execution.failed",
"status": "failed",
"http_status": 503,
"attempts": 3,
"error": "Connection timeout",
"created_at": "2025-12-21T09:00:00Z",
"last_attempt_at": "2025-12-21T09:15:00Z"
}
],
"has_more": false
}

Best Practices​

Endpoint Implementation​

  1. Respond quickly - Acknowledge receipt with 200 OK immediately
  2. Process async - Queue events for background processing
  3. Handle duplicates - Use event IDs for idempotency
  4. Verify signatures - Always validate webhook authenticity
  5. Log failures - Track and alert on webhook errors

Example: Async Processing​

const queue = require('./queue'); // Your queue system

app.post('/webhooks/faos', async (req, res) => {
const signature = req.headers['x-faos-signature'];
const payload = JSON.stringify(req.body);

try {
// Verify signature
verifyWebhook(payload, signature, process.env.FAOS_WEBHOOK_SECRET);

// Queue for async processing
await queue.add('faos-webhook', req.body);

// Respond immediately
res.sendStatus(200);
} catch (err) {
console.error('Webhook error:', err);
res.sendStatus(400);
}
});

// Background worker
queue.process('faos-webhook', async (job) => {
const event = job.data;

switch (event.type) {
case 'agent.execution.completed':
await handleAgentCompletion(event.data);
break;
case 'workflow.execution.failed':
await handleWorkflowFailure(event.data);
break;
// ... other event types
}
});

Errors​

Common webhook-specific errors:

Error CodeHTTP StatusDescription
webhook_not_found404Webhook ID doesn't exist
invalid_url400Webhook URL is malformed
delivery_failed500All retry attempts failed
invalid_event_type400Unknown event type

See Error Reference for all error codes.

Rate Limits​

EndpointLimit
Create Webhook10/hour
Test Webhook20/hour
All other endpoints60/minute

Webhook deliveries themselves are not rate limited.

Next Steps​