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
}
}
}
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β
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: active, paused, failed |
limit | integer | Results 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β
| Event | Description | Payload |
|---|---|---|
agent.created | New agent created | Agent object |
agent.updated | Agent configuration changed | Agent object |
agent.deleted | Agent deleted | Agent ID |
agent.execution.started | Agent begins task | Execution object |
agent.execution.completed | Agent completes task | Execution object with result |
agent.execution.failed | Agent task failed | Execution object with error |
agent.execution.awaiting_approval | Agent needs approval (L2) | Execution object |
Workflow Eventsβ
| Event | Description | Payload |
|---|---|---|
workflow.created | New workflow created | Workflow object |
workflow.updated | Workflow modified | Workflow object |
workflow.deleted | Workflow deleted | Workflow ID |
workflow.execution.started | Workflow begins | Execution object |
workflow.execution.completed | Workflow completes | Execution object with result |
workflow.execution.failed | Workflow fails | Execution object with error |
workflow.execution.step_completed | Step finishes | Step result |
Integration Eventsβ
| Event | Description | Payload |
|---|---|---|
integration.connected | New integration added | Integration object |
integration.disconnected | Integration removed | Integration ID |
integration.error | Integration failure | Error 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β
- Extract timestamp and signature from header
- Construct signed payload:
{timestamp}.{request_body} - Compute HMAC-SHA256 with your webhook secret
- Compare computed signature with received signature
- 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β
| Attempt | Delay |
|---|---|
| 1st | Immediate |
| 2nd | 1 minute |
| 3rd | 5 minutes |
| 4th | 15 minutes |
| 5th | 1 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β
- Respond quickly - Acknowledge receipt with 200 OK immediately
- Process async - Queue events for background processing
- Handle duplicates - Use event IDs for idempotency
- Verify signatures - Always validate webhook authenticity
- 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 Code | HTTP Status | Description |
|---|---|---|
webhook_not_found | 404 | Webhook ID doesn't exist |
invalid_url | 400 | Webhook URL is malformed |
delivery_failed | 500 | All retry attempts failed |
invalid_event_type | 400 | Unknown event type |
See Error Reference for all error codes.
Rate Limitsβ
| Endpoint | Limit |
|---|---|
| Create Webhook | 10/hour |
| Test Webhook | 20/hour |
| All other endpoints | 60/minute |
Webhook deliveries themselves are not rate limited.
Next Stepsβ
- Agents API - Manage AI agents
- Workflows API - Automate processes
- Error Reference - Complete error documentation