> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nudj.cx/llms.txt
> Use this file to discover all available pages before exploring further.

# Recipe Library

> Ready-to-use webhook integration patterns and code examples

## Recipe Library Overview

Pre-built webhook integration patterns for common use cases. Each recipe includes complete code examples and deployment instructions.

## Recipe: Slack Notification Bot

Send real-time Slack notifications when users complete challenges or earn rewards.

<Tabs>
  <Tab title="Setup">
    ### Prerequisites

    * Slack workspace with incoming webhooks enabled
    * Slack webhook URL from your workspace settings

    ### Configuration

    1. Get your Slack webhook URL from Slack App settings
    2. Configure Nudj webhook to point to your handler
    3. Deploy the handler code below
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    const express = require('express');
    const axios = require('axios');
    const app = express();

    const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL;
    const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

    app.post('/webhooks/nudj', express.json(), async (req, res) => {
      // Verify webhook authenticity
      if (req.headers['x-api-key'] !== WEBHOOK_SECRET) {
        return res.status(401).json({ error: 'Unauthorized' });
      }

      const event = req.body;
      
      try {
        // Handle different event types
        switch (event.eventSubCategory) {
          case 'challenge-completion':
            await sendSlackMessage({
              text: `🎯 Challenge Completed!`,
              blocks: [{
                type: 'section',
                text: {
                  type: 'mrkdwn',
                  text: `*User:* ${event.userId}\n*Challenge:* ${event.eventSourceId}\n*Time:* ${event.createdAt}`
                }
              }]
            });
            break;
            
          case 'reward-distribution':
            const { earnedPoints, earnedXp } = event.payload;
            await sendSlackMessage({
              text: `🎁 Rewards Distributed!`,
              blocks: [{
                type: 'section',
                text: {
                  type: 'mrkdwn',
                  text: `*User:* ${event.userId}\n*Points:* ${earnedPoints}\n*XP:* ${earnedXp}`
                }
              }]
            });
            break;
            
          case 'achievement-completion':
            await sendSlackMessage({
              text: `🏆 Achievement Unlocked!`,
              blocks: [{
                type: 'section',
                text: {
                  type: 'mrkdwn',
                  text: `*User:* ${event.userId}\n*Achievement:* ${event.payload.achievementName}`
                }
              }]
            });
            break;
        }
        
        res.status(200).json({ success: true });
      } catch (error) {
        console.error('Slack notification failed:', error);
        res.status(200).json({ success: true }); // Return 200 to prevent retries
      }
    });

    async function sendSlackMessage(message) {
      await axios.post(SLACK_WEBHOOK_URL, message);
    }

    app.listen(3000, () => {
      console.log('Webhook handler running on port 3000');
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from flask import Flask, request, jsonify
    import requests
    import os
    from datetime import datetime

    app = Flask(__name__)

    SLACK_WEBHOOK_URL = os.environ.get('SLACK_WEBHOOK_URL')
    WEBHOOK_SECRET = os.environ.get('WEBHOOK_SECRET')

    @app.route('/webhooks/nudj', methods=['POST'])
    def handle_webhook():
        # Verify webhook authenticity
        if request.headers.get('X-Api-Key') != WEBHOOK_SECRET:
            return jsonify({'error': 'Unauthorized'}), 401
        
        event = request.json
        
        try:
            event_type = event.get('eventSubCategory')
            
            if event_type == 'challenge-completion':
                send_slack_message({
                    'text': '🎯 Challenge Completed!',
                    'blocks': [{
                        'type': 'section',
                        'text': {
                            'type': 'mrkdwn',
                            'text': f"*User:* {event.get('userId')}\n"
                                   f"*Challenge:* {event.get('eventSourceId')}\n"
                                   f"*Time:* {event.get('createdAt')}"
                        }
                    }]
                })
            
            elif event_type == 'reward-distribution':
                payload = event.get('payload', {})
                send_slack_message({
                    'text': '🎁 Rewards Distributed!',
                    'blocks': [{
                        'type': 'section',
                        'text': {
                            'type': 'mrkdwn',
                            'text': f"*User:* {event.get('userId')}\n"
                                   f"*Points:* {payload.get('earnedPoints')}\n"
                                   f"*XP:* {payload.get('earnedXp')}"
                        }
                    }]
                })
            
            return jsonify({'success': True}), 200
            
        except Exception as e:
            print(f"Error processing webhook: {e}")
            return jsonify({'success': True}), 200  # Return 200 to prevent retries

    def send_slack_message(message):
        requests.post(SLACK_WEBHOOK_URL, json=message)

    if __name__ == '__main__':
        app.run(port=3000)
    ```
  </Tab>
</Tabs>

## Recipe: Email Notification System

Send personalized emails for important user events using SendGrid.

<Tabs>
  <Tab title="Setup">
    ### Prerequisites

    * SendGrid account and API key
    * Email templates configured in SendGrid
    * Verified sender domain

    ### Email Templates Needed

    * Challenge completion
    * Reward earned
    * Achievement unlocked
    * Weekly summary
  </Tab>

  <Tab title="Node.js">
    ```javascript theme={null}
    const express = require('express');
    const sgMail = require('@sendgrid/mail');
    const app = express();

    sgMail.setApiKey(process.env.SENDGRID_API_KEY);
    const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

    // Template IDs from SendGrid
    const TEMPLATES = {
      'challenge-completion': 'd-challenge-complete-template-id',
      'reward-distribution': 'd-reward-earned-template-id',
      'achievement-completion': 'd-achievement-template-id',
      'streak-extended': 'd-streak-template-id'
    };

    app.post('/webhooks/nudj', express.json(), async (req, res) => {
      if (req.headers['x-api-key'] !== WEBHOOK_SECRET) {
        return res.status(401).json({ error: 'Unauthorized' });
      }

      const event = req.body;
      
      try {
        const templateId = TEMPLATES[event.eventSubCategory];
        if (!templateId) {
          return res.status(200).json({ success: true });
        }

        // Extract user email from payload (reward-distribution includes it)
        let userEmail;
        if (event.eventSubCategory === 'reward-distribution') {
          userEmail = event.payload?.user?.email;
        } else {
          // You'd need to look up user email from your database
          userEmail = await getUserEmail(event.userId);
        }

        if (userEmail) {
          await sendEmail(userEmail, templateId, event);
        }
        
        res.status(200).json({ success: true });
      } catch (error) {
        console.error('Email send failed:', error);
        res.status(200).json({ success: true });
      }
    });

    async function sendEmail(to, templateId, eventData) {
      const msg = {
        to,
        from: 'notifications@yourcompany.com',
        templateId,
        dynamicTemplateData: {
          userId: eventData.userId,
          eventType: eventData.eventSubCategory,
          timestamp: eventData.createdAt,
          ...eventData.payload
        }
      };
      
      await sgMail.send(msg);
    }

    async function getUserEmail(userId) {
      // Implement your user lookup logic here
      // This would query your database or call your API
      return null; // Placeholder
    }

    app.listen(3000, () => {
      console.log('Email webhook handler running on port 3000');
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from flask import Flask, request, jsonify
    from sendgrid import SendGridAPIClient
    from sendgrid.helpers.mail import Mail, Email, To
    import os

    app = Flask(__name__)

    sg = SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY'))
    WEBHOOK_SECRET = os.environ.get('WEBHOOK_SECRET')

    TEMPLATES = {
        'challenge-completion': 'd-challenge-complete-template-id',
        'reward-distribution': 'd-reward-earned-template-id',
        'achievement-completion': 'd-achievement-template-id',
        'streak-extended': 'd-streak-template-id'
    }

    @app.route('/webhooks/nudj', methods=['POST'])
    def handle_webhook():
        if request.headers.get('X-Api-Key') != WEBHOOK_SECRET:
            return jsonify({'error': 'Unauthorized'}), 401
        
        event = request.json
        
        try:
            template_id = TEMPLATES.get(event.get('eventSubCategory'))
            if not template_id:
                return jsonify({'success': True}), 200
            
            # Get user email
            user_email = None
            if event.get('eventSubCategory') == 'reward-distribution':
                user_email = event.get('payload', {}).get('user', {}).get('email')
            else:
                user_email = get_user_email(event.get('userId'))
            
            if user_email:
                send_email(user_email, template_id, event)
            
            return jsonify({'success': True}), 200
            
        except Exception as e:
            print(f"Error: {e}")
            return jsonify({'success': True}), 200

    def send_email(to_email, template_id, event_data):
        message = Mail(
            from_email='notifications@yourcompany.com',
            to_emails=to_email
        )
        message.template_id = template_id
        message.dynamic_template_data = {
            'userId': event_data.get('userId'),
            'eventType': event_data.get('eventSubCategory'),
            'timestamp': event_data.get('createdAt'),
            **event_data.get('payload', {})
        }
        sg.send(message)

    def get_user_email(user_id):
        # Implement your user lookup
        return None

    if __name__ == '__main__':
        app.run(port=3000)
    ```
  </Tab>
</Tabs>

## Recipe: Analytics & Data Pipeline

Stream events to your data warehouse for analytics.

<Tabs>
  <Tab title="Setup">
    ### Prerequisites

    * Data warehouse (BigQuery, Snowflake, Redshift)
    * Message queue (optional but recommended)

    ### Architecture

    1. Webhook receives events
    2. Events queued for processing
    3. Batch insert to data warehouse
    4. Analytics dashboards update
  </Tab>

  <Tab title="BigQuery Integration">
    ```javascript theme={null}
    const express = require('express');
    const { BigQuery } = require('@google-cloud/bigquery');
    const app = express();

    const bigquery = new BigQuery();
    const dataset = bigquery.dataset('nudj_events');
    const table = dataset.table('webhook_events');

    const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
    const eventBatch = [];
    const BATCH_SIZE = 100;
    const FLUSH_INTERVAL = 5000; // 5 seconds

    app.post('/webhooks/nudj', express.json(), async (req, res) => {
      if (req.headers['x-api-key'] !== WEBHOOK_SECRET) {
        return res.status(401).json({ error: 'Unauthorized' });
      }

      const event = req.body;
      
      // Add event to batch
      eventBatch.push({
        event_id: event.id,
        event_category: event.eventCategory,
        event_subcategory: event.eventSubCategory,
        organisation_id: event.organisationId,
        community_id: event.communityId,
        user_id: event.userId,
        event_source_id: event.eventSourceId,
        payload: JSON.stringify(event.payload),
        tags: event.tags,
        created_at: event.createdAt,
        received_at: new Date().toISOString()
      });
      
      // Flush batch if it's full
      if (eventBatch.length >= BATCH_SIZE) {
        await flushBatch();
      }
      
      res.status(200).json({ success: true });
    });

    async function flushBatch() {
      if (eventBatch.length === 0) return;
      
      const events = [...eventBatch];
      eventBatch.length = 0; // Clear batch
      
      try {
        await table.insert(events);
        console.log(`Inserted ${events.length} events to BigQuery`);
      } catch (error) {
        console.error('BigQuery insert failed:', error);
        // Consider adding to dead letter queue
      }
    }

    // Periodic flush
    setInterval(flushBatch, FLUSH_INTERVAL);

    app.listen(3000, () => {
      console.log('Analytics webhook handler running on port 3000');
    });
    ```
  </Tab>

  <Tab title="Snowflake Integration">
    ```python theme={null}
    from flask import Flask, request, jsonify
    import snowflake.connector
    import json
    import os
    from datetime import datetime
    from queue import Queue
    import threading

    app = Flask(__name__)

    WEBHOOK_SECRET = os.environ.get('WEBHOOK_SECRET')
    event_queue = Queue()

    # Snowflake connection
    conn = snowflake.connector.connect(
        user=os.environ.get('SNOWFLAKE_USER'),
        password=os.environ.get('SNOWFLAKE_PASSWORD'),
        account=os.environ.get('SNOWFLAKE_ACCOUNT'),
        warehouse='COMPUTE_WH',
        database='NUDJ_ANALYTICS',
        schema='EVENTS'
    )

    @app.route('/webhooks/nudj', methods=['POST'])
    def handle_webhook():
        if request.headers.get('X-Api-Key') != WEBHOOK_SECRET:
            return jsonify({'error': 'Unauthorized'}), 401
        
        event = request.json
        
        # Queue event for processing
        event_queue.put({
            'EVENT_ID': event.get('id'),
            'EVENT_CATEGORY': event.get('eventCategory'),
            'EVENT_SUBCATEGORY': event.get('eventSubCategory'),
            'ORGANISATION_ID': event.get('organisationId'),
            'COMMUNITY_ID': event.get('communityId'),
            'USER_ID': event.get('userId'),
            'EVENT_SOURCE_ID': event.get('eventSourceId'),
            'PAYLOAD': json.dumps(event.get('payload', {})),
            'TAGS': json.dumps(event.get('tags', [])),
            'CREATED_AT': event.get('createdAt'),
            'RECEIVED_AT': datetime.utcnow().isoformat()
        })
        
        return jsonify({'success': True}), 200

    def process_queue():
        """Background worker to process queued events"""
        cursor = conn.cursor()
        batch = []
        
        while True:
            try:
                # Collect batch
                while not event_queue.empty() and len(batch) < 100:
                    batch.append(event_queue.get())
                
                if batch:
                    # Insert batch into Snowflake
                    cursor.executemany(
                        """INSERT INTO WEBHOOK_EVENTS 
                        (EVENT_ID, EVENT_CATEGORY, EVENT_SUBCATEGORY, 
                         ORGANISATION_ID, COMMUNITY_ID, USER_ID, 
                         EVENT_SOURCE_ID, PAYLOAD, TAGS, 
                         CREATED_AT, RECEIVED_AT)
                        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
                        [tuple(event.values()) for event in batch]
                    )
                    conn.commit()
                    print(f"Inserted {len(batch)} events to Snowflake")
                    batch.clear()
                    
            except Exception as e:
                print(f"Error processing batch: {e}")
                
            threading.Event().wait(5)  # Process every 5 seconds

    # Start background worker
    worker = threading.Thread(target=process_queue, daemon=True)
    worker.start()

    if __name__ == '__main__':
        app.run(port=3000)
    ```
  </Tab>
</Tabs>

## Recipe: Zapier/Make.com Integration

Connect Nudj webhooks to 1000+ apps without code.

<Tabs>
  <Tab title="Zapier Setup">
    ### Creating a Zap

    1. **Trigger Setup**
       * Choose "Webhooks by Zapier" as trigger
       * Select "Catch Hook" as event
       * Copy the webhook URL provided

    2. **Configure Nudj Webhook**
       ```json theme={null}
       {
         "url": "https://hooks.zapier.com/hooks/catch/YOUR_ID/",
         "events": ["challenge-completion", "reward-distribution"],
         "httpMethod": "POST",
         "isEnabled": true
       }
       ```

    3. **Test & Map Fields**
       * Send test webhook from Nudj
       * Map fields to your action apps
       * Common actions:
         * Add row to Google Sheets
         * Create Salesforce lead
         * Send Teams message
         * Create Asana task
  </Tab>

  <Tab title="Make.com Setup">
    ### Creating a Scenario

    1. **Webhook Module**
       * Add "Webhooks" → "Custom webhook"
       * Copy the webhook URL
       * Add to Nudj configuration

    2. **Data Processing**
       * Add Router for different event types
       * Parse JSON payload
       * Add filters for specific conditions

    3. **Action Modules**
       * Google Sheets: Log events
       * Slack: Send notifications
       * Email: Send alerts
       * Database: Store records

    ### Example Scenario

    ```
    Webhook → Router → Branch 1: Challenge Complete → Slack
                    → Branch 2: Reward Earned → Google Sheets
                    → Branch 3: Achievement → Email
    ```
  </Tab>
</Tabs>

## Recipe: Database Sync

Keep your database synchronized with Nudj events.

<Tabs>
  <Tab title="PostgreSQL">
    ```javascript theme={null}
    const express = require('express');
    const { Pool } = require('pg');
    const app = express();

    const pool = new Pool({
      connectionString: process.env.DATABASE_URL
    });

    const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

    // Create events table if not exists
    async function initDatabase() {
      await pool.query(`
        CREATE TABLE IF NOT EXISTS nudj_events (
          id VARCHAR(255) PRIMARY KEY,
          event_category VARCHAR(100),
          event_subcategory VARCHAR(100),
          organisation_id VARCHAR(255),
          community_id VARCHAR(255),
          user_id VARCHAR(255),
          event_source_id VARCHAR(255),
          payload JSONB,
          tags TEXT[],
          created_at TIMESTAMP,
          received_at TIMESTAMP DEFAULT NOW()
        )
      `);
      
      // Create user points table
      await pool.query(`
        CREATE TABLE IF NOT EXISTS user_points (
          user_id VARCHAR(255) PRIMARY KEY,
          total_points INTEGER DEFAULT 0,
          total_xp INTEGER DEFAULT 0,
          last_updated TIMESTAMP DEFAULT NOW()
        )
      `);
    }

    app.post('/webhooks/nudj', express.json(), async (req, res) => {
      if (req.headers['x-api-key'] !== WEBHOOK_SECRET) {
        return res.status(401).json({ error: 'Unauthorized' });
      }

      const event = req.body;
      
      try {
        // Store raw event
        await pool.query(
          `INSERT INTO nudj_events 
           (id, event_category, event_subcategory, organisation_id, 
            community_id, user_id, event_source_id, payload, tags, created_at)
           VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
           ON CONFLICT (id) DO NOTHING`,
          [
            event.id,
            event.eventCategory,
            event.eventSubCategory,
            event.organisationId,
            event.communityId,
            event.userId,
            event.eventSourceId,
            JSON.stringify(event.payload),
            event.tags,
            event.createdAt
          ]
        );
        
        // Update user points for reward events
        if (event.eventSubCategory === 'reward-distribution') {
          const { earnedPoints = 0, earnedXp = 0 } = event.payload;
          await pool.query(
            `INSERT INTO user_points (user_id, total_points, total_xp)
             VALUES ($1, $2, $3)
             ON CONFLICT (user_id) 
             DO UPDATE SET 
               total_points = user_points.total_points + $2,
               total_xp = user_points.total_xp + $3,
               last_updated = NOW()`,
            [event.userId, earnedPoints, earnedXp]
          );
        }
        
        res.status(200).json({ success: true });
      } catch (error) {
        console.error('Database error:', error);
        res.status(500).json({ error: 'Internal error' });
      }
    });

    initDatabase().then(() => {
      app.listen(3000, () => {
        console.log('Database sync webhook running on port 3000');
      });
    });
    ```
  </Tab>

  <Tab title="MongoDB">
    ```javascript theme={null}
    const express = require('express');
    const { MongoClient } = require('mongodb');
    const app = express();

    const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
    const MONGODB_URI = process.env.MONGODB_URI;

    let db;

    MongoClient.connect(MONGODB_URI).then(client => {
      db = client.db('nudj_analytics');
      console.log('Connected to MongoDB');
    });

    app.post('/webhooks/nudj', express.json(), async (req, res) => {
      if (req.headers['x-api-key'] !== WEBHOOK_SECRET) {
        return res.status(401).json({ error: 'Unauthorized' });
      }

      const event = req.body;
      
      try {
        // Store event
        await db.collection('events').insertOne({
          ...event,
          _id: event.id,
          receivedAt: new Date()
        });
        
        // Update user statistics
        if (event.eventSubCategory === 'reward-distribution') {
          const { earnedPoints = 0, earnedXp = 0 } = event.payload;
          
          await db.collection('user_stats').updateOne(
            { _id: event.userId },
            {
              $inc: { 
                totalPoints: earnedPoints,
                totalXp: earnedXp,
                rewardCount: 1
              },
              $set: { lastActivity: new Date() },
              $setOnInsert: { 
                userId: event.userId,
                createdAt: new Date() 
              }
            },
            { upsert: true }
          );
        }
        
        // Track challenge completions
        if (event.eventSubCategory === 'challenge-completion') {
          await db.collection('challenge_stats').updateOne(
            { _id: event.eventSourceId },
            {
              $inc: { completions: 1 },
              $addToSet: { completedBy: event.userId }
            },
            { upsert: true }
          );
        }
        
        res.status(200).json({ success: true });
      } catch (error) {
        console.error('MongoDB error:', error);
        res.status(500).json({ error: 'Internal error' });
      }
    });

    app.listen(3000, () => {
      console.log('MongoDB sync webhook running on port 3000');
    });
    ```
  </Tab>
</Tabs>

## Deployment Options

### Serverless Deployment

<Tabs>
  <Tab title="Vercel">
    ```javascript theme={null}
    // api/webhooks/nudj.js
    export default async function handler(req, res) {
      if (req.method !== 'POST') {
        return res.status(405).json({ error: 'Method not allowed' });
      }
      
      if (req.headers['x-api-key'] !== process.env.WEBHOOK_SECRET) {
        return res.status(401).json({ error: 'Unauthorized' });
      }
      
      const event = req.body;
      
      // Process webhook
      await processWebhook(event);
      
      res.status(200).json({ success: true });
    }
    ```
  </Tab>

  <Tab title="AWS Lambda">
    ```javascript theme={null}
    // handler.js
    exports.handler = async (event) => {
      const body = JSON.parse(event.body);
      const apiKey = event.headers['x-api-key'];
      
      if (apiKey !== process.env.WEBHOOK_SECRET) {
        return {
          statusCode: 401,
          body: JSON.stringify({ error: 'Unauthorized' })
        };
      }
      
      // Process webhook
      await processWebhook(body);
      
      return {
        statusCode: 200,
        body: JSON.stringify({ success: true })
      };
    };
    ```
  </Tab>
</Tabs>
