Webhooks

Receive real-time events in your own systems — with Zapier, Make, and signature verification.

Receive real-time events in your own systems when something happens in vitelnk — a lead captured, a video watched, a CTA clicked. Webhooks are available on paid plans.

Add a webhook endpoint
1
Go to Settings → Webhooks.
2
Click Add endpoint and paste your server URL.
3
Optionally add a secret — vitelnk will sign every delivery with HMAC-SHA256 so you can verify it's genuine.
4
Select which events to receive, then save.
5
Use Send test ping to verify your endpoint is reachable.
Event payload reference

Every event is delivered as an HTTP POST with a JSON body in this shape:

JSON
{
  "event": "<event.name>",
  "timestamp": "<ISO 8601>",
  "data": { ... }
}
lead.captured
Fired when a viewer submits the viewer registration form on a share page.
JSON
{
  "event": "lead.captured",
  "timestamp": "2026-05-03T10:00:00.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link — Acme",
    "email": "[email protected]"
  }
}
video.watched
Fired when a viewer reaches the link's watch threshold (70% by default, set per video or per link) and at 100%.
JSON
{
  "event": "video.watched",
  "timestamp": "2026-05-03T10:02:30.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link — Acme",
    "watch_percent": 100,
    "threshold_percent": 70
  }
}
cta.clicked
Fired when a viewer clicks the primary CTA button.
JSON
{
  "event": "cta.clicked",
  "timestamp": "2026-05-03T10:03:10.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link — Acme"
  }
}
cta_link.clicked
Fired when a viewer clicks one of the secondary/social links below the video.
JSON
{
  "event": "cta_link.clicked",
  "timestamp": "2026-05-03T10:03:20.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link — Acme"
  }
}
calendar.clicked
Fired when a viewer engages with an embedded Cal.com or Calendly calendar on the share page. Only available for Cal.com and Calendly CTAs — vitelnk uses each provider's own embed SDK to detect this reliably. A custom/raw embed has no tracking for this event.
JSON
{
  "event": "calendar.clicked",
  "timestamp": "2026-05-03T10:04:00.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link — Acme"
  }
}
booking.completed
Fired when a viewer completes a booking through an embedded Cal.com or Calendly calendar. Only available for Cal.com and Calendly CTAs — see calendar.clicked above.
JSON
{
  "event": "booking.completed",
  "timestamp": "2026-05-03T10:05:30.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link — Acme"
  }
}
video.downloaded
Fired when a viewer downloads a file from the share page. "file" is "original" for the original upload, or the quality (e.g. "1080p") for an MP4 download.
JSON
{
  "event": "video.downloaded",
  "timestamp": "2026-05-03T10:06:00.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link, Acme",
    "file": "original"
  }
}
message.received
Fired when a viewer submits a message through the viewer messages form.
JSON
{
  "event": "message.received",
  "timestamp": "2026-05-03T10:07:00.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link — Acme",
    "message": "Loved this, can we hop on a call?"
  }
}
feedback.received
Fired when a viewer submits reaction/feedback on the share page.
JSON
{
  "event": "feedback.received",
  "timestamp": "2026-05-03T10:07:30.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link — Acme"
  }
}
share.viewed
Fired when a share link page is opened by a viewer (not the video owner).
JSON
{
  "event": "share.viewed",
  "timestamp": "2026-05-03T10:00:00.000Z",
  "data": {
    "video_id": "my-demo-video",
    "video_title": "Product Demo",
    "share_token": "abc123xyz",
    "share_name": "Prospect Link — Acme"
  }
}
upload_request.started
Fired when someone starts sending files to one of your upload links, once per sender visit.
JSON
{
  "event": "upload_request.started",
  "timestamp": "2026-10-06T14:02:00.000Z",
  "data": {
    "upload_request_id": 42,
    "upload_request_title": "Wedding clips: Hannah & Luis",
    "uploader_name": "Jane Guest",
    "uploader_email": "[email protected]"
  }
}
upload_request.completed
Fired when a sender has finished: a summary of everything they sent in that visit, with one item per video or file.
JSON
{
  "event": "upload_request.completed",
  "timestamp": "2026-10-06T14:20:00.000Z",
  "data": {
    "upload_request_id": 42,
    "upload_request_title": "Wedding clips: Hannah & Luis",
    "uploader_name": "Jane Guest",
    "uploader_email": "[email protected]",
    "videos_count": 2,
    "files_count": 0,
    "awaiting_review_count": 2,
    "total_bytes": 1874919424,
    "incomplete_count": 0,
    "items": [
      { "type": "video", "id": "img-4021", "title": "IMG_4021", "status": "awaiting_approval" },
      { "type": "video", "id": "img-4022", "title": "IMG_4022", "status": "awaiting_approval" }
    ]
  }
}
Signature verification

When you set a secret on an endpoint, every delivery includes an X-vitelnk-Signature header. The value is sha256=<hex> where the hex is HMAC-SHA256 of the raw request body signed with your secret. Always verify this before processing an event.

JavaScript
const crypto = require('crypto');

function verifySignature(rawBody, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

// Express example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-vitelnk-signature'];
  if (!verifySignature(req.body, sig, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  console.log('Event:', event.event, event.data);
  res.sendStatus(200);
});
Zapier setup
1
In Zapier, create a new Zap and choose "Webhooks by Zapier" as the trigger app.
2
Select "Catch Hook" as the trigger event, then click Continue.
3
Copy the unique webhook URL that Zapier generates.
4
In vitelnk → Settings → Webhooks, click "Add Endpoint" and paste the Zapier URL.
5
Select the events you want to receive (e.g. lead.captured), then save.
6
Back in Zapier, click "Test trigger" — Zapier will wait for a delivery. Send a test ping from the vitelnk endpoint card.
7
Once Zapier captures the payload, map the fields (event, data.email, data.video_title, etc.) to your action app (HubSpot, Google Sheets, Slack, etc.).
8
Turn on the Zap.
Make (Integromat) setup
1
In Make, create a new Scenario and add a "Webhooks" module as the trigger.
2
Choose "Custom webhook" and click "Add", then copy the generated URL.
3
In vitelnk → Settings → Webhooks, add the Make URL as a new endpoint.
4
Select your events and save. Then click "Run once" in Make to start listening.
5
Send a test ping from vitelnk. Make will capture the payload structure automatically.
6
Add your action modules (Google Sheets, Slack, HubSpot CRM, etc.) and map the fields.
7
Activate the Scenario.
Retry & backoff

If your endpoint returns a non-2xx status or times out, vitelnk retries automatically with exponential backoff.

SettingWhat it does
1st retry10 seconds
2nd retry30 seconds
3rd retry60 seconds
4th retry5 minutes
5th retry (final)10 minutes

After 5 failed attempts the delivery is marked failed and no further retries occur. The delivery log in Settings shows the status, HTTP code, and attempt count for every delivery. Each endpoint is limited to 100 deliveries per hour to prevent runaway loops.

Frequently asked questions