Reward DNA Webhooks
Virtual Incentives supports webhooks to provide real-time notifications when key reward lifecycle events occur. These webhooks allow clients to stay up-to-date as rewards move through their lifecycle from order creation to email or SMS delivery to activation. Webhooks are managed within our VI Now client portal.
Webhooks require approval prior to access. Please contact your Virtual Incentives Account Manager to discuss your use case.
Getting Started
To manage your webhooks:
- Log in to VI Now.
- Navigate to the Webhooks section.
- Use the management interface to:
- Register endpoints to receive events
- Subscribe to specific event types
- View delivery logs
👤 An Admin must enable the Webhooks page in VI Now before users in the organization can access it.
Creating and Managing Endpoints
- In the Webhooks section, click Add Endpoint.
- Provide your endpoint URL and optional description.
- Optionally add custom headers.
- A signing secret will be generated for validating event signatures.
Subscribing to Events
You can subscribe to any combination of the following event types. This consolidated list reflects the order lifecycle, reward status updates, and payout events as used throughout the VI platform:
| Event Type | Description |
|---|---|
| order.created | A new order was successfully created. |
| order.processing | Order is currently being processed. |
| order.processed | Order has completed processing. |
| order.pending_funds | Order is awaiting client funding. |
| order.canceled | An order was canceled before fulfillment. |
| reward.activated.auto_activated | Reward was automatically activated. |
| reward.activated.instant_issue | Physical Instant Issue Visa card was activated via API. |
| reward.activated.phone | Reward was activated via phone. |
| reward.activated.web | Reward was activated online. |
| reward.cancel_fee | Fee charged for canceling a reward. |
| reward.cancel_reissue_fee | Fee charged for canceling and reissuing a reward. |
| reward.canceled | Reward was canceled after delivery. |
| reward.claimed | A recipient reveals their reward details, confirming successful delivery. |
| reward.credit_applied | Refund issued for a canceled reward. |
| reward.data_redacted.gdpr | Reward data redacted due to GDPR compliance. |
| reward.data_redacted.retention_policy | Reward data redacted per retention policy. |
| reward.delivery_failed | Delivery attempt failed (e.g., email or SMS undeliverable). |
| reward.delivery_failed.blacklisted | Delivery failed due to blacklisted recipient or domain. |
| reward.email.link_extended | Reward link expiration date was extended. |
| reward.email.resent | Reward email was resent. |
| reward.email.viewed | Reward email was viewed. |
| reward.extend_link_fee | Fee charged for extending reward link expiration. |
| reward.sms_resent | Reward SMS message was resent. |
| reward.link_clicked | Reward link was clicked. |
| reward.blocked_recipient_signals_fraud | Reward blocked due to potential fraud detected. |
| reward.idv.failed | Recipient failed identity verification. |
| reward.idv.passed | Recipient passed identity verification. |
| reward.multifactor_authentication.failed | MFA attempt failed. |
| reward.multifactor_authentication.reset | Reward flagged for MFA failure was reset. |
| reward.online_registration_completed | Recipient completed online account registration. |
| reward.reissued_reward | A reward was reissued. |
| reward.reminder_sent | Reminder sent for unclaimed reward. |
| reward.sent | Reward was successfully sent. |
| reward.sent.fm_override | Previously flagged reward was whitelisted and sent. |
| reward.card_shipped | A physical card was shipped. |
| reward.shipped_via_courier | Reward shipped using a courier service. |
| reward.recipient_reissue_fee | Fee charged for reissuing reward to recipient. |
| reward.payout.succeeded | PayPal or Venmo payout was successfully delivered. |
| reward.payout.unclaimed | PayPal or Venmo payout sent to unregistered recipient; awaiting claim. |
| reward.payout.held | PayPal or Venmo payout is under review and temporarily held. |
| reward.payout.denied | PayPal or Venmo payout was declined by the recipient. |
| reward.payout.blocked | PayPal or Venmo payout was blocked due to account or compliance issues. |
| reward.payout.refunded | PayPal or Venmo payout was refunded after being claimed. |
| reward.payout.returned | PayPal or Venmo payout was voided and funds returned. For Cash Payouts, this means the recipient-provided bank details were invalid; an email is sent for re-enter bank details. |
| reward.payout.failed | PayPal, Venmo, or Cash Payout attempt failed. |
| reward.payout.canceled | PayPal, Venmo, or Cash Payout was canceled prior to processing. |
| reward.payout.bank_account_linked | Cash Payout recipient entered bank account details. |
| reward.payout.sent | Cash Payout sent to the recipient's bank account. |
Viewing Logs
Navigate to the Logs tab within the Webhooks interface to:
- View webhook deliveries and retries
- Inspect request/response payloads
- Diagnose failed or delayed notifications
⏱️ Webhooks are retried automatically using exponential backoff.
📦Payload
Each webhook contains a JSON body with the following structure:
Example Webhook Payloads
{
"date": "06/17/2025 16:01:56",
"event": "reward.canceled",
"event_id": "339133515",
"note": "",
"recipient_id": "42498355",
"user": "John Smith"
}
{
"date": "06/17/2025 16:01:58",
"event": "reward.credit_applied",
"event_id": "339128032",
"note": "$10.00",
"recipient_id": "42498355",
"user": "John Smith"
}
Payload Fields
| Status | Type | Description |
|---|---|---|
| date | string | The date/time when the webhook event occurred |
| event | string | The event type (e.g., order.processed) |
| event_id | string | A unique identifier for this specific webhook event |
| note | string | Note added during a manually initiated event, or credit amount for reward cancelation. |
| recipient_id | string | Virtual Incentives unique identifier associated with the reward |
| user | string | Client user associated with a manually initiated event such as a cancelation |
🔐Webhook Signature Verification
Each webhook includes headers that allow you to verify the authenticity of the request using an HMAC-based signature.
Required Headers
| Header | Description |
|---|---|
| svix-id | Unique message ID |
| svix-timestamp | UNIX timestamp of when the webhook was sent |
| svix-signature | HMAC-SHA256 signature of the message payload |
How to Verify the Signature
- Concatenate the three values: svix-id, svix-timestamp, and the raw request body with a period (.) as a separator:
to_sign = svix-id + "." + svix-timestamp + "." + raw_body- Compute the HMAC SHA256 digest of to_sign using your secret key (provided to you by VI), and encode it as a Base64 string:
import hmac
import hashlib
import base64
secret = base64.b64decode("your-secret-here")
signature = base64.b64encode(
hmac.new(secret, to_sign.encode(), hashlib.sha256).digest()
).decode()- Compare this computed signature with the one in the svix-signature header. If they match, the webhook is authentic.
Security TipAlways check that svix-timestamp is recent (e.g., within 5 minutes) to protect against replay attacks.
Additional Resources
Verifying webhook payloads - If you prefer to use a library rather than implement the verification logic manually, this guide provides examples in multiple languages and frameworks:
IP Addresses for Whitelisting - Optionally whitelist IP addresses from which webhook events will be delivered. The only applicable IPs for Virtual Incentives are listed under "US".
🔄 Retry Behavior
If your server does not respond with a 2xx HTTP status code, we will retry the webhook several times with exponential backoff.
Ensure your endpoint can safely handle duplicate events.
✅ Security Best Practices
- Respond quickly with a
200 OKafter validating and logging the event. - Always validate the
svix-signature. - Store the latest
statusfor eachuuidto maintain a full verification history. - Secure your endpoint with HTTPS
- Limit IP access or implement token-based authentication where possible.
- Log and monitor webhook traffic for anomalies.
Updated about 13 hours ago