Webhooks and async processing
This article covers two related patterns:
- Lido calling your system when something happens (workflow-side webhooks via the Send Webhook node).
- Your system being called by Lido when extraction completes (the inverse of polling — a workflow listens with a Webhook Trigger).
If you're integrating Lido with your own backend, webhooks usually replace polling.
When to use webhooks
Pattern | Use case |
|---|---|
Send Webhook (Lido → your system) | Notify your app when a workflow finishes; push extracted data to a backend; replace polling with push |
Webhook Trigger (your system → Lido) | Kick off a workflow from any external system that can make an HTTP request |
Polling (your code calls | Fine for batch jobs, prototypes, lower-volume systems where you control the timing |
Polling is simpler. Webhooks are more efficient at scale and remove the result-expiration concern (you store the result on receipt, not on poll).
Pattern 1: Lido pushes results to you (Send Webhook)
This is the recommended high-volume pattern. The full pipeline runs inside a Lido workflow, and the final node POSTs the extracted data to your backend.
Workflow shape
Trigger (Drive / OneDrive / Lido Mailbox / etc.)
↓
Data Extractor
↓
Send Webhook → POST https://your-backend.com/lido-callback
The Send Webhook node sends a JSON payload of your choosing. Typical:
{
"source_file": "{{$item.data.file.name}}",
"extracted": {{$item.previous.data}},
"workflow_run_id": "{{$run.id}}",
"timestamp": "{{$now()}}"
}
Your backend receives this, stores it, and acks with a 200. If it returns 4xx/5xx, the workflow node's error output fires (see "Verification and retries" below).
Why this is better than polling
- No result-expiration issue. You store the data on receipt, not within 24 hours.
- No wasted API quota. No
GET /job-result/...calls. - Faster end-to-end. You learn about the result the moment it's ready.
- No state on your side. No "have I polled this jobId yet?" tracking.
Authentication
The Send Webhook node has fields for custom headers. Use them to authenticate the inbound call to your backend:
Header | Use |
|---|---|
| Static secret you check on every inbound request |
| If you sign the payload (see "Verification" below) |
| So you know which workflow sent the request |
Store the secret in a Lido workspace setting and reference it: {{$workspace.lidoCallbackSecret}}. Don't paste it inline.
Verification and retries
Build your endpoint to be idempotent. A request that fails (network blip) should be safe to retry. Two common patterns:
- Idempotency key. Include
{{$run.id}}in the payload; ignore duplicates on your side. - Lido-side retry. The Send Webhook node has retry settings. Configure 3 retries with exponential backoff. After all retries fail, route to an Error / Send Email node so you find out about the dead letter.
Pattern 2: Your system kicks off a workflow (Webhook Trigger)
The inverse: your application has a "Process invoice" button that POSTs to a Lido workflow URL.
Workflow shape
Webhook Trigger (Lido-hosted URL: https://hooks.lido.app/{token})
↓
Data Extractor (Source File: {{$item.data.file_url}})
↓
... rest of pipeline ...
Setting it up
- In a workflow, add Webhook Trigger as the first node.
- Lido generates a unique URL.
- Copy the URL. Send POST requests to it from your system; the body becomes
{{$item.data.*}}for downstream nodes. - Optionally configure expected headers (e.g.,
Authorization) so the workflow rejects unauthenticated calls.
Example
import requests
response = requests.post(
"https://hooks.lido.app/abc123xyz",
json={
"file_url": "https://your-cdn.com/invoices/abc.pdf",
"vendor_id": 42,
"submitted_by": "aleks@example.com"
},
headers={"Authorization": "Bearer your-shared-secret"}
)
The workflow fires immediately. Lido responds with 202 Accepted (the workflow runs asynchronously) or, if you've configured a synchronous response, 200 with the workflow's final output.
Synchronous vs. asynchronous
- Asynchronous (default): Lido returns 202 immediately. Your system kicks off and forgets. Use the inverse Send Webhook pattern if you need the result back.
- Synchronous: the workflow runs to completion before responding. Your call blocks until the result is ready. Configure this in the Webhook Trigger node settings; useful for short workflows where the caller wants the result inline.
Synchronous mode is bound by your client's HTTP timeout. Lido extraction takes 10–30+ seconds, so synchronous works only when your client tolerates that wait.
Combining both: end-to-end async
Most production integrations combine both:
Your app → POST hooks.lido.app/abc123 (Webhook Trigger)
↓
Data Extractor
↓
Send Webhook → POST your-backend.com/lido-callback
↓
(your backend stores the result and notifies the user)
This is fully async. Your app submits, gets 202, and forgets. Minutes later, your backend gets a callback with the extracted data.
Tips
- Always use HTTPS for both directions.
- Authenticate with a shared secret at minimum. Validate on your side; reject anything missing the header.
- Make endpoints idempotent. Retries happen.
- Log workflow run IDs on both sides so you can match Lido-side runs to your-side records.
- Set up dead-letter alerting. If Send Webhook exhausts its retries, route to a "manual review" channel — don't silently drop.
- Use the Webhook Trigger's "test" feature in the workflow editor to see the exact payload your system is sending.
Common mistakes
- Plain HTTP endpoints. Use HTTPS. Always.
- No auth on Webhook Trigger. Anyone with the URL can fire your workflow. Add a header check.
- No retry budget on Send Webhook. A blip on your side and the data is lost.
- Synchronous when async is appropriate. Holding an HTTP connection open for 30 seconds will cause timeouts at every load balancer in between.
- Returning 4xx for transient errors. A 4xx tells Lido "don't retry — this will never work." Use 5xx for transient.
- Forgetting that workflow trigger payloads count toward page allowance if they include file processing. Plan capacity accordingly.
Related articles
- Lido API: quickstart and authentication
- Extract data via the API: deep dive
- Triggers: how workflows start
- Build your first workflow
- Error handling and retries
Updated on: 16/04/2026
Thank you!