Skip to content

Receive webhooks

When to use this

Use webhooks instead of polling whenever your service can accept inbound HTTPS calls. Docmation invokes your URL once a work item reaches a terminal state (Finished or Faulted); you then call GetResult to fetch the actual payload. Webhooks are the preferred completion signal — polling exists as a fallback.

Prerequisites

  • A public HTTPS endpoint that accepts an HTTP GET with no body, returns a 2xx quickly, and is idempotent.
  • A webhookUrl value on each AddWorkItem* submission. The URL may contain the literal {0} placeholder — Docmation replaces it with the workItemId before calling, so you can route the request without parsing query strings.

Walkthrough

1. Register the URL on submit

Every AddWorkItem* request (see Submit a MAD batch, Submit a DOCOM batch, Submit an NVWA batch) accepts a webhookUrl on the BaseWorkItem:

{
  "customerReference": "ORDER-2026-0001",
  "documentReference": null,
  "webhookUrl": "https://example.com/docmation/webhook/{0}",
  "...": "..."
}

Use {0} in the path so the work-item id is part of the URL the receiver sees.

2. Receive the call

Docmation makes a single GET to the rendered URL. There is no request body and no signed payload — the URL itself (containing {0} → workItemId) is the entire signal. A minimal receiver:

GET https://example.com/docmation/webhook/67890 HTTP/1.1

Your handler should:

  1. Parse the workItemId from the path.
  2. Acknowledge quickly with 200 OK (any 2xx works — 200, 201, 204).
  3. Asynchronously call back into Docmation to fetch the actual result, e.g. GET /api/VlmMad/GetResult?workItemId=67890.

3. Fetch the result and mark it consumed

curl "https://api.docmation.eu/api/VlmMad/GetResult?workItemId=67890" \
  -H "Authorization: Bearer <jwt>"

Once Docmation observes that the result has been fetched (ResultFetched is stamped), it stops calling the webhook even if some retries remain on the counter.

Retry & delivery semantics

Webhook delivery is driven by WebhookService, which runs as a cron job every 3 minutes (CronJobs.CallWebhooks). Each work item carries a WebhookCallCount budget (default from AppSettings.WebhookRetryCount, currently 9):

  • Both transient network failures and non-2xx HTTP responses (4xx and 5xx alike) are treated the same — they decrement the counter and schedule a retry.
  • After a failed attempt, the next is scheduled at (maxRetryCount − WebhookCallCount)² × 30 seconds using the pre-decrement value of WebhookCallCount. With the default WebhookRetryCount = 9, the total budget across 9 attempts is roughly 1 h 42 min.
  • A successful 2xx flips WebhookCallSuccessful to true and stops further attempts.
  • If the budget is exhausted before a success, Docmation gives up. The work item itself is unaffected — GetResult will still serve the data.

Backoff schedule (with the default WebhookRetryCount = 9)

Attempt WebhookCallCount going in Delay until next attempt Cumulative wall-clock
1 9 (9-9)² × 30 = 0 s 0 s
2 8 (9-8)² × 30 = 30 s 30 s
3 7 (9-7)² × 30 = 120 s 2 min 30 s
4 6 (9-6)² × 30 = 270 s 7 min
5 5 (9-5)² × 30 = 480 s 15 min
6 4 (9-4)² × 30 = 750 s 27 min 30 s
7 3 (9-3)² × 30 = 1080 s 45 min 30 s
8 2 (9-2)² × 30 = 1470 s 1 h 10 min
9 1 (9-1)² × 30 = 1920 s 1 h 42 min
— 0 (loop drops the row; no further attempts) —

The actual call only fires when the cron job runs (every 3 min) after the scheduled time, so delays above are a floor.

What to watch for

  • GET, not POST — the webhook is a plain GET against the rendered URL. Do not configure your endpoint to require a body or signed payload.
  • Idempotency is your responsibility — Docmation may call the same workItemId more than once (replay after a non-2xx). Accept duplicates as no-ops.
  • Respond quickly — slow handlers risk timing out and triggering a retry. Acknowledge first, work later.
  • Invalid URLs are not retried indefinitely — if string.Format(workItemUrl, workItemId) fails to parse as an absolute http(s):// URI, the service logs a warning and decrements the retry counter the same way as a failed HTTP call.
  • No payload means no signature — there is no HMAC or shared secret today; restrict access by URL knowledge (treat the URL as a capability) or by IP-allow-listing Docmation's outbound range. Plan to add a shared secret in v2 if you need stronger authentication.
  • Develop locally — in DEBUG builds the WebhookClient redirects non-localhost URLs to https://httpbin.org/get to prevent accidental production calls during development. This is a build-time guard, not a configurable runtime setting.
  • Consistency with the errors & retries reference page — same retry semantics described in one place, in case you spot a discrepancy.

AI-drafted from WebhookService.cs. Verify field names against the live Swagger UI before publishing.