Chuyển tới nội dung chính

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