Linkzly

Webhooks

Webhooks let Linkzly notify your server the moment something happens — a link is clicked, a domain is verified, a team member joins, or an API key is revoked. I

14 min read

Webhooks

Webhooks let Linkzly notify your server the moment something happens — a link is clicked, a domain is verified, a team member joins, or an API key is revoked. Instead of polling the Linkzly API on a schedule to check for changes, your server receives an HTTP POST request automatically as events occur.

Use webhooks to:

  • Sync click data into your own database in real time
  • Trigger downstream workflows (for example, send a Slack alert when a domain is verified)
  • Keep an external analytics platform up to date with the latest events
  • Audit API key activity in your own logging system

Navigate to Webhooks under the Integration section in the left sidebar to create and manage your webhooks.


18.1 Available Event Types

Subscribe your webhook to any combination of the events below. You can update your subscriptions at any time. In the event selection UI, events are grouped into categories and tagged with a frequency badge (HIGH, MEDIUM, or LOW) to help you plan for expected volume.

Link Management

Event Display Name Frequency Trigger
link.created Link Created MEDIUM A new short link is created
link.updated Link Updated MEDIUM A short link is modified
link.deleted Link Deleted LOW A short link is deleted
link.clicked Link Clicked HIGH A short link receives a click

Note: link.clicked is a high-volume event. If your link receives thousands of clicks per hour, subscribe to this event only if your server can handle the volume. Consider using the Analytics API to pull aggregated data instead.

QR Code

Event Display Name Frequency Trigger
qr_code.created QR Code Created MEDIUM A new QR code is generated
qr_code.scanned QR Code Scanned HIGH A QR code is scanned

Note: qr_code.scanned is a high-volume event. The same volume considerations apply as for link.clicked.

Domain Management

Event Display Name Frequency Trigger
domain.created Domain Created LOW A custom domain is added to the organization
domain.verified Domain Verified LOW A domain's DNS verification succeeds
domain.deleted Domain Deleted LOW A custom domain is removed

API Keys

Event Display Name Frequency Trigger
api_key.created API Key Created LOW A new API key is created
api_key.revoked API Key Revoked LOW An API key is revoked or deleted

Team Management

Event Display Name Frequency Trigger
team.member_added Team Member Added LOW A team member accepts an invitation and joins the organization
team.member_removed Team Member Removed LOW A team member is removed from the organization

18.2 Webhook Configuration Fields

Click Create Webhook to open the creation form. All fields are described below.

Basic Information

Field Required Description
Webhook Name Yes A display label for this webhook so you can identify it at a glance.
Description No Internal notes about what this webhook does and who maintains it.

Endpoint Configuration

Field Required Description
Webhook URL Yes The HTTPS endpoint on your server that receives POST requests from Linkzly. Must be a valid HTTPS URL. Use the Validate button to check the URL before saving.

Events to Subscribe

Select one or more event types from the multi-select list. Events are grouped by category (Link Management, QR Code, Domain Management, API Keys, Team Management) and tagged with frequency badges to indicate expected volume.

Advanced Configuration

Field Required Description
Retry Policy No How Linkzly retries failed deliveries: exponential (default), linear, immediate, or none.
Max Retries No Number of retry attempts. Accepted range: 0–10. Default: 3.
Timeout (seconds) No How many seconds Linkzly waits for a response from your server. Default: 30 seconds.

Custom Headers

Key-value pairs added to every delivery request. Use these to pass authentication tokens or API keys required by your server. Click Add Header to add a new header. You may add up to 10 custom headers per webhook.

Note: The following reserved headers cannot be used as custom header names: Content-Type, User-Agent, and any header beginning with X-Webhook-.

Webhook Status

Newly created webhooks are active by default. You can enable or disable a webhook at any time using the Enable / Disable action in the webhook's actions menu. A disabled webhook does not receive any events.


18.3 Payload Structure

Linkzly sends an HTTP POST request to your URL with a JSON body for every event.

Delivery Headers

Every delivery includes the following HTTP headers:

Header Description
X-Webhook-Timestamp Unix timestamp in milliseconds of when the request was sent
X-Webhook-Signature HMAC-SHA256 signature in the format sha256=<hex_signature>
X-Webhook-Event The event type string (e.g., link.clicked)
X-Webhook-Delivery Unique delivery identifier for this specific attempt
X-Webhook-Attempt Attempt number (1 = first try, 2 = first retry, etc.)
Content-Type application/json
User-Agent Linkzly-Webhook/2.0

