Webhooks

Receive real-time notifications when contracts change state

View as Markdown

Webhooks let your server react to events on the Vlens platform in real time, without polling. When an event occurs, Vlens sends an HTTP POST with a JSON payload to a URL you configure in the Vlens portal.


Use cases

Webhooks support:

  • Tracking contract lifecycle changes (creation, approval, signing, countersignature)
  • Synchronizing contract status with external systems
  • Triggering automated workflows on contract events
  • Maintaining audit and monitoring dashboards

Available events

EventTriggered when
App.BusinessRequestStatusChangeA business request changes status

Setting up a subscription

  1. Sign in to the Vlens portal
  2. Navigate to Webhook Subscriptions
  3. Click Add New Webhook Subscription
  4. Provide:
    • Webhook Endpoint — the URL that will receive POST notifications
    • Webhook Events — one or more events to subscribe to
  5. Click Save

Subscriptions are event-specific and endpoint-specific — multiple subscriptions can target the same event with different endpoints (useful for fan-out to different downstream systems).


Payload format

Every webhook delivery is a POST with a JSON body:

1{
2 "Id": "2b020a26-ec12-4f59-8e6a-7d4bf941372b",
3 "WebhookEvent": "App.BusinessRequestStatusChange",
4 "Attempt": 1,
5 "Data": {
6 "Id": "c2f27bd2-bb49-4dde-bb5f-22a6b8e0d20d",
7 "NewStatus": "PendingApproval"
8 },
9 "CreationTimeUtc": "2025-12-11T11:27:18.6197007Z"
10}
FieldDescription
IdUnique delivery ID
WebhookEventThe event name
AttemptDelivery attempt number
DataEvent-specific payload (see below)
CreationTimeUtcWhen the event occurred (UTC)

Data for BusinessRequestStatusChange

FieldDescription
IdThe business request UUID
NewStatusThe new status name — e.g. PendingApproval, Approved, CustomerSigned, ServiceProviderSigned

Verifying webhook signatures

Vlens signs every delivery with an HMAC-SHA256 hash of the raw request body, sent in the abp-webhook-signature header. Always verify this signature before processing the payload.

abp-webhook-signature: sha256=<hex-digest>

How to verify:

  1. Read the raw request body (before JSON parsing)
  2. Compute HMAC-SHA256(rawBody, webhookSecret)
  3. Compare your digest (hex-encoded) to the value after sha256= in the header
  4. Reject the request if they do not match

Never process a webhook without verifying the signature. An unverified endpoint can be spoofed by anyone who knows your URL.

1import crypto from "crypto";
2import express from "express";
3
4const app = express();
5
6// Use raw body for signature verification
7app.use(express.raw({ type: "application/json" }));
8
9function verifySignature(rawBody, signature, secret) {
10 const expected = "sha256=" + crypto
11 .createHmac("sha256", secret)
12 .update(rawBody)
13 .digest("hex");
14 return crypto.timingSafeEqual(
15 Buffer.from(expected),
16 Buffer.from(signature)
17 );
18}
19
20app.post("/webhooks/vlens", (req, res) => {
21 const signature = req.headers["abp-webhook-signature"];
22 if (!verifySignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
23 return res.status(401).send("Invalid signature");
24 }
25
26 const payload = JSON.parse(req.body);
27 res.status(200).send("ok");
28
29 if (payload.WebhookEvent === "App.BusinessRequestStatusChange") {
30 handleContractStatusChange(payload.Data.Id, payload.Data.NewStatus);
31 }
32});

Your webhook secret is configured when you create the subscription in the Vlens portal. Store it in an environment variable — never in source code.


Receiving a webhook (without signature verification)

The example below skips signature verification. Use only for local development — always verify in production.

1import express from "express";
2
3const app = express();
4app.use(express.json());
5
6app.post("/webhooks/vlens", (req, res) => {
7 const { Id, WebhookEvent, Data, Attempt } = req.body;
8
9 // Acknowledge receipt quickly — process async
10 res.status(200).send("ok");
11
12 // Deduplicate using Id
13 if (alreadyProcessed(Id)) return;
14 markProcessed(Id);
15
16 if (WebhookEvent === "App.BusinessRequestStatusChange") {
17 handleContractStatusChange(Data.Id, Data.NewStatus);
18 }
19});
20
21app.listen(3000);

Delivery logs

Every webhook delivery is logged and viewable in the Vlens portal. Each log entry includes:

  • HTTP method (POST)
  • Source IP address
  • Timestamp
  • Request headers
  • Request body

Use the delivery log to debug failed or unexpected deliveries.


Common patterns

Reconcile on completion

1if (WebhookEvent === "App.BusinessRequestStatusChange"
2 && Data.NewStatus === "ServiceProviderSigned") {
3 // Contract fully executed — sync to internal systems and notify the customer
4 await crm.markContractCompleted(Data.Id);
5 await sendCustomerNotification(Data.Id);
6}

Polling fallback

For mission-critical workflows, combine webhooks with periodic polling of GET /api/BusinessRequest/CurrentListIds to catch any missed deliveries.