RiftRift

Tracking

Webhooks

Receive real-time notifications when users click your links, when installs are attributed, and when conversions fire. Push events to Slack, your CRM, or any analytics pipeline.

Setup

1

Register a webhook

Provide an HTTPS URL and the event types you want to receive. Supported events: click, attribution, and conversion.

curl -X POST https://api.riftl.ink/v1/webhooks \
  -H "Authorization: Bearer rl_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourserver.com/rift-webhook",
    "events": ["click", "attribution", "conversion"]
  }'

Response:

{
  "id": "6650a1b2c3d4e5f6a7b8c9d0",
  "url": "https://yourserver.com/rift-webhook",
  "events": ["click", "attribution", "conversion"],
  "secret": "a1b2c3d4...64-char-hex-string",
  "created_at": "2026-03-24T12:00:00Z"
}
Important: Save the secret immediately — it is only returned once at creation time. You'll use it to verify webhook signatures.
2

List your webhooks

curl https://api.riftl.ink/v1/webhooks \
  -H "Authorization: Bearer rl_live_YOUR_KEY"

The list response omits the secret field for security.

3

Delete a webhook

curl -X DELETE https://api.riftl.ink/v1/webhooks/WEBHOOK_ID \
  -H "Authorization: Bearer rl_live_YOUR_KEY"

Event payloads

4

Click event

Sent when a user clicks or resolves one of your links:

{
  "event": "click",
  "timestamp": "2026-03-24T15:00:00Z",
  "data": {
    "tenant_id": "6650a1b2c3d4e5f6a7b8c9d0",
    "link_id": "summer-sale",
    "user_agent": "Mozilla/5.0 ...",
    "referer": "https://twitter.com",
    "platform": "ios",
    "timestamp": "2026-03-24T15:00:00Z"
  }
}
5

Attribution event

Sent when an install is attributed to one of your links:

{
  "event": "attribution",
  "timestamp": "2026-03-24T15:05:00Z",
  "data": {
    "tenant_id": "6650a1b2c3d4e5f6a7b8c9d0",
    "link_id": "summer-sale",
    "install_id": "device-uuid-123",
    "app_version": "1.2.0",
    "timestamp": "2026-03-24T15:05:00Z"
  }
}
6

Conversion event

Sent when a conversion event is ingested via a source. Includes a stable event_id for customer-side dedup on retry — use it as the idempotency key in your handler.

{
  "event": "conversion",
  "timestamp": "2026-03-24T15:10:00Z",
  "data": {
    "event_id": "66a1b2c3d4e5f6a7b8c9d0e1",
    "tenant_id": "6650a1b2c3d4e5f6a7b8c9d0",
    "source_id": "66a1b2c3d4e5f6a7b8c9d0e2",
    "link_id": "summer-sale",
    "conversion_type": "deposit",
    "user_id": "usr_abc123",
    "amount_cents": 10000,
    "currency": "usd",
    "metadata": { "tx_hash": "0xabc..." },
    "timestamp": "2026-03-24T15:10:00Z"
  }
}
Note: amount_cents and currency are only present for revenue-bearing conversion types. Non-revenue events (e.g. signup, tutorial_complete) omit them.

Verifying signatures

7

Validate the HMAC signature

Every webhook request includes an X-Rift-Signature header containing an HMAC-SHA256 hex digest of the raw request body, signed with your webhook secret.

import hmac, hashlib

def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)
const crypto = require("crypto");

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

Limits & retry behavior

  • Maximum 2 webhooks per tenant.
  • Webhook URLs must use HTTPS.
  • Failed deliveries are retried 4 times with exponential backoff (0s, 1s, 5s, 25s).
  • Delivery timeout is 10 seconds per attempt.
  • Delivery is fire-and-forget — it does not block the API response to the original request.
Note: Webhook delivery is best-effort. For zero-loss reconciliation, pull from GET /v1/links/{link_id}/stats on a schedule — events are the durable source of truth inside Rift's store. The webhook is a push notification for convenience, not the canonical data path.