Webhooks allow you to receive real-time notifications when events occur in Airweave. Instead of polling the API, register an endpoint and Airweave will push updates to you the moment they happen.
Beta Feature The Webhooks API is currently in beta. The API is stable but may receive enhancements based on feedback.
Overview
Webhooks are HTTP POST requests sent to your server when specific events occur:
Sync jobs completing or failing
Source connections being created, authenticated, or deleted
Collections being created, updated, or deleted
This enables reactive integrations: trigger workflows, update dashboards, send alerts, or sync state with external systems automatically.
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Airweave │ ──── │ Svix │ ──── │ Your Server │
│ (Events) │ │ (Delivery) │ │ (Webhook) │
└─────────────┘ └─────────────┘ └─────────────┘
Airweave uses Svix for webhook delivery, which provides:
Automatic retries with exponential backoff
Cryptographic signature verification
Delivery guarantees and observability
Available Event Types
Sync Events
Event Description When it fires sync.pendingSync job queued Job created and waiting to start sync.runningSync job started Job begins processing sync.completedSync finished successfully All data synced without errors sync.failedSync job failed Job encountered an error sync.cancelledSync job cancelled Job was manually cancelled
Source Connection Events
Event Description When it fires source_connection.createdConnection created New source connection added source_connection.auth_completedOAuth completed Connection authenticated source_connection.deletedConnection removed Connection and data deleted
Collection Events
Event Description When it fires collection.createdCollection created New collection set up collection.updatedCollection modified Name or config changed collection.deletedCollection removed Collection and data deleted
Most integrations only need sync.completed and sync.failed. Subscribe to other events if you need to track infrastructure changes or audit activities.
Creating a Subscription
Create a webhook subscription to start receiving events.
Prepare your endpoint
Set up an HTTPS endpoint that accepts POST requests and returns a 200 status code. Use ngrok or similar tools for local development.
Create subscription
Use the API to register your endpoint and choose which events to receive.
Verify signatures
Validate webhook signatures to ensure requests are from Airweave.
from airweave import AirweaveSDK
client = AirweaveSDK( api_key = "YOUR_API_KEY" )
# Create webhook subscription
subscription = client.webhooks.create_subscription(
url = "https://api.mycompany.com/webhooks/airweave" ,
event_types = [ "sync.completed" , "sync.failed" ]
)
print ( f "Subscription ID: { subscription.id } " )
print ( f "URL: { subscription.url } " )
print ( f "Events: { subscription.filter_types } " )
# Save the signing secret for signature verification
detail = client.webhooks.get_subscription(
subscription_id = subscription.id,
include_secret = True
)
signing_secret = detail.secret
print ( f "Secret: { signing_secret } " )
# Store this securely! You'll need it to verify signatures.
Request Parameters
HTTPS URL where webhook events will be delivered. Must be publicly accessible and return a 2xx status code. Example: "https://api.mycompany.com/webhooks/airweave"
List of event types to subscribe to. Events not in this list won’t be delivered. Available: sync.pending, sync.running, sync.completed, sync.failed, sync.cancelled, source_connection.created, source_connection.auth_completed, source_connection.deleted, collection.created, collection.updated, collection.deleted Example: ["sync.completed", "sync.failed"]
Optional custom signing secret (min 24 characters). If not provided, a secure secret will be auto-generated. Example: "whsec_C2FVsBQIhrscChlQIMV10R9X4jZ8"
Webhook Payloads
sync.completed
Fired when a sync job finishes successfully:
{
"event_type" : "sync.completed" ,
"sync_id" : "440e8400-e29b-41d4-a716-446655440099" ,
"sync_job_id" : "550e8400-e29b-41d4-a716-446655440000" ,
"collection_id" : "770e8400-e29b-41d4-a716-446655440002" ,
"collection_readable_id" : "sales-data-ab123" ,
"collection_name" : "Sales Data" ,
"source_connection_id" : "660e8400-e29b-41d4-a716-446655440001" ,
"source_type" : "salesforce" ,
"entities_inserted" : 42 ,
"entities_updated" : 10 ,
"entities_deleted" : 3 ,
"entities_skipped" : 120 ,
"chunks_written" : 215 ,
"timestamp" : "2025-01-15T14:30:00Z"
}
Unique identifier for this specific sync job run
Human-readable collection ID (e.g., "sales-data-ab123")
Source connector type (e.g., "salesforce", "github", "notion")
Number of new entities added
Number of existing entities updated
Number of entities removed
Number of chunks written to vector database
sync.failed
Fired when a sync job encounters an error:
{
"event_type" : "sync.failed" ,
"sync_id" : "440e8400-e29b-41d4-a716-446655440099" ,
"sync_job_id" : "550e8400-e29b-41d4-a716-446655440000" ,
"collection_id" : "770e8400-e29b-41d4-a716-446655440002" ,
"collection_readable_id" : "sales-data-ab123" ,
"collection_name" : "Sales Data" ,
"source_connection_id" : "660e8400-e29b-41d4-a716-446655440001" ,
"source_type" : "salesforce" ,
"error" : "Authentication token expired" ,
"timestamp" : "2025-01-15T14:02:30Z"
}
source_connection.created
Fired when a new source connection is added:
{
"event_type" : "source_connection.created" ,
"source_connection_id" : "660e8400-e29b-41d4-a716-446655440001" ,
"collection_readable_id" : "finance-data-ab123" ,
"source_type" : "notion" ,
"is_authenticated" : false ,
"timestamp" : "2025-01-15T13:55:00Z"
}
collection.created
Fired when a new collection is created:
{
"event_type" : "collection.created" ,
"collection_id" : "770e8400-e29b-41d4-a716-446655440002" ,
"collection_readable_id" : "customer-support-x7k9m" ,
"collection_name" : "Customer Support" ,
"timestamp" : "2025-01-15T10:00:00Z"
}
Verifying Signatures
Every webhook delivery includes signature headers for verification. Always verify signatures to ensure requests are from Airweave.
POST /webhooks/airweave HTTP / 1.1
Host : your-server.com
Content-Type : application/json
svix-id : msg_2xKvB8LPqM4nRst
svix-timestamp : 1705329000
svix-signature : v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=
Unique message identifier
Unix timestamp when the message was sent
Space-separated list of signatures (format: v1,<base64-signature>)
Verification Example
Python
TypeScript
Install Svix SDK
import hmac
import hashlib
import base64
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
SIGNING_SECRET = "whsec_C2FVsBQIhrscChlQIMV10R9X4jZ8" # From subscription
def verify_signature ( payload : bytes , headers : dict ) -> bool :
"""Verify Svix webhook signature."""
msg_id = headers.get( "svix-id" )
timestamp = headers.get( "svix-timestamp" )
signatures = headers.get( "svix-signature" , "" )
if not msg_id or not timestamp or not signatures:
return False
# Decode the secret (remove 'whsec_' prefix)
secret = SIGNING_SECRET
if secret.startswith( "whsec_" ):
secret = secret[ 6 :]
secret_bytes = base64.b64decode(secret)
# Construct signed content
signed_content = f " { msg_id } . { timestamp } . { payload.decode( 'utf-8' ) } "
# Compute expected signature
expected = hmac.new(
secret_bytes,
signed_content.encode( 'utf-8' ),
hashlib.sha256
).digest()
expected_b64 = base64.b64encode(expected).decode( 'utf-8' )
# Compare with provided signatures
for sig in signatures.split( " " ):
parts = sig.split( "," , 1 )
if len (parts) == 2 and parts[ 0 ] == "v1" :
if hmac.compare_digest(expected_b64, parts[ 1 ]):
return True
return False
@app.post ( "/webhooks/airweave" )
async def receive_webhook ( request : Request):
payload = await request.body()
headers = dict (request.headers)
# Verify signature
if not verify_signature(payload, headers):
raise HTTPException( status_code = 401 , detail = "Invalid signature" )
# Parse event
event = await request.json()
event_type = event.get( "event_type" )
if event_type == "sync.completed" :
print ( f "Sync completed: { event[ 'collection_name' ] } " )
print ( f " Inserted: { event[ 'entities_inserted' ] } " )
print ( f " Updated: { event[ 'entities_updated' ] } " )
# Trigger your workflow here
elif event_type == "sync.failed" :
print ( f "Sync failed: { event[ 'collection_name' ] } " )
print ( f " Error: { event[ 'error' ] } " )
# Send alert
return { "status" : "ok" }
Always verify signatures before processing webhook payloads. This prevents attackers from sending forged requests to your endpoint.
Managing Subscriptions
List Subscriptions
subscriptions = client.webhooks.list_subscriptions()
for sub in subscriptions:
print ( f "ID: { sub.id } " )
print ( f "URL: { sub.url } " )
print ( f "Events: { sub.filter_types } " )
print ( f "Status: { 'Disabled' if sub.disabled else 'Active' } " )
print ( f "Health: { sub.health_status } " )
print ()
Update Subscription
# Change URL
updated = client.webhooks.update_subscription(
subscription_id = "c3d4e5f6-a7b8-9012-cdef-345678901234" ,
url = "https://api.mycompany.com/webhooks/airweave-v2"
)
# Change event types
updated = client.webhooks.update_subscription(
subscription_id = "c3d4e5f6-a7b8-9012-cdef-345678901234" ,
event_types = [ "sync.completed" , "sync.failed" , "sync.running" ]
)
# Disable subscription
updated = client.webhooks.update_subscription(
subscription_id = "c3d4e5f6-a7b8-9012-cdef-345678901234" ,
disabled = True
)
# Re-enable and recover missed messages
from datetime import datetime, timezone, timedelta
updated = client.webhooks.update_subscription(
subscription_id = "c3d4e5f6-a7b8-9012-cdef-345678901234" ,
disabled = False ,
recover_since = (datetime.now(timezone.utc) - timedelta( days = 7 ))
)
Delete Subscription
deleted = client.webhooks.delete_subscription(
subscription_id = "c3d4e5f6-a7b8-9012-cdef-345678901234"
)
print ( f "Deleted: { deleted.url } " )
Once deleted, Airweave will stop sending events to this endpoint immediately. Any pending deliveries will be cancelled.
Recovering Failed Messages
If your endpoint was temporarily down, you can replay failed messages.
from datetime import datetime, timezone, timedelta
# Recover last 24 hours
recovery = client.webhooks.recover_messages(
subscription_id = "c3d4e5f6-a7b8-9012-cdef-345678901234" ,
since = datetime.now(timezone.utc) - timedelta( days = 1 ),
until = datetime.now(timezone.utc)
)
print ( f "Recovery task ID: { recovery.id } " )
print ( f "Status: { recovery.status } " ) # "running" or "completed"
Viewing Messages and Attempts
Inspect webhook messages and delivery attempts for debugging.
# List all messages
messages = client.webhooks.list_messages(
event_types = [ "sync.completed" , "sync.failed" ]
)
for msg in messages[: 5 ]:
print ( f "Event: { msg.event_type } " )
print ( f "Timestamp: { msg.timestamp } " )
print ( f "Payload: { msg.payload } " )
print ()
# Get specific message with delivery attempts
message = client.webhooks.get_message(
message_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890" ,
include_attempts = True
)
print ( f "Event: { message.event_type } " )
if message.delivery_attempts:
for attempt in message.delivery_attempts:
print ( f " Attempt { attempt.id } :" )
print ( f " Status: { attempt.status } " )
print ( f " Response Code: { attempt.response_status_code } " )
print ( f " Response: { attempt.response } " )
Health Status
Subscriptions have health statuses based on recent delivery attempts:
All recent deliveries succeeded (2xx responses). Your endpoint is working correctly.
Mix of successes and failures in recent deliveries. Check your endpoint logs for intermittent issues.
Multiple consecutive failures beyond threshold (3+). Action required - your endpoint is down or returning errors.
No delivery attempts yet. This is normal for newly created subscriptions.
Best Practices
Always verify signatures
Use the signing secret to validate that requests are from Airweave. Never skip signature verification in production.
Respond quickly
Return a 200 OK response as soon as you receive the webhook. Process the event asynchronously if needed.
Handle retries
Make your endpoint idempotent. Airweave may deliver the same event multiple times during retries.
Monitor health status
Check subscription health regularly. Set up alerts for failing status.
Use HTTPS
Webhook URLs must use HTTPS. Use ngrok or similar tools for local development.
Use Cases
Trigger Workflows Start a data pipeline, refresh a cache, or kick off downstream processing when a sync completes.
Send Alerts Notify your team via Slack, email, or PagerDuty when a sync fails or a connection is removed.
Track Infrastructure Know the moment a source connection is added, authenticated, or deleted, or when collections change.
Audit & Logging Record every lifecycle event to your logging system for compliance or debugging.
Next Steps
Collections Learn about organizing data with collections
Search Search across your synced data