Any custom headers you configured are also included.

Standard Payload Fields (all events)

Every event payload includes these top-level fields:

{
  "id": "evt_xxxxxxxxxxxxxxxx",
  "event": "link.clicked",
  "timestamp": "2024-06-15T12:34:56.789Z",
  "organizationId": "org_xxxxxxxxxxxx",
  "organization": {
    "id": "org_xxxxxxxxxxxx",
    "name": "Acme Corp"
  },
  "data": { ... }
}
Field Description
id Unique event identifier with the prefix evt_
event The event type string (e.g., link.clicked, domain.verified)
timestamp ISO 8601 UTC datetime when the event occurred
organizationId Your organization ID
organization Optional object containing id and name of the organization
data Object containing event-specific fields (see below)

Event-Specific Data Fields

link.clicked

Field Description
linkId The ID of the short link that was clicked
shortUrl The full short URL
clickedAt ISO 8601 datetime of the click
country Country name of the visitor
countryCode ISO 3166-1 alpha-2 country code
city City of the visitor (when available)
device Device type: mobile, desktop, tablet, etc.
browser Browser name
os Operating system
referrer Referring domain (if available)

qr_code.scanned

Field Description
qrCodeId The ID of the scanned QR code
linkId The ID of the linked short link
shortUrl The full short URL associated with the QR code
scannedAt ISO 8601 datetime of the scan
country Country name of the scanner
device Device type
browser Browser or scanning app
os Operating system

domain.verified

Field Description
id The domain ID
domain The domain name
verifiedAt ISO 8601 datetime when verification succeeded
sslStatus Current SSL certificate status
sslExpiresAt ISO 8601 datetime when the SSL certificate expires

team.member_added

Field Description
memberId The new member's user ID
email The new member's email address
name The new member's full name
role The role assigned to the new member
permissions Array of specific permissions granted
invitedBy User ID of the person who sent the invitation
joinedAt ISO 8601 datetime when the member accepted

18.4 Signature Verification

Every webhook delivery includes signature headers. You should always verify these headers to confirm the request came from Linkzly and was not tampered with in transit.

Header Description
X-Webhook-Timestamp Unix timestamp in milliseconds of when the request was sent
X-Webhook-Signature HMAC-SHA256 signature in the format sha256=<hex_signature>

How to Verify

The signature is computed as:

HMAC-SHA256(webhookSecret, "{timestamp}.{rawBody}")

The X-Webhook-Signature header value includes the sha256= prefix as part of the string (for example: sha256=abc123def456...). Compute the HMAC on your server using your webhook secret and the {timestamp}.{rawBody} string, then compare the resulting hex digest — prepended with sha256= — against the full header value.

Always use a constant-time comparison function (such as crypto.timingSafeEqual) to prevent timing attacks.

Replay Protection

Reject any request where the X-Webhook-Timestamp is more than 5 minutes older than your server's current time. This prevents an attacker from capturing a valid request and replaying it later.

Example — JavaScript Verification

const crypto = require('crypto');

function verifyWebhookSignature(rawBody, timestamp, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex');

  // The header value includes the 'sha256=' prefix
  const headerValue = `sha256=${expected}`;
  return crypto.timingSafeEqual(
    Buffer.from(headerValue),
    Buffer.from(signature)
  );
}

Pass the raw request body (before any parsing), the X-Webhook-Timestamp header value, the full X-Webhook-Signature header value (including the sha256= prefix), and your webhook secret.

Rotating the Secret

Your webhook secret is shown once at creation time. If the secret is ever exposed, click Rotate Secret from the webhook's actions menu. Linkzly generates a new secret immediately. Update your server to use the new secret — deliveries signed with the old secret will fail verification.

Security Tools

The Security Tools dialog (accessible from the top-right of the Webhooks page) provides two interactive utilities to help during development:

  • Generate Signature — Enter your webhook secret and a JSON payload to generate a valid signature and the expected delivery headers.
  • Verify Signature — Enter your webhook secret, a JSON payload, a signature, and a timestamp to confirm whether the signature is valid.

Verify Utility Endpoint

Linkzly also provides an API endpoint to debug signature verification:

POST /api/webhooks/utilities/verify-signature

Send the signature, timestamp, and raw body, and the API will confirm whether the signature is valid.


18.5 Retry Logic

When your server returns a non-2xx response or times out, Linkzly retries the delivery according to the retry policy configured on the webhook.

