{"id":1119,"date":"2026-05-18T17:00:00","date_gmt":"2026-05-18T22:00:00","guid":{"rendered":"https:\/\/tolinku.com\/blog\/?p=1119"},"modified":"2026-03-07T03:34:45","modified_gmt":"2026-03-07T08:34:45","slug":"webhook-event-types","status":"publish","type":"post","link":"https:\/\/tolinku.com\/blog\/webhook-event-types\/","title":{"rendered":"Webhook Event Types for Deep Linking Platforms"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Every deep link interaction produces a trail of events. A user clicks a link. The app opens via deferred deep linking. A referral converts. Each of these moments is a discrete event type that your webhook endpoint can receive, parse, and act on.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you are new to webhooks in the deep linking context, start with <a href=\"https:\/\/tolinku.com\/blog\/webhooks-integrations-deep-linking\/\">Webhooks and Integrations for Deep Linking<\/a>, which covers the fundamentals of setting up webhook receivers and securing your endpoints. This article goes deeper into the individual event types: what each payload contains, when each event fires, and how to build handlers that route events to the right systems.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img decoding=\"async\" src=\"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/platform-webhooks.png\" alt=\"Tolinku webhook configuration for event notifications\">\n<em>The webhooks page with create form, webhook list, and delivery log.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Core Event Types<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Tolinku produces five webhook event types, each mapping to a specific moment in the user journey:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Event Type<\/th>\n<th>Fires When<\/th>\n<th>Typical Use<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td><code>link.clicked<\/code><\/td>\n<td>User taps or clicks a deep link<\/td>\n<td>Click analytics, campaign tracking<\/td>\n<\/tr>\n<tr>\n<td><code>deferred_link.claimed<\/code><\/td>\n<td>App claims a deferred deep link after install<\/td>\n<td>Attribution, onboarding flows<\/td>\n<\/tr>\n<tr>\n<td><code>install.tracked<\/code><\/td>\n<td>SDK reports a new app install<\/td>\n<td>User acquisition tracking, welcome sequences<\/td>\n<\/tr>\n<tr>\n<td><code>referral.created<\/code><\/td>\n<td>A new referral link is generated<\/td>\n<td>Referral program monitoring<\/td>\n<\/tr>\n<tr>\n<td><code>referral.completed<\/code><\/td>\n<td>A referred user reaches the reward milestone<\/td>\n<td>Reward fulfillment, referral analytics<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Not every integration needs all five. A basic analytics sync might only subscribe to <code>link.clicked<\/code> and <code>install.tracked<\/code>. A referral program needs <code>referral.created<\/code> and <code>referral.completed<\/code>. The key is subscribing only to what you will actually process, which reduces noise and keeps your handler focused.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tolinku lets you select exactly which event types each webhook endpoint receives. See the <a href=\"https:\/\/tolinku.com\/docs\/user-guide\/webhooks\/event-types\/\">webhook event types documentation<\/a> for the full reference.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Payload Structure<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">All webhook deliveries share a common envelope structure. Tolinku sends each event as an HTTP POST with these headers:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Header<\/th>\n<th>Value<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td><code>Content-Type<\/code><\/td>\n<td><code>application\/json<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>X-Webhook-Signature<\/code><\/td>\n<td>HMAC-SHA256 hex signature<\/td>\n<\/tr>\n<tr>\n<td><code>X-Webhook-Event<\/code><\/td>\n<td>The event type string (e.g., <code>link.clicked<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><code>User-Agent<\/code><\/td>\n<td><code>Tolinku\/1.0<\/code><\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Every payload follows this envelope:<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;event&quot;: &quot;link.clicked&quot;,\n  &quot;timestamp&quot;: &quot;2026-05-17T09:41:22.318Z&quot;,\n  &quot;data&quot;: { }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>event<\/code> field tells your handler which type of event arrived. The <code>timestamp<\/code> is ISO 8601 in UTC. The <code>data<\/code> object contains event-specific fields.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Event Payloads in Detail<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">link.clicked<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is the highest-volume event. It fires every time a user clicks or taps a deep link.<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;event&quot;: &quot;link.clicked&quot;,\n  &quot;timestamp&quot;: &quot;2026-05-17T09:41:22.318Z&quot;,\n  &quot;data&quot;: {\n    &quot;prefix&quot;: &quot;promo&quot;,\n    &quot;token&quot;: &quot;summer-sale&quot;,\n    &quot;hostname&quot;: &quot;links.yourapp.com&quot;,\n    &quot;ip&quot;: &quot;203.0.113.42&quot;,\n    &quot;platform&quot;: &quot;ios&quot;,\n    &quot;device_type&quot;: &quot;mobile&quot;,\n    &quot;campaign&quot;: &quot;summer2026&quot;\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Click events are the raw material for campaign dashboards. The <code>prefix<\/code> and <code>token<\/code> fields identify which route was clicked (e.g., <code>\/promo\/summer-sale<\/code>). The <code>platform<\/code> field tells you whether the click came from iOS, Android, or web. The <code>campaign<\/code> field is populated from the <code>utm_campaign<\/code> query parameter on the link, which is useful for tying clicks back to specific marketing campaigns.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">deferred_link.claimed<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Fires when the app SDK claims a deferred deep link after a new install. This confirms that the user installed the app, opened it, and was matched back to the original click.<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;event&quot;: &quot;deferred_link.claimed&quot;,\n  &quot;timestamp&quot;: &quot;2026-05-17T10:03:47.892Z&quot;,\n  &quot;data&quot;: {\n    &quot;deep_link_path&quot;: &quot;\/promo\/summer-sale&quot;,\n    &quot;method&quot;: &quot;token&quot;,\n    &quot;ip&quot;: &quot;203.0.113.42&quot;\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>method<\/code> field indicates how the deferred link was resolved. A value of <code>token<\/code> means the link was claimed using an explicit deferred link token. A value of <code>signals<\/code> means the platform matched the user using device signals (fingerprinting). This distinction is useful for understanding your attribution quality: token-based matches are deterministic, while signal-based matches are probabilistic.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">install.tracked<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Fires when the SDK reports a new app install. This event is distinct from <code>deferred_link.claimed<\/code> because it fires for all installs that hit your deep link domain, not just those that claim a deferred link.<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;event&quot;: &quot;install.tracked&quot;,\n  &quot;timestamp&quot;: &quot;2026-05-17T10:01:15.204Z&quot;,\n  &quot;data&quot;: {\n    &quot;hostname&quot;: &quot;links.yourapp.com&quot;,\n    &quot;ip&quot;: &quot;203.0.113.42&quot;,\n    &quot;platform&quot;: &quot;android&quot;,\n    &quot;device_type&quot;: &quot;mobile&quot;,\n    &quot;campaign&quot;: &quot;summer2026&quot;\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Install events are high-value because they represent new user acquisition. The payload includes the same platform and campaign fields as click events, letting you attribute installs back to the originating campaign.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">referral.created<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Fires when a new referral link is generated through the SDK. This tells you a user has entered your referral program.<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;event&quot;: &quot;referral.created&quot;,\n  &quot;timestamp&quot;: &quot;2026-05-17T14:22:10.553Z&quot;,\n  &quot;data&quot;: {\n    &quot;referral_code&quot;: &quot;ABC123&quot;,\n    &quot;referrer_id&quot;: &quot;user_789&quot;,\n    &quot;referral_url&quot;: &quot;https:\/\/links.yourapp.com\/ref\/ABC123&quot;\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Use this event to track referral program participation rates. The <code>referral_code<\/code> is the unique code assigned to the referrer. The <code>referral_url<\/code> is the full deep link URL that the referrer can share.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">referral.completed<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Fires when a referred user reaches the reward milestone defined in your <a href=\"https:\/\/tolinku.com\/features\/webhooks\">referral program configuration<\/a>. This is the trigger for issuing rewards.<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;event&quot;: &quot;referral.completed&quot;,\n  &quot;timestamp&quot;: &quot;2026-05-17T15:10:33.204Z&quot;,\n  &quot;data&quot;: {\n    &quot;referral_code&quot;: &quot;ABC123&quot;,\n    &quot;referrer_id&quot;: &quot;user_789&quot;,\n    &quot;referred_user_id&quot;: &quot;user_456&quot;,\n    &quot;milestone&quot;: &quot;completed&quot;\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>referrer_id<\/code> and <code>referred_user_id<\/code> fields let you credit both sides of the referral. The <code>milestone<\/code> field indicates which milestone was reached, corresponding to the milestones you configured in your Appspace&#39;s referral settings.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building an Event Handler<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A practical webhook handler needs to do three things: verify the signature, route events to the correct processing logic, and respond quickly. Tolinku enforces a 10-second delivery timeout; if your endpoint takes longer, the delivery is marked as failed and retried.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here is a complete handler in Node.js with <a href=\"https:\/\/expressjs.com\/\" rel=\"nofollow noopener\" target=\"_blank\">Express<\/a>:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">import express from &quot;express&quot;;\nimport crypto from &quot;crypto&quot;;\n\nconst app = express();\napp.use(&quot;\/webhooks&quot;, express.raw({ type: &quot;application\/json&quot; }));\n\nconst WEBHOOK_SECRET = process.env.TOLINKU_WEBHOOK_SECRET; \/\/ whsec_...\n\nfunction verifySignature(payload, signature) {\n  const expected = crypto\n    .createHmac(&quot;sha256&quot;, WEBHOOK_SECRET)\n    .update(payload)\n    .digest(&quot;hex&quot;);\n  const sig = Buffer.from(signature, &quot;hex&quot;);\n  const exp = Buffer.from(expected, &quot;hex&quot;);\n  if (sig.length !== exp.length) return false;\n  return crypto.timingSafeEqual(sig, exp);\n}\n\n\/\/ Event handlers mapped by type\nconst handlers = {\n  &quot;link.clicked&quot;: handleClick,\n  &quot;deferred_link.claimed&quot;: handleDeferredClaim,\n  &quot;install.tracked&quot;: handleInstall,\n  &quot;referral.created&quot;: handleReferralCreated,\n  &quot;referral.completed&quot;: handleReferralCompleted,\n};\n\napp.post(&quot;\/webhooks\/tolinku&quot;, async (req, res) =&gt; {\n  const signature = req.headers[&quot;x-webhook-signature&quot;];\n\n  if (!signature || !verifySignature(req.body, signature)) {\n    return res.status(401).json({ error: &quot;Invalid signature&quot; });\n  }\n\n  const event = JSON.parse(req.body.toString());\n\n  \/\/ Respond immediately, process async\n  const handler = handlers[event.event];\n  if (handler) {\n    res.status(200).json({ status: &quot;accepted&quot; });\n    handler(event).catch(console.error);\n  } else {\n    res.status(200).json({ status: &quot;unhandled&quot; });\n  }\n});\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The handler responds with <code>200<\/code> before processing the event. Tolinku retries failed deliveries on a schedule of 1 minute, 5 minutes, and 30 minutes, so you may receive duplicates if your endpoint is temporarily unavailable. Build your handlers to be idempotent: processing the same event twice should produce the same result as processing it once.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For idempotency, you can hash the event payload (since the envelope does not include a unique event ID) and store processed hashes in Redis or your database:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">async function isDuplicate(event) {\n  const hash = crypto\n    .createHash(&quot;sha256&quot;)\n    .update(JSON.stringify(event))\n    .digest(&quot;hex&quot;);\n  const exists = await redis.get(`webhook:${hash}`);\n  if (exists) return true;\n  await redis.set(`webhook:${hash}`, &quot;1&quot;, &quot;EX&quot;, 86400); \/\/ 24h TTL\n  return false;\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Integration Patterns<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Analytics Sync<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Push click and install data to your analytics warehouse:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">async function handleClick(event) {\n  await analyticsDB.insert(&quot;deep_link_clicks&quot;, {\n    prefix: event.data.prefix,\n    token: event.data.token,\n    campaign: event.data.campaign,\n    platform: event.data.platform,\n    device_type: event.data.device_type,\n    timestamp: event.timestamp,\n  });\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">CRM Updates<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Update user profiles when installs arrive:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">async function handleInstall(event) {\n  await crm.createOrUpdate({\n    source: &quot;deep_link&quot;,\n    campaign: event.data.campaign,\n    platform: event.data.platform,\n    first_seen: event.timestamp,\n  });\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Referral Reward Fulfillment<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Trigger rewards when referrals complete:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">async function handleReferralCompleted(event) {\n  await rewardService.issueReward(event.data.referrer_id, {\n    type: &quot;referral_bonus&quot;,\n    referred_user: event.data.referred_user_id,\n    milestone: event.data.milestone,\n  });\n\n  await slack.send(&quot;#referrals&quot;, {\n    text: `Referral ${event.data.referral_code} completed. ` +\n          `${event.data.referrer_id} referred ${event.data.referred_user_id}.`,\n  });\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Choosing Which Events to Subscribe To<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When creating a webhook in Tolinku, you select exactly which event types your endpoint should receive. The webhook creation form lets you check or uncheck individual event types.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here is a decision framework:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Subscribe to <code>link.clicked<\/code> if<\/strong> you need real-time click analytics, want to detect click fraud, or need to trigger actions immediately on link interaction.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Subscribe to <code>deferred_link.claimed<\/code> if<\/strong> you are building onboarding flows that depend on the original deep link context, or need to track deferred deep link attribution quality.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Subscribe to <code>install.tracked<\/code> if<\/strong> you are tracking user acquisition, attributing installs to campaigns, or triggering welcome sequences for users who arrived via deep links.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Subscribe to <code>referral.created<\/code> if<\/strong> you are monitoring referral program participation, tracking how many users generate referral links, or syncing referral data to external CRM systems.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Subscribe to <code>referral.completed<\/code> if<\/strong> you are fulfilling referral rewards, tracking referral conversion rates, or notifying teams when referrals convert.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you are just getting started, begin with <code>link.clicked<\/code> and <code>install.tracked<\/code>. These two events give you the most actionable data with the least handler complexity. Add referral events as your integration matures.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Error Handling and Retry Logic<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Webhook deliveries can fail. Your server might be down, or a transient database error might cause a 500 response. Tolinku retries failed deliveries up to three times with increasing delays: 1 minute, 5 minutes, and 30 minutes after the initial failure. Your handler needs to be resilient to duplicates and graceful with errors.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A defensive handler wraps processing in a try\/catch and logs failures without crashing:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">app.post(&quot;\/webhooks\/tolinku&quot;, async (req, res) =&gt; {\n  \/\/ ... signature verification ...\n\n  const event = JSON.parse(req.body.toString());\n  res.status(200).json({ status: &quot;accepted&quot; });\n\n  try {\n    const handler = handlers[event.event];\n    if (handler) await handler(event);\n  } catch (err) {\n    console.error(`Failed to process ${event.event}:`, err);\n    \/\/ Queue for retry via your own job system\n    await retryQueue.add({ event, attempts: 0 });\n  }\n});\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Always respond with <code>200<\/code> before processing. If you respond with a non-2xx status, the platform will retry, and you could end up processing the event multiple times once your system recovers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Next Steps<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Webhook event types are the building blocks of a connected deep linking system. Each event type represents a specific moment in the user journey, and each carries the data you need to act on that moment. Start with the events that map to your most important business metrics, build handlers that are idempotent and fast, and expand your subscriptions as your integration needs grow.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To configure <a href=\"https:\/\/tolinku.com\/features\/webhooks\">webhooks<\/a> in your Tolinku Appspace, visit the webhook settings page and select the event types you need. The <a href=\"https:\/\/tolinku.com\/docs\/user-guide\/webhooks\/event-types\/\">event types documentation<\/a> has the full payload reference for each type.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Understand webhook event types for deep linking. Learn which events to subscribe to and how to handle click, install, and referral payloads.<\/p>\n","protected":false},"author":2,"featured_media":1118,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Webhook Event Types for Deep Linking Platforms","rank_math_description":"Understand webhook event types for deep linking. Learn which events to subscribe to and how to handle click, install, and referral payloads.","rank_math_focus_keyword":"webhook event types","rank_math_canonical_url":"","rank_math_facebook_title":"","rank_math_facebook_description":"","rank_math_facebook_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-webhook-event-types.png","rank_math_facebook_image_id":"","rank_math_twitter_title":"","rank_math_twitter_description":"","rank_math_twitter_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-webhook-event-types.png","footnotes":""},"categories":[15],"tags":[37,62,20,264,265,263,69,61],"class_list":["post-1119","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering","tag-analytics","tag-api","tag-deep-linking","tag-engineering","tag-events","tag-integrations","tag-mobile-development","tag-webhooks"],"_links":{"self":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1119","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/comments?post=1119"}],"version-history":[{"count":2,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1119\/revisions"}],"predecessor-version":[{"id":2250,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1119\/revisions\/2250"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media\/1118"}],"wp:attachment":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media?parent=1119"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/categories?post=1119"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/tags?post=1119"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}