For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Book a demoLog in
DocumentationAPI ReferenceModel VersioningChangelog
DocumentationAPI ReferenceModel VersioningChangelog
    • Studio
    • Support
    • Benchmarks
    • Status
  • Getting Started
    • Overview
    • API Quickstart
    • Dashboard Quickstart
    • Agent Quickstart
  • Dev Tools
    • SDKs
    • CLI
  • Capabilities
      • Configuration
      • Events
      • Best Practices
LogoLogo
Book a demoLog in
On this page
  • Responding to webhooks
  • Quick acknowledgment
  • Asynchronous processing
  • Handling duplicates and retries
  • Idempotency with event IDs
  • Error handling and reliability
  • Retry strategy
  • Security considerations
  • Always verify signatures
Webhooks

Best Practices

Was this page helpful?
Previous

Data Handling

Next
Built with

Responding to webhooks

Quick acknowledgment

Respond with a 2xx status quickly, preferably within a few seconds. Extend times out after 30 seconds.

1from extend_ai import Extend
2from extend_ai.wrapper.errors import WebhookSignatureVerificationError
3
4client = Extend(token="YOUR_API_KEY")
5
6@app.post('/webhook')
7async def handle_webhook(request):
8 try:
9 event = client.webhooks.verify_and_parse(
10 body=request.body.decode(),
11 headers=dict(request.headers),
12 signing_secret="wss_your_signing_secret"
13 )
14
15 # Queue the event for async processing, then respond immediately
16 await message_queue.send({
17 "type": "webhook-event",
18 "payload": event
19 })
20
21 return {"status": "ok"}
22 except WebhookSignatureVerificationError:
23 return {"error": "Invalid signature"}, 401

Asynchronous processing

Queue tasks that are slow, depend on external services, or may need retries.

1from extend_ai import Extend
2from extend_ai.wrapper.errors import WebhookSignatureVerificationError
3
4client = Extend(token="YOUR_API_KEY")
5
6# ❌ Bad: Synchronous work can cause timeouts and duplicates
7@app.post('/webhook')
8async def handle_webhook_bad(request):
9 event = client.webhooks.verify_and_parse(body, headers, secret)
10
11 await send_to_multiple_apis(event["payload"])
12 await generate_pdf_report(event["payload"])
13 await enrich_data_from_third_party(event["payload"])
14 await send_email_notifications(event["payload"])
15
16 return {"status": "ok"}
17
18# ✅ Good: Enqueue then respond
19@app.post('/webhook')
20async def handle_webhook_good(request):
21 try:
22 event = client.webhooks.verify_and_parse(
23 body=request.body.decode(),
24 headers=dict(request.headers),
25 signing_secret="wss_your_signing_secret"
26 )
27
28 await job_queue.add("process-webhook", event)
29 return {"status": "ok"}
30 except WebhookSignatureVerificationError:
31 return {"error": "Invalid signature"}, 401

Handling duplicates and retries

Idempotency with event IDs

Extend tries to minimize duplicate requests, but occasionally they are unavoidable. If your side effects are not idempotent, you can use the eventId (e.g., event_abc123) to avoid processing the same event multiple times.

1async def process_webhook(event):
2 event_id = event["eventId"]
3
4 # Check if already processed
5 if await redis.get(f"processed:{event_id}"):
6 return
7
8 # Process the event
9 await handle_event(event)
10
11 # Mark as processed (expire after 7 days)
12 await redis.setex(f"processed:{event_id}", 86400 * 7, "true")

Error handling and reliability

Retry strategy

Extend retries failed or timed-out (30 s) requests with exponential backoff:

1from extend_ai import Extend
2from extend_ai.wrapper.errors import WebhookSignatureVerificationError
3
4client = Extend(token="YOUR_API_KEY")
5
6@app.post('/webhook')
7async def handle_webhook(request):
8 try:
9 event = client.webhooks.verify_and_parse(
10 body=request.body.decode(),
11 headers=dict(request.headers),
12 signing_secret="wss_your_signing_secret"
13 )
14
15 queued = await message_queue.send(event)
16 if not queued.success:
17 # Return 503 to trigger a retry from Extend
18 return {"error": "Service temporarily unavailable"}, 503
19
20 return {"status": "ok"}
21 except WebhookSignatureVerificationError:
22 return {"error": "Invalid signature"}, 401

Security considerations

Always verify signatures

Always verify the webhook signature using the SDK’s verifyAndParse() or verify_and_parse() method. This ensures:

  • The request actually came from Extend
  • The payload hasn’t been tampered with
  • The request is recent (protects against replay attacks)

See the signature verification guide for more details.