Skip to main content

Webhook Events API

Real-time HTTP notifications for customer, subscription, and loyalty events. Includes authentication, payload examples, and code samples.

Updated over 3 weeks ago

Webhook Events API

Subscribfy sends real-time HTTP POST notifications to your endpoints when events occur. Use webhooks to sync customer data, trigger automations, or integrate with third-party systems.


Authentication

Each webhook request is signed using HMAC SHA-256. Verify the signature to ensure requests originate from Subscribfy.

Header

Description

Signature

HMAC SHA-256 hash of the request body

x-subscribfy-triggered-at

Unix timestamp when event occurred

x-subscribfy-shop-domain

Your Shopify store domain

Subscribfy Token

Your unique secret token is used to sign all webhook requests. Generate it in Settings > Webhooks

  • Token is shown only once at generation - store it securely

  • If lost, regenerate a new token (invalidates the old one)

  • Never expose your token in client-side code


Signature Verification

PHP

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $payload, $subscribfyToken);if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}$event = json_decode($payload, true);

Node.js

const crypto = require('crypto');app.post('/webhook', (req, res) => {
    const signature = req.headers['signature'];
    const payload = JSON.stringify(req.body);
    const expected = crypto
        .createHmac('sha256', process.env.SUBSCRIBFY_TOKEN)
        .update(payload)
        .digest('hex');    if (signature !== expected) {
        return res.status(401).send('Invalid signature');
    }    // Process event
    const { topic, data } = req.body;
    console.log(`Received: ${topic}`);
    res.status(200).send('OK');
});

Python

import hmac
import hashlib
from flask import Flask, request@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('Signature', '')
    payload = request.get_data()
    expected = hmac.new(
        SUBSCRIBFY_TOKEN.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()    if not hmac.compare_digest(signature, expected):
        return 'Invalid signature', 401    event = request.get_json()
    return 'OK', 200


Configuration

  1. Go to Settings > Webhooks in the Subscribfy app

  2. Select the event category (Wallet Pass, Membership, etc.)

  3. Enter your endpoint URL(s) - separate multiple URLs with commas

  4. Click Test Call to verify your endpoint

  5. Click Save to activate


Event Reference

Wallet Pass Events

Topic

Trigger

wallet_pass/created

New wallet pass generated for customer

wallet_pass/updated

Pass content updated (points, rewards, tier)

wallet_pass/installed

Pass installed on customer's device

wallet_pass/removed

Pass removed/uninstalled from device

Membership Events

Topic

Trigger

membership/created

New membership contract created

membership/updated

Contract modified (frequency, next date)

membership/paused

Membership paused by customer or admin

membership/reactivated

Paused/cancelled membership resumed

membership/cancelled

Membership cancelled

membership/billing_success

Payment processed successfully

membership/billing_failure

Payment failed

membership/store_credits_changed

Customer store credits modified

Product Subscription Events

Topic

Trigger

subscription/created

New product subscription started

subscription/updated

Subscription modified (products, shipping, frequency)

subscription/paused

Subscription paused

subscription/reactivated

Subscription resumed

subscription/cancelled

Subscription cancelled

subscription/billing_success

Renewal payment successful

subscription/billing_failure

Renewal payment failed

Loyalty Events

Topic

Trigger

loyalty/rule_created

New loyalty rule created in admin

loyalty/rule_updated

Loyalty rule settings modified

loyalty/rule_completed

Customer completed a rule and earned reward

loyalty/tier_created

New tier created

loyalty/tier_updated

Tier settings modified

loyalty/tier_changed

Customer promoted to new tier

loyalty/tier_lost

Customer demoted from tier

loyalty/points_changed

Customer points earned, spent, or adjusted

loyalty/coupon_created

New coupon created

loyalty/coupon_redeemed

Customer redeemed a loyalty coupon


Payload Structure

All webhooks follow this structure:

{
    "topic": "event/type",
    "data": {
        "customer": { ... },
        // Event-specific data
    }
}

Customer Object

Included in all events:

"customer": {
    "id": "gid://shopify/Customer/123456789",
    "email": "customer@example.com",
    "name": "John Doe",
    "loyalty_points": 1250.00,
    "store_credits": 25.50,
    "birth_date": "1990-05-15",
    "tier": {
        "id": 1,
        "name": "Gold"
    }
} 

Example: Wallet Pass Created

{
    "topic": "wallet_pass/created",
    "data": {
        "pass_instance": {
            "status": "Active",
            "serial_number": "955773794",
            "created_at": "2026-01-22T10:30:00.000000Z",
            "deleted_at": null
        },
        "customer": {
            "id": "gid://shopify/Customer/424525265",
            "email": "john@example.com",
            "name": "John Doe",
            "loyalty_points": 500.00,
            "store_credits": 10.00,
            "tier": { "id": 2, "name": "Silver" }
        }
    }
}

Example: Membership Billing Success

{
    "topic": "membership/billing_success",
    "data": {
        "contract": {
            "id": "gid://shopify/SubscriptionContract/123",
            "status": "active",
            "next_billing_date": "2026-02-22",
            "billing_policy": {
                "interval": "month",
                "interval_count": 1
            }
        },
        "order": {
            "id": "gid://shopify/Order/456789",
            "total_price": "29.99",
            "currency": "USD"
        },
        "customer": {
            "id": "gid://shopify/Customer/123456",
            "email": "member@example.com",
            "name": "Jane Smith"
        }
    }
}

Example: Loyalty Points Changed

{
    "topic": "loyalty/points_changed",
    "data": {
        "change": {
            "previous_balance": 500,
            "new_balance": 750,
            "difference": 250,
            "reason": "Order completed",
            "rule_name": "Points per dollar spent"
        },
        "customer": {
            "id": "gid://shopify/Customer/789",
            "email": "loyal@example.com",
            "name": "Mike Johnson",
            "loyalty_points": 750.00,
            "tier": { "id": 3, "name": "Platinum" }
        }
    }
}

Request Details

Property

Value

Method

POST

Content-Type

application/json

Timeout

30 seconds

Retries

None (ensure your endpoint is reliable)


Best Practices

  • Respond quickly - Return 2xx status within 5 seconds, process asynchronously

  • Verify signatures - Always validate the Signature header

  • Handle duplicates - Use idempotency keys or check for duplicate events

  • Log everything - Store raw payloads for debugging

  • Use HTTPS - All webhook URLs must use HTTPS

  • Monitor failures - Set up alerts for failed webhook deliveries


Troubleshooting

Not receiving webhooks?
Verify your endpoint is publicly accessible and returns 2xx status. Check firewall rules.

Invalid signature errors?
Ensure you're using the raw request body (not parsed JSON) for HMAC calculation.

Missing events?
Check that the specific event type is enabled in Settings > Webhooks.

Test endpoint?
Use webhook.site or ngrok for local development testing.


Did this answer your question?