Retry Policy Timing Description
Exponential (default) 1st retry after 2 seconds, 2nd after 4 seconds, 3rd after 8 seconds Each retry waits twice as long as the previous. Best for most production use cases.
Linear 5-second fixed delay between each retry Every retry attempt waits the same fixed interval.
Immediate 1-second delay between each retry Retries are sent as quickly as possible with a minimal delay.
None No retries Failed deliveries are logged but not retried.

Max retries is configurable from 0 to 10 on any retry policy. The default is 3 retries. If all retries are exhausted, the delivery is marked as failed in the delivery log.

Your server must return a 2xx HTTP status code to acknowledge successful receipt. Any other response code (including redirects) is treated as a failure.

Automatic Suspension (Circuit Breaker)

If a webhook accumulates 5 consecutive failures, Linkzly automatically suspends it to protect your server from continued traffic while it is unreachable. A suspended webhook appears with a Suspended status badge in the webhooks list.

To reactivate a suspended webhook, open its actions menu and select Enable. You can also manually suspend any active webhook from the same actions menu if you need to pause deliveries temporarily.


18.6 Delivery Logs

Every delivery attempt — successful or not — is recorded in the delivery log for each webhook. Click View Deliveries from a webhook's actions menu to open the Webhook Deliveries dialog.

Summary stats above the table show counts for Total, Success, Failed, and Pending deliveries.

Column Description
Status Success (green), Failed (red), or Pending (yellow)
Event The event type that triggered this delivery (e.g., link.clicked)
Sent At The date and time when the delivery was attempted
Response The HTTP status code your server returned
Duration How long your server took to respond, in milliseconds
Attempt Which attempt this was, displayed as a badge (e.g., #1, #2)
Actions Retry icon (RefreshCw) for failed deliveries; View Details icon for all deliveries

The retry action is only available for deliveries with a Failed status. Clicking it manually triggers a new delivery attempt immediately.


18.7 Webhook Analytics

Click View Analytics from a webhook's actions menu to open the Webhook Analytics dialog and see a health overview of its delivery performance.

Metric Description
Health Score Percentage of successful deliveries. Rated as: Excellent (≥ 80%), Good (≥ 60%), Fair (≥ 40%), Poor (< 40%).
Total Deliveries All-time count of delivery attempts for this webhook
Success Rate Percentage of deliveries that received a 2xx response from your server
Avg Response Mean response time in milliseconds across all deliveries
Failures Current count of consecutive back-to-back failed deliveries. A high number here may indicate your endpoint is down.
Event Breakdown Table showing delivery count and percentage per subscribed event type

18.8 URL Validation

Use the Validate button on the Webhook URL field to check your endpoint before saving the configuration.

The following checks are performed:

  • The URL must be a valid HTTPS URL (HTTP is not accepted, except for localhost and 127.0.0.1 during development)
  • Non-standard port numbers generate a warning
  • A root path (/) generates a suggestion to use a more specific path
  • A security score is returned based on the results

If the URL is valid, the button area shows a "URL is valid" confirmation along with the security score. Errors and warnings are listed if any checks fail.

After saving, use the Test Webhook button from the actions menu to send a sample event payload to your endpoint and confirm it processes the delivery correctly.


18.9 Bulk Operations

You can manage multiple webhooks at once from the main Webhooks list.

  1. Select webhooks using the checkboxes on the left side of the table.
  2. Click the Bulk Actions dropdown that appears.
  3. Choose one of the available actions:
    • Enable Selected — Activate all selected webhooks
    • Disable Selected — Deactivate all selected webhooks without deleting them
    • Delete Selected — Permanently remove all selected webhooks and their delivery logs

After completing a bulk action, Linkzly displays a confirmation toast showing how many webhooks were updated successfully.


18.10 Webhook Templates

Linkzly provides built-in templates to quickly create webhooks pre-configured for common integration patterns. Click the Templates button in the top-right of the Webhooks page to browse available templates.

Available templates include:

  • Slack Notifications — Send Linkzly events to a Slack channel
  • Discord Webhook — Post events to a Discord server
  • Analytics Webhook — Forward events to an analytics platform
  • Team Notifications — Notify on team membership changes
  • Domain Management — Alert on domain verification events
  • Complete Activity Stream — Subscribe to all available event types

Select a template and customize the URL and any other fields before saving.

Was this helpful?

Help us improve our documentation