Back

Webhooks

Set up real-time event notifications for wallet card activities

Webhooks

Webhooks allow you to receive real-time notifications when events occur in your WalletWerk account. This enables you to keep your systems in sync without polling the API.

Setting Up Webhooks

  1. Create a Webhook Endpoint

    • Log in to your dashboard
    • Navigate to DeveloperWebhooks
    • Click Add Webhook
    • Enter your endpoint URL (must be HTTPS in production)
    • Select which events to subscribe to
    • Copy and securely store your signing secret
      You'll only see it once!
  2. Verify Webhook Signatures

    All webhook payloads include a signature in the X-WalletWerk-Signature header. You must verify this signature to ensure the request is from WalletWerk.

    How it works:

    • WalletWerk sends the raw JSON body (as a string) and a signature header
    • You compute an HMAC-SHA256 hash of the raw JSON body using your secret
    • Compare your computed hash with the signature in the header
    • If they match, the webhook is authentic

    Important: You must use the raw JSON body (as received, before parsing), not the parsed JSON object. The signature is computed from the exact bytes of the request body.

    Common Mistakes:

    • ❌ Parsing JSON before verifying the signature
    • ❌ Using req.body after JSON parsing (Express) or request.json (Flask) instead of raw body
    • ❌ Not using constant-time comparison (vulnerable to timing attacks)
    • ✅ Always verify the signature using the raw request body string

When We Send Events

WalletWerk sends webhook events when:

  • A wallet card is created, updated, or changes status
  • A recipient is added, invited, or updated
  • A campaign is created or updated
  • A user adds or removes a card from their wallet
  • A card is revoked or expires

Event Types

Card Events

Response Fields

EventDescriptionWhen It's Triggered
card.createdWallet card createdWhen a card is successfully generated for a recipient
card.activeCard added to walletWhen a user adds the card to their Apple/Google wallet
card.updatedCard data updatedWhen card data changes (propagated to wallet)
card.removedCard removed from walletWhen a user deletes the card from their wallet
card.revokedCard revokedWhen you revoke a card via API or dashboard
card.expiredCard expiredWhen a card passes its expiration date

Recipient Events

Response Fields

EventDescriptionWhen It's Triggered
recipient.createdRecipient addedWhen a recipient is added to a campaign
recipient.invitedInvite sentWhen an invite is sent to a recipient
recipient.updatedRecipient updatedWhen recipient data is modified

Campaign Events

Response Fields

EventDescriptionWhen It's Triggered
campaign.createdCampaign createdWhen a new campaign is created
campaign.updatedCampaign updatedWhen campaign data is modified
campaign.completedCampaign completedWhen a campaign ends or is marked as completed

Event Payload

All webhook payloads follow this structure:

{
  "event": "card.active",
  "timestamp": "2025-12-09T10:30:00Z",
  "organization_id": 123,
  "data": {
    "card_id": "card_abc123",
    "recipient_id": "recipient_xyz789",
    "campaign_id": "campaign_def456",
    "provider": "apple",
    "old_status": "invited",
    "new_status": "active",
    "metadata": {}
  }
}

Status Fields in Webhook Payloads:

  • Card events (card.*): old_status and new_status show wallet card status changes (active, removed, revoked, expired)
  • Recipient events (recipient.*): old_status and new_status show recipient status changes (pending, created, invited, active, revoked, deleted)
  • Campaign events (campaign.*): Status fields may not be present

Verify Signatures

Every webhook request includes these headers:

Headers

HeaderDescription
X-WalletWerk-SignatureHMAC-SHA256 signature of the payload
X-WalletWerk-EventThe event type (e.g., card.active)
X-WalletWerk-TimestampISO 8601 timestamp of when the event occurred
X-WalletWerk-Delivery-IDUnique ID for this webhook delivery (for idempotency)
Content-TypeAlways application/json

See the Setting Up Webhooks section above for signature verification code examples.

Retry Behavior and Disabling

Retry Logic

WalletWerk will retry failed deliveries with exponential backoff:

  • First retry: 1 minute
  • Second retry: 5 minutes
  • Third retry: 15 minutes
  • Fourth retry: 1 hour
  • Maximum: 24 hours

Timeout

Webhook endpoints must respond within 30 seconds. If your endpoint doesn't respond within this time, WalletWerk will consider the delivery failed and retry.

Failure Handling

Webhooks are automatically disabled after 10 consecutive failures. You'll need to re-enable them from the dashboard.

Idempotency

Use the X-WalletWerk-Delivery-ID header to ensure idempotent processing. Each webhook delivery has a unique ID that you can use to prevent duplicate processing:

// Store processed delivery IDs
const processedIds = new Set();

app.post('/webhooks/walletwerk', express.raw({ type: 'application/json' }), (req, res) => {
  const deliveryId = req.headers['x-walletwerk-delivery-id'];
  
  // Check if we've already processed this delivery
  if (processedIds.has(deliveryId)) {
    return res.status(200).send('OK'); // Already processed
  }
  
  // Process the event...
  processedIds.add(deliveryId);
  res.status(200).send('OK');
});

Testing Webhooks

You can test your webhook endpoint from the dashboard:

  1. Navigate to DeveloperWebhooks
  2. Click the test button (send icon) next to your webhook
  3. A test payload will be sent to your endpoint with event type webhook.test

The test payload follows the same format as regular webhook events, allowing you to verify your signature verification and event handling logic.