SnipyDevelopers
Webhooks

Webhooks Guide

Receive real-time HTTP POST notifications when events happen in your Snipy account. Subscribe to any of our 15 event types and build reactive integrations.

Setup

1. Create a webhook endpoint

Set up an HTTPS endpoint on your server that can receive POST requests. The endpoint must return a 2xx status code within 10 seconds to acknowledge receipt.

Express.js handler
app.post("/webhook", (req, res) => {
  const signature = req.headers["x-snipy-signature"];
  const payload = JSON.stringify(req.body);

  // Verify signature
  const expected = crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(payload)
    .digest("hex");

  if (signature !== expected) {
    return res.status(401).send("Invalid signature");
  }

  const event = req.body;
  console.log("Received:", event.event, event.data);

  // Handle the event
  switch (event.event) {
    case "link.clicked":
      // Track click
      break;
    case "subscriber.added":
      // Sync to CRM
      break;
  }

  res.status(200).send("OK");
});

2. Subscribe to events

Use the API to create a webhook subscription with the events you want to listen for.

cURL
curl -X POST https://api.snipy.com/api/webhooks/subscribe \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourserver.com/webhook",
    "events": ["link.clicked", "link.created", "subscriber.added"],
    "secret": "whsec_your_signing_secret"
  }'

3. Verify signatures

Every webhook payload is signed with your secret using HMAC-SHA256. The signature is sent in the X-Snipy-Signature header. Always verify signatures to ensure payloads are authentic.

Python verification
import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

Retry policy

If your endpoint does not return a 2xx response within 10 seconds, the webhook delivery is retried with exponential backoff:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry (final)24 hours

After 5 failed attempts, the webhook subscription is automatically deactivated. You can reactivate it from the dashboard or via the API.

Payload format

All webhook payloads follow a consistent structure with the event type, timestamp, and event-specific data.

General structure
{
  "event": "event.type",
  "timestamp": "2026-03-04T12:00:00Z",
  "data": {
    // Event-specific fields
  }
}
Headers sent with every webhook:
HeaderDescription
Content-Typeapplication/json
X-Snipy-SignatureHMAC-SHA256 signature of the raw payload body
X-Snipy-EventEvent type (e.g. link.clicked)
X-Snipy-DeliveryUnique delivery ID for deduplication

Event types

Below are all 15 supported event types with example payloads.

qr.created

Fired when a new QR code is generated.

Example payload
{
  "event": "qr.created",
  "timestamp": "2026-03-04T12:10:00Z",
  "data": {
    "id": 78,
    "name": "Product QR",
    "linkedUrl": "https://snipy.to/product",
    "userId": 42
  }
}
qr.scanned

Fired when a QR code is scanned (triggers alongside link.clicked for the linked URL).

Example payload
{
  "event": "qr.scanned",
  "timestamp": "2026-03-04T13:00:00Z",
  "data": {
    "qrId": 78,
    "linkId": 456,
    "country": "US",
    "browser": "Safari",
    "platform": "iOS"
  }
}
bio.viewed

Fired when a bio profile page receives a view.

Example payload
{
  "event": "bio.viewed",
  "timestamp": "2026-03-04T15:00:00Z",
  "data": {
    "bioId": 12,
    "slug": "johndoe",
    "country": "GB",
    "referrer": "google.com"
  }
}
bio.updated

Fired when a bio profile's content or settings are changed.

Example payload
{
  "event": "bio.updated",
  "timestamp": "2026-03-04T16:00:00Z",
  "data": {
    "bioId": 12,
    "slug": "johndoe",
    "changes": ["blocks", "theme"],
    "userId": 42
  }
}
subscriber.added

Fired when a new subscriber signs up through a bio newsletter block.

Example payload
{
  "event": "subscriber.added",
  "timestamp": "2026-03-04T17:00:00Z",
  "data": {
    "bioId": 12,
    "email": "fan@example.com",
    "source": "newsletter_block"
  }
}
plan.upgraded

Fired when the user upgrades their subscription plan.

Example payload
{
  "event": "plan.upgraded",
  "timestamp": "2026-03-04T10:00:00Z",
  "data": {
    "userId": 42,
    "previousPlan": "Starter",
    "newPlan": "Pro",
    "billingCycle": "monthly"
  }
}
product.created

Fired when a new digital product is listed in the creator store.

Example payload
{
  "event": "product.created",
  "timestamp": "2026-03-04T11:00:00Z",
  "data": {
    "productId": 99,
    "name": "Social Media Template Pack",
    "price": 1999,
    "currency": "usd",
    "userId": 42
  }
}
product.purchased

Fired when a customer purchases a digital product.

Example payload
{
  "event": "product.purchased",
  "timestamp": "2026-03-04T18:00:00Z",
  "data": {
    "productId": 99,
    "buyerEmail": "buyer@example.com",
    "price": 1999,
    "currency": "usd",
    "sellerId": 42
  }
}
tip.received

Fired when a tip is received through a bio profile tip jar.

Example payload
{
  "event": "tip.received",
  "timestamp": "2026-03-04T19:00:00Z",
  "data": {
    "bioId": 12,
    "amount": 500,
    "currency": "usd",
    "tipper": "Anonymous",
    "message": "Great content!"
  }
}
verification.approved

Fired when a user's identity verification is approved.

Example payload
{
  "event": "verification.approved",
  "timestamp": "2026-03-04T09:00:00Z",
  "data": {
    "userId": 42,
    "verificationType": "identity",
    "verifiedAt": "2026-03-04T09:00:00Z"
  }
}
newsletter.sent

Fired when a newsletter is sent to bio subscribers.

Example payload
{
  "event": "newsletter.sent",
  "timestamp": "2026-03-04T20:00:00Z",
  "data": {
    "bioId": 12,
    "subject": "March Update",
    "recipientCount": 250,
    "userId": 42
  }
}