Skip to main content
Receive real-time HTTP notifications when loyalty events occur in your customers’ accounts. Stay in sync with customer activity on your platform.
Prerequisites: Your API key (zupy_pk_*). See Getting Started if you don’t have these yet.
Two webhook surfaces — make sure you’re on the right one. This page covers the outbound flow: Zupy → your system. There’s a separate inbound flow (your system → Zupy) where you push order/customer data for processing — see Webhook Setup (Inbound). The URLs are deliberately distinct:
  • 🟠 Outbound (this page): GET/PUT /api/v2/integrations/webhooks/ — you configure where Zupy should call.
  • 🟢 Inbound: POST /api/v2/webhooks/integrations/{partner}/ — you call this; Zupy ingests.
Integrating via OpenDelivery? Partners on the OpenDelivery standard receive a different outbound surface: the OD LoyaltyEventEnvelope with X-App-Id / X-App-MerchantId / X-App-Signature headers (HMAC hex without the sha256= prefix, signed with your OAuth2 client_secret). This page documents the native webhook format only — don’t mix the two verification schemes. If you enable both surfaces, you will receive the same fact twice (e.g. points.earned and loyalty.points.earned); pick one.

How It Works

Zupy sends an HTTP POST to your configured webhook URL whenever a loyalty event occurs:
  1. Event Occurs — Customer earns points, redeems a reward, coupon expires, etc.
  2. Sign — Event payload is signed with HMAC-SHA256 using your secret
  3. Send — HTTP POST to your webhook_url with signed payload
  4. Retry — If your server returns non-2xx, we retry with exponential backoff

Event Types

Setup

1

Configure your webhook URL

Use the webhook management API to set your endpoint:
The response includes your webhook_secret (masked). You’ll need this for signature verification.
2

Select events to receive

Choose which events trigger notifications. Leave empty to receive all events.Available events:
  • customer.enrolled
  • customer.tier_changed
  • points.earned
  • points.spent
  • reward.redeemed
  • coupon.used
  • coupon.cancelled
  • coupon.expiring
  • coupon.expired
3

Test your integration

Send a test ping to verify connectivity:
Response:
4

Verify signatures

Implement signature verification in your webhook handler (see below).

Payload Format

Every webhook POST contains a JSON payload with this structure:

Headers

Signature Verification

Verify the payload authenticity using HMAC-SHA256. This prevents spoofed requests.
Important: Use the raw request body bytes for verification — not the parsed JSON. The signature is computed over the exact bytes received.

Retry Behavior

If your server returns a non-2xx status code or times out, Zupy retries delivery:
  • Max delivery attempts: 4 (1 initial + 3 retries)
  • Timeout: 10 seconds per attempt
  • Backoff: Exponential base-4 (1s, 4s, 16s)
  • After exhaustion: Event is marked as exhausted and not retried again
Always respond with 2xx within 10 seconds. If you need longer processing, respond immediately and process asynchronously.

Idempotency

Use the X-Webhook-Id header to handle duplicate deliveries:
The same event may be delivered multiple times (due to retries). Always check X-Webhook-Id before processing.

Event Payloads

Triggered when a new customer joins a loyalty program.
Triggered when a customer’s points balance increases.
Triggered when a customer redeems a reward (coupon created).
Triggered when a coupon is validated or used at a store.
Triggered 3 days before a coupon expires.
Triggered when a customer moves loyalty tier.
Triggered when a customer’s points balance decreases.
Triggered when a coupon is cancelled.
Triggered when a coupon passes its expiration date.

Best Practices

Respond quickly

Always return 2xx within 10 seconds. If you need longer processing, respond immediately and process asynchronously.

Verify signatures

Never process a webhook without verifying the signature first. This prevents spoofed requests.

Use X-Webhook-Id for deduplication

Store processed webhook IDs and skip duplicates. Retries may send the same event multiple times.

Return 2xx even for async processing

As long as you received the webhook, return 2xx. Don’t wait for your downstream processing to complete.

Log failed verifications

Keep logs of failed signature verifications for debugging security issues.

Webhook Management API Reference

Get Webhook Configuration

Response:

Update Webhook Configuration

Request Body:
Response:

Test Webhook Delivery

Response: