Skip to main content

Webhooks

Receive real-time notifications when events occur in Ascend.

Overview

Webhooks allow your application to receive HTTP POST requests when specific events occur, enabling real-time integrations without polling.

Configuring Webhooks

Via Dashboard

  1. Navigate to SettingsWebhooks
  2. Click Add Webhook
  3. Enter your endpoint URL
  4. Select events to subscribe to
  5. Copy and store the signing secret

Via API

curl -X POST https://pilot.owkai.app/api/api/webhooks \
-H "Authorization: Bearer ask_live_xxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/ascend",
"events": ["action.approved", "action.blocked"],
"secret": "whsec_your_secret"
}'

Webhook Payload

All webhooks follow this structure:

{
"id": "evt_abc123",
"type": "action.approved",
"created_at": "2025-01-15T10:30:00Z",
"data": {
"action_id": "act_xyz789",
"agent_id": "my-agent",
"status": "approved",
"risk_score": 25
}
}

Event Types

Action Events

EventDescription
action.submittedAction submitted
action.approvedAction approved
action.deniedAction denied
action.blockedAction blocked by policy
action.escalatedAction escalated
action.timeoutApproval timed out

Workflow Events

EventDescription
workflow.startedWorkflow initiated
workflow.completedWorkflow finished
workflow.escalatedWorkflow escalated

Security Events

EventDescription
security.high_riskHigh risk action detected
security.anomalyAnomaly detected

Verifying Signatures

Webhooks are signed using HMAC-SHA256. Always verify the signature.

Node.js

import crypto from 'crypto';

function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');

return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expected}`)
);
}

// Express middleware
app.post('/webhooks/ascend', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-ascend-signature'];
const payload = req.body.toString();

if (!verifyWebhook(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}

const event = JSON.parse(payload);
console.log(`Event: ${event.type}`);

res.status(200).send('OK');
});

Python

import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()

return hmac.compare_digest(signature, f"sha256={expected}")

# Flask example
@app.route('/webhooks/ascend', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Ascend-Signature')
payload = request.get_data()

if not verify_webhook(payload, signature, WEBHOOK_SECRET):
return 'Invalid signature', 401

event = request.get_json()
print(f"Event: {event['type']}")

return 'OK', 200

Headers

Each webhook request includes:

HeaderDescription
X-Ascend-SignatureHMAC-SHA256 signature
X-Ascend-EventEvent type
X-Ascend-DeliveryUnique delivery ID
X-Ascend-TimestampUnix timestamp

Retry Policy

Webhooks are retried on failure:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours

After 5 failed attempts, the webhook is marked as failed.

Best Practices

1. Respond Quickly

Return 200 within 30 seconds. Process async if needed:

app.post('/webhooks/ascend', (req, res) => {
// Acknowledge immediately
res.status(200).send('OK');

// Process async
processWebhookAsync(req.body);
});

2. Handle Duplicates

Events may be delivered multiple times. Use id for deduplication:

const processedEvents = new Set();

function handleEvent(event) {
if (processedEvents.has(event.id)) {
return; // Already processed
}

processedEvents.add(event.id);
// Process event...
}

3. Verify Signatures

Always verify webhook signatures in production.

Testing Webhooks

Send Test Event

curl -X POST https://pilot.owkai.app/api/api/webhooks/{webhook_id}/test \
-H "Authorization: Bearer ask_live_xxxx"

Local Development

Use tools like ngrok for local testing:

ngrok http 3000
# Use the ngrok URL as your webhook endpoint

Next Steps