Setting up webhooks
You can configure webhooks in two ways:Global webhook (Dashboard)
Set a global webhook URL for your organization on the Dashboard Settings page. This webhook will receive notifications for all workflow sessions in your organization.Per-request webhook (API)
When running a workflow via the API, you can specify a custom webhook URL in the Run Workflow request. This is useful for testing with ngrok or routing different workflows to different endpoints.- TypeScript
- Python
Webhook payload structure
When a session completes, Simplex will send a POST request to your webhook URL with the following payload:Testing Locally
- TypeScript
- Python
Testing with ngrok
When developing locally, you can use ngrok to create a public URL that forwards to your local development server:- Install ngrok if you haven’t already
- Start your local webhook server (e.g., on port 3000)
- Run ngrok to expose your local server:
- Use the generated ngrok URL in your webhook configuration:
Webhook security
Simplex signs all webhook requests using HMAC-SHA256 to ensure authenticity. You should always verify the signature before processing webhook data.Finding your webhook secret
Your webhook secret is available on the Dashboard Settings page. Keep this secret secure and never commit it to version control.How signing works
Each webhook request includes anX-Simplex-Signature
header containing an HMAC-SHA256 signature of the request body:
Verifying webhooks
- TypeScript SDK
- Python SDK
- Manual verification
The Simplex TypeScript SDK includes a built-in
verifySimplexWebhook()
function that handles signature verification for you.Installation
- Next.js App Router
- Next.js Pages Router
Best practices
1. Always verify signatures
Never process webhook data without first verifying the signature. This ensures the request actually came from Simplex and hasn’t been tampered with.2. Respond quickly
Your webhook endpoint should acknowledge receipt within 30 seconds to prevent retries from the Simplex server. If you need to perform long-running operations (like processing large files or making external API calls), respond with a200 OK
immediately and process the data asynchronously.
3. Handle errors gracefully
Return appropriate HTTP status codes:200
- Webhook received and verified successfully401
- Signature verification failed500
- Server error
4. Use environment variables
Store your webhook secret in environment variables, never in code:5. Test with ngrok
Use ngrok to test webhooks locally before deploying to production:Troubleshooting
”Invalid signature” errors
Cause: The most common cause is parsing the request body as JSON before verification. Solution: Always use the raw request body:- Express: Use
express.raw({ type: 'application/json' })
- Next.js: Disable
bodyParser
in API route config - Flask: Use
request.get_data(as_text=True)
orrequest.body
- FastAPI: Use
await request.body()
Webhook not receiving requests
- Check that your webhook URL is correct in the Dashboard Settings
- Ensure your endpoint is publicly accessible (use ngrok for local testing)
- Verify your server is running and responding to POST requests
- Check your firewall settings
Missing X-Simplex-Signature header
Ensure you’re reading headers correctly. Header names are case-insensitive in HTTP, but some frameworks may normalize them:X-Simplex-Signature
x-simplex-signature
HTTP_X_SIMPLEX_SIGNATURE
(Django/WSGI)