Limai Docs
API ReferenceWebhooks

Webhook Setup

Configure webhooks to receive real-time notifications when documents are processed.

Subscribe to real-time events from document processing workflows. Get notified instantly when documents are extracted or reviewed with secure, reliable webhook delivery.

Setting Up Webhooks

  1. Navigate to Events Page -- Go to your deployment and click "Events" in the left sidebar
  2. Add Webhook Subscription -- Click "Add Webhook" and enter your HTTPS endpoint URL
  3. Select Event Types -- Choose which events you want to receive: DOCUMENT_EXTRACTED, DOCUMENT_REVIEWED, or both
  4. Verify Your Endpoint -- Click "Verify URL" to confirm you control the endpoint and activate the subscription

URL Verification

Before activating your webhook subscription, LimAI verifies that you control the endpoint by sending a verification challenge.

  1. You click "Verify URL" for your webhook subscription
  2. LimAI sends a VERIFICATION event to your endpoint with a challenge value
  3. Your endpoint must respond with the challenge value in the response body
  4. The subscription is marked as verified and activated

HMAC Signature Verification

All webhook events are signed with HMAC-SHA256 for authenticity verification. Each webhook subscription gets a unique secret key, and every request includes an X-Webhook-Signature header with the format sha256=<hex_digest>.

Always verify the signature before processing events.

const crypto = require("crypto")
const express = require("express")

function verifyWebhookSignature(payload, signature, secretKey) {
const expectedSignature = crypto
  .createHmac("sha256", secretKey)
  .update(payload)
  .digest("hex")

const receivedSignature = signature.replace("sha256=", "")

return crypto.timingSafeEqual(
  Buffer.from(expectedSignature, "hex"),
  Buffer.from(receivedSignature, "hex")
)
}

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const signature = req.headers["x-webhook-signature"]
const payload = req.body.toString()

if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
  return res.status(401).send("Invalid signature")
}

const event = JSON.parse(payload)

if (event.eventType === "VERIFICATION") {
  return res.json({ challenge: event.challenge })
}

switch (event.eventType) {
  case "DOCUMENT_EXTRACTED":
    handleDocumentExtracted(event)
    break
  case "DOCUMENT_REVIEWED":
    handleDocumentReviewed(event)
    break
}

res.status(200).send("OK")
})

Retry Policy

Failed webhook deliveries are retried with exponential backoff:

  • Maximum retries: 5 attempts
  • Backoff: Exponential, starting at 1 second
  • Success criteria: Your endpoint must respond with a 2xx status code

Event Types

EventDescription
DOCUMENT_EXTRACTEDFires when document processing completes (success or failure)
DOCUMENT_REVIEWEDFires when all rows in a document are accepted

Retrieving Data from Webhooks

Webhook payloads contain metadata (file ID, schema ID, status) but not the actual extracted data. Use the get-file-data endpoint with the fileId from the webhook payload to retrieve the processed content.

Best Practices

  • Always verify HMAC signatures before processing events
  • Respond with 2xx status codes quickly to avoid timeouts
  • Implement idempotency using the unique eventId to prevent duplicate processing
  • Process events asynchronously to avoid blocking the response
  • Use HTTPS endpoints to protect data in transit
  • Store webhook secret keys in environment variables