Skip to main content
Webhooks allow your application to receive real-time updates when long-running or asynchronous jobs are completed — such as parsing or extraction tasks submitted via Reducto’s API. Instead of continuously polling the job status, you can configure a webhook endpoint to be notified automatically when a job finishes. Svix provides enterprise-grade webhook infrastructure with built-in security (request signing), automatic retries with exponential backoff, delivery tracking, and a management dashboard.

Why Use Svix Webhooks?

Svix webhooks offer several advantages over direct webhooks:
  • Built-in Security: Automatic request signing with cryptographic verification
  • Reliable Delivery: Advanced retry logic with exponential backoff
  • Delivery Dashboard: Web UI to monitor webhook deliveries and debug failures
  • Multiple Endpoints: Support for multiple webhook endpoints via channels
  • Event Filtering: Route different event types to different endpoints
  • Replay Capability: Manually replay failed webhook deliveries

How Svix Webhooks Work

When you submit an async job with Svix webhooks configured, Reducto will:
  1. Process your document asynchronously
  2. Send a signed webhook notification to Svix when the job completes (or fails)
  3. Svix delivers the notification to your configured endpoint(s) with automatic retries
  4. Your application verifies the signature and processes the webhook payload

Setting Up Svix Webhooks

Step 1: Configure Your Webhook Endpoint

First, get the Svix configuration URL to set up your webhook endpoints:
import requests

webhook_url = requests.post(
    "https://platform.reducto.ai/configure_webhook",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
)

# Go to this link to configure your webhook receiving application
print(webhook_url.text)
This will return a URL to the Svix dashboard where you can:
  • Add webhook endpoint URLs
  • Configure channels for routing
  • View delivery logs and debug failures
  • Get your webhook signing secret

Step 2: Submit Jobs with Svix Webhooks

from reducto import Reducto

client = Reducto(api_key="your_api_key")

# Submit an async parse job with Svix webhooks
submission = client.parse.run_job(
    input="https://ci.reducto.ai/onepager.pdf",
    async_config={
        "webhook": {
            "mode": "svix",
            "channels": []  # Optional: specify channels or omit to send to all
        },
        "metadata": {
            "user_id": "user_123",
            "document_type": "invoice"
        }
    }
)

print(f"Job submitted: {submission.job_id}")

Using Channels for Routing

Channels allow you to route webhooks to different endpoints. For example, you might want to send production jobs to one endpoint and development jobs to another:
from reducto import Reducto

client = Reducto(api_key="your_api_key")

# Send to production channel
production_submission = client.parse.run_job(
    input="https://ci.reducto.ai/onepager.pdf",
    async_config={
        "webhook": {
            "mode": "svix",
            "channels": ["production"]
        }
    }
)

# Send to development channel
dev_submission = client.parse.run_job(
    input="https://ci.reducto.ai/test.pdf",
    async_config={
        "webhook": {
            "mode": "svix",
            "channels": ["development"]
        }
    }
)

Webhook Handler with Signature Verification

from flask import Flask, request, jsonify
from reducto import Reducto
from svix.webhooks import Webhook, WebhookVerificationError

app = Flask(__name__)
client = Reducto(api_key="your_api_key")

# Get this from the Svix dashboard
SVIX_WEBHOOK_SECRET = "whsec_your_webhook_secret"

@app.route('/webhook/reducto', methods=['POST'])
def handle_webhook():
    # Get the webhook signature headers
    svix_id = request.headers.get('svix-id')
    svix_timestamp = request.headers.get('svix-timestamp')
    svix_signature = request.headers.get('svix-signature')
    
    if not all([svix_id, svix_timestamp, svix_signature]):
        return jsonify({"error": "Missing signature headers"}), 401
    
    # Verify the webhook signature
    wh = Webhook(SVIX_WEBHOOK_SECRET)
    try:
        payload = wh.verify(request.data, {
            'svix-id': svix_id,
            'svix-timestamp': svix_timestamp,
            'svix-signature': svix_signature
        })
    except WebhookVerificationError as e:
        return jsonify({"error": "Invalid signature"}), 401
    
    # Process the verified webhook
    job_id = payload['job_id']
    status = payload['status']
    metadata = payload.get('metadata', {})
    
    if status == "Completed":
        # Retrieve the job result
        job = client.job.get(job_id)
        result = job.result
        
        # Process the result
        print(f"Job {job_id} completed successfully")
        print(f"Metadata: {metadata}")
        print(f"Result: {result}")
        
    elif status == "Failed":
        print(f"Job {job_id} failed")
    
    return jsonify({"received": True}), 200

if __name__ == '__main__':
    app.run(port=5000)

Using Svix Webhooks with Extract

Svix webhooks work with all async endpoints. Here’s an example with the extract endpoint:
from reducto import Reducto

client = Reducto(api_key="your_api_key")

submission = client.extract.run_job(
    input="https://ci.reducto.ai/invoice.pdf",
    instructions={
        "schema": {
            "invoice_number": "string",
            "total_amount": "number",
            "date": "string"
        }
    },
    async_config={
        "webhook": {
            "mode": "svix",
            "channels": ["invoices"]
        }
    }
)

print(f"Extraction job submitted: {submission.job_id}")

Webhook Payload Structure

The webhook notification will be sent as a JSON POST request with the following structure:
{
  "status": "Completed",  // or "Failed"
  "job_id": "job_abc123",
  "metadata": {
    // Your custom metadata (optional)
  }
}

Verifying Webhook Signatures

Svix automatically signs all webhook requests. Always verify the signature to ensure the webhook is legitimate and hasn’t been tampered with.

Why Signature Verification Matters

Without signature verification, anyone could send fake webhook requests to your endpoint. Signature verification ensures:
  1. The webhook came from Reducto/Svix (authenticity)
  2. The payload hasn’t been modified (integrity)
  3. The webhook isn’t a replay of an old request (freshness)

Getting Your Webhook Secret

  1. Go to the Svix dashboard (use the URL from /configure_webhook)
  2. Navigate to your endpoint settings
  3. Copy the webhook signing secret (starts with whsec_)
  4. Store it securely as an environment variable

Signature Verification Best Practices

  1. Always verify signatures: Never skip signature verification in production
  2. Use the official Svix SDK: The SDK handles signature verification correctly
  3. Preserve raw request body: Don’t parse the JSON before verification
  4. Check timestamp: Reject webhooks with timestamps too far in the past
  5. Store secrets securely: Use environment variables or secret management systems

Managing Webhooks in the Svix Dashboard

The Svix dashboard provides powerful tools for managing your webhooks:

Viewing Delivery Logs

  • See all webhook deliveries with timestamps and status codes
  • View request and response bodies for debugging
  • Filter by endpoint, status, or time range

Debugging Failed Deliveries

  • Identify why webhooks failed (network errors, timeouts, invalid responses)
  • View detailed error messages and stack traces
  • Check signature verification failures

Manual Replay

  • Replay failed webhooks after fixing issues
  • Replay webhooks to test new endpoint implementations
  • Bulk replay multiple webhooks at once

Endpoint Management

  • Add, edit, or remove webhook endpoints
  • Configure rate limits and retry policies
  • Set up endpoint-specific channels and filters

Advanced Features

Multiple Endpoints

Configure multiple webhook endpoints to receive the same events:
# In the Svix dashboard, add multiple endpoints:
# - https://api.example.com/webhooks/reducto
# - https://backup.example.com/webhooks/reducto

# Both endpoints will receive webhook notifications
submission = client.parse.run_job(
    input="https://ci.reducto.ai/onepager.pdf",
    async_config={
        "webhook": {
            "mode": "svix"
        }
    }
)

Channel-Based Routing

Use channels to route different types of jobs to different endpoints:
# Configure in Svix dashboard:
# - Endpoint A: listens to "production" channel
# - Endpoint B: listens to "development" channel
# - Endpoint C: listens to all channels

# This goes to Endpoint A and C
prod_job = client.parse.run_job(
    input="https://ci.reducto.ai/prod-doc.pdf",
    async_config={
        "webhook": {
            "mode": "svix",
            "channels": ["production"]
        }
    }
)

# This goes to Endpoint B and C
dev_job = client.parse.run_job(
    input="https://ci.reducto.ai/test-doc.pdf",
    async_config={
        "webhook": {
            "mode": "svix",
            "channels": ["development"]
        }
    }
)

Best Practices

  1. Always Verify Signatures: Use the Svix SDK to verify webhook signatures. Never skip this step in production.
  2. Use HTTPS: Always use HTTPS endpoints to ensure secure transmission of webhook data.
  3. Implement Idempotency: Your webhook handler should be idempotent since Svix may retry deliveries. Use the svix-id header as an idempotency key.
  4. Return Quickly: Return a 2xx status code quickly (within 15 seconds). Process the job result asynchronously if needed.
  5. Use Channels for Environments: Separate production and development webhooks using channels to avoid mixing test and production data.
  6. Monitor the Dashboard: Regularly check the Svix dashboard for failed deliveries and debug issues promptly.
  7. Handle Failures Gracefully: Implement proper error handling and logging in your webhook endpoint.
  8. Use Metadata: Include custom metadata in your webhook configuration to help identify and route jobs in your application.
  9. Test with Replay: Use the Svix dashboard’s replay feature to test your webhook handler without submitting new jobs.
  10. Set Up Alerts: Configure alerts in your monitoring system for webhook delivery failures.

Troubleshooting

Webhooks Not Being Received

  1. Check the Svix dashboard for delivery attempts and errors
  2. Verify your endpoint URL is correct and publicly accessible
  3. Ensure your endpoint returns a 2xx status code
  4. Check for firewall or network issues blocking Svix’s IP addresses

Signature Verification Failing

  1. Verify you’re using the correct webhook secret from the Svix dashboard
  2. Ensure you’re passing the raw request body to the verification function
  3. Check that all required headers (svix-id, svix-timestamp, svix-signature) are present
  4. Make sure you’re using the latest version of the Svix SDK

Webhook Timeouts

  1. Reduce processing time in your webhook handler
  2. Return a 2xx response immediately and process asynchronously
  3. Check for slow database queries or external API calls
  4. Consider using a message queue for heavy processing

Comparison with Direct Webhooks

FeatureSvix WebhooksDirect Webhooks
Setup complexityRequires Svix configurationSimple URL configuration
SecurityBuilt-in request signingManual validation required
Retry logicAdvanced with exponential backoffBasic (3 retries)
Delivery trackingFull dashboard with logsNot included
Multiple endpointsSupported via channelsOne URL per job
Replay capabilityBuilt-in via dashboardNot available
Debugging toolsComprehensive dashboardManual logging required
For production applications with high reliability requirements, Svix webhooks are recommended due to their superior security, reliability, and debugging capabilities. For simpler use cases or quick prototyping, consider direct webhooks.