Skip to main content
Webhooks provide real-time notifications when users earn rewards in Nudj, enabling immediate delivery to your external systems. This technical guide covers webhook setup, security, testing, and troubleshooting for reward notifications.
Quick Start: For comprehensive reward integration patterns, see Reward Integration & Delivery. This guide focuses specifically on webhook implementation details.

Webhook Overview

Nudj’s webhook system sends HTTP POST requests to your endpoint whenever reward-related events occur, providing instant notification for reward processing.

Real-Time Delivery

Instant NotificationsReceive reward events within milliseconds of occurrence for immediate user gratification.

Secure & Reliable

Enterprise SecurityHMAC-SHA256 signature verification and automatic retry logic with exponential backoff.

Comprehensive Events

Rich Event DataDetailed event payloads with user context, reward details, and challenge information.

Webhook Events

Nudj provides different event types for comprehensive reward tracking:
  • Core Reward Events
  • Extended Events
Primary events for reward processing:
Triggered when: User completes a challenge and earns a reward
{
  "event": "reward.earned",
  "timestamp": "2024-02-15T14:30:00.000Z",
  "data": {
    "reward": {
      "id": "reward_abc123",
      "type": "asset",
      "category": "loyalty_points",
      "value": 100,
      "currency": "GBP",
      "name": "Weekly Challenge Bonus"
    },
    "user": {
      "id": "user_xyz789",
      "email": "user@example.com",
      "external_id": "customer_456"
    },
    "challenge": {
      "id": "challenge_def456",
      "name": "Weekly Shopping Challenge"
    }
  }
}

Webhook Configuration

Setting Up Webhooks in Nudj Admin

1

Access Webhook Settings

Navigate to Settings → Integrations → Webhooks in your Nudj admin panel.
2

Create New Webhook

Configure your webhook endpoint:
{
  "endpoint_url": "https://your-api.com/webhooks/nudj/rewards",
  "events": [
    "reward.earned",
    "reward.delivered",
    "reward.delivery_failed"
  ],
  "authentication": {
    "method": "hmac_sha256",
    "secret": "your-webhook-signing-secret"
  },
  "retry_policy": {
    "max_retries": 3,
    "initial_delay": 1000,
    "backoff_multiplier": 2
  },
  "timeout": 30000,
  "active": true
}

Endpoint Implementation

  • Node.js / Express
  • Python / Flask
Complete webhook endpoint with security and error handling:
const express = require('express');
const crypto = require('crypto');
const app = express();

// Middleware for raw body (needed for signature verification)
app.use('/webhooks', express.raw({ type: 'application/json' }));

// Webhook endpoint
app.post('/webhooks/nudj/rewards', async (req, res) => {
  try {
    const payload = JSON.parse(req.body.toString());
    const signature = req.headers['x-nudj-signature'];
    
    // Verify webhook signature
    if (!verifySignature(req.body, signature)) {
      return res.status(401).json({ error: 'Unauthorized' });
    }
    
    // Process the webhook event
    await processWebhookEvent(payload);
    
    // Respond quickly to Nudj
    res.status(200).json({ 
      success: true, 
      processed_at: new Date().toISOString() 
    });
    
  } catch (error) {
    console.error('Webhook processing failed:', error);
    res.status(500).json({ error: 'Processing failed' });
  }
});

function verifySignature(rawBody, signature) {
  const expectedSignature = crypto
    .createHmac('sha256', process.env.NUDJ_WEBHOOK_SECRET)
    .update(rawBody)
    .digest('hex');
  
  return signature?.replace('sha256=', '') === expectedSignature;
}

Security Implementation

Signature Verification

Webhook security relies on HMAC-SHA256 signature verification:
function verifyWebhookSignature(rawBody, signature, secret) {
  // Generate expected signature
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  
  // Extract received signature (remove 'sha256=' prefix)
  const receivedSignature = signature?.replace('sha256=', '');
  
  // Use timing-safe comparison
  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature, 'hex'),
    Buffer.from(receivedSignature, 'hex')
  );
}

Testing Webhooks

Local Development Testing

1

Set Up Local Tunnel

Use ngrok to expose your local webhook endpoint:
# Install ngrok
npm install -g ngrok

# Start your local server
node webhook-server.js  # Running on port 3000

# Create tunnel
ngrok http 3000

# Use the HTTPS URL in Nudj admin
2

Test with Sample Data

Test with curl:
curl -X POST https://your-tunnel.ngrok.io/webhooks/nudj/rewards \
  -H "Content-Type: application/json" \
  -H "X-Nudj-Signature: sha256=test_signature" \
  -d '{
    "event": "reward.earned",
    "data": {
      "reward": {"id": "test_reward_123", "value": 100},
      "user": {"id": "test_user_456", "external_id": "customer_789"}
    }
  }'

Troubleshooting

Common causes and diagnostic steps:
  • URL Accessibility: Is the webhook URL accessible from the internet?
  • SSL Certificate: Is HTTPS properly configured?
  • Firewall/Security: Are inbound HTTPS requests allowed?
  • Response Time: Does endpoint respond within 30 seconds?
# Test URL accessibility
curl -I https://your-api.com/webhooks/nudj/rewards
Debug signature verification:
function debugSignatureVerification(rawBody, signature, secret) {
  console.log('Raw Body Length:', rawBody.length);
  console.log('Received Signature:', signature);
  
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  
  console.log('Expected Signature:', expectedSignature);
  console.log('Signatures Match:', signature?.replace('sha256=', '') === expectedSignature);
}

Next Steps

I