Articles on: API & developers

Webhooks and async processing

This article covers two related patterns:


  1. Lido calling your system when something happens (workflow-side webhooks via the Send Webhook node).
  2. 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 GET /job-result/...)

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

Authorization: Bearer <your-secret>

Static secret you check on every inbound request

X-Lido-Signature: <hmac>

If you sign the payload (see "Verification" below)

X-Workflow-Id: <id>

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


  1. In a workflow, add Webhook Trigger as the first node.
  2. Lido generates a unique URL.
  3. Copy the URL. Send POST requests to it from your system; the body becomes {{$item.data.*}} for downstream nodes.
  4. 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.




  • 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

Was this article helpful?

Share your feedback

Cancel

Thank you!