BlogEngineering
Engineering

Building an install-attribution pipeline with webhooks

Stream install.attributed events into your warehouse, verify the signatures, and reconcile probabilistic, deterministic, and SKAN in one place.

LTLinkTrail TeamEngineeringMay 28, 2026·9 min read

Polling an attribution API on a cron is how you end up with a pipeline that's always a few minutes stale and occasionally hammering an endpoint for data that hasn't changed. If you want attribution in your warehouse as it happens, let the platform push it to you.

Subscribe to the events that matter

Register an HTTPS endpoint and subscribe to the lifecycle you care about — typically install attribution and any later re-attribution. Each delivery is a self-contained record of how an install was matched.

{
  "event": "install.attributed",
  "installId": "inst_9f2",
  "matchType": "fingerprint",
  "score": 0.82,
  "channel": "tiktok",
  "deepLinkPath": "/promo/summer",
  "customData": { "code": "SUMMER50" }
}

Verify the signature — against the raw body

A webhook endpoint is a public URL accepting state-changing data, so authenticate every delivery. Compute an HMAC over the exact bytes you received and compare in constant time. The most common bug here is verifying after a JSON middleware has re-serialized the body, which changes the bytes and breaks the signature.

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: string, signature: string, secret: string) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

Land it idempotently

  • Key rows on installId so a retried delivery updates rather than duplicates.
  • Store matchType and score as columns, never collapsed into a single attributed flag.
  • Keep the raw payload too — schemas evolve, and you'll want to re-derive metrics later.

Reconcile the three sources of truth

Webhooks give you deterministic and probabilistic matches in real time; SKAN postbacks arrive later, aggregated and delayed. Land all three in the same schema, reconcile on a stable window, and always be able to answer 'which source said so' for any number on the dashboard.

Ingest the raw postback yourself, store it forever, and reconcile. A vendor's summarized report is a starting hypothesis, not the truth.
Tagged#Webhooks#Data engineering#Attribution