Last updated: Aug 4, 2025, 11:26 AM UTC

Integration Documentation

Status: Complete
Version: 5.0
Last Updated: 2024
Purpose: Comprehensive integration guide for connecting NudgeCampaign with external systems

Table of Contents

  1. Integration Overview
  2. REST API Documentation
  3. Webhook System
  4. Third-Party Integrations
  5. Authentication & Security
  6. SDK Documentation
  7. Data Synchronization
  8. Integration Patterns
  9. Testing & Debugging
  10. Migration Guides

Integration Overview

NudgeCampaign provides extensive integration capabilities to connect with your existing technology stack, enabling seamless data flow and automation across your marketing ecosystem.

Integration Architecture

graph TB subgraph "External Systems" CRM[CRM Systems] ERP[ERP Platforms] Analytics[Analytics Tools] Ecommerce[E-commerce] Support[Support Systems] end subgraph "Integration Layer" API[REST API] Webhooks[Webhook Engine] SDK[SDKs] Connect[Native Connectors] end subgraph "NudgeCampaign Core" Core[Platform Core] Queue[Message Queue] Process[Processing Engine] Store[Data Store] end CRM --> API ERP --> SDK Analytics --> Webhooks Ecommerce --> Connect Support --> API API --> Queue SDK --> Queue Webhooks --> Process Connect --> Core Queue --> Process Process --> Store Core --> Store

Integration Capabilities

Core Features

  • RESTful API with comprehensive endpoints
  • Real-time webhook notifications
  • Batch data import/export
  • OAuth 2.0 authentication
  • Rate limiting and throttling
  • Multi-tenant data isolation
  • Async processing for large operations
  • Comprehensive error handling

Supported Protocols

  • REST/HTTP(S)
  • WebSocket for real-time updates
  • GraphQL (beta)
  • SOAP (legacy support)
  • SFTP for bulk transfers
  • Email (SMTP/IMAP)

Integration Types

1. Native Integrations

Pre-built connectors maintained by NudgeCampaign:

  • Salesforce CRM
  • HubSpot
  • Shopify
  • WooCommerce
  • Stripe
  • Zapier
  • Microsoft Dynamics
  • Google Analytics

2. Custom Integrations

Build your own integrations using:

  • REST API
  • Webhooks
  • SDK libraries
  • Custom connectors

3. Middleware Platforms

Connect through integration platforms:

  • Zapier (1000+ apps)
  • Make (formerly Integromat)
  • n8n (self-hosted)
  • Tray.io
  • Workato

REST API Documentation

API Overview

Base URL: https://api.nudgecampaign.com/v1

All API requests must include authentication headers and follow REST conventions.

Authentication

API Key Authentication

curl -X GET https://api.nudgecampaign.com/v1/contacts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "X-Organization-ID: YOUR_ORG_ID"

OAuth 2.0 Flow

// OAuth 2.0 Authorization Code Flow
const authUrl = 'https://auth.nudgecampaign.com/oauth/authorize';
const params = {
  client_id: 'YOUR_CLIENT_ID',
  redirect_uri: 'YOUR_REDIRECT_URI',
  response_type: 'code',
  scope: 'contacts:read campaigns:write',
  state: 'RANDOM_STATE_STRING'
};

// Redirect user to authorization URL
window.location.href = `${authUrl}?${new URLSearchParams(params)}`;

// Exchange code for token
const tokenResponse = await fetch('https://auth.nudgecampaign.com/oauth/token', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    grant_type: 'authorization_code',
    code: authorizationCode,
    client_id: clientId,
    client_secret: clientSecret,
    redirect_uri: redirectUri
  })
});

Core Endpoints

Contacts API

List Contacts
GET /v1/contacts

Query Parameters:

  • page (integer): Page number (default: 1)
  • limit (integer): Items per page (max: 100)
  • sort (string): Sort field and direction
  • filter (string): Filter expression
  • fields (string): Comma-separated field list

Response:

{
  "data": [
    {
      "id": "cnt_abc123",
      "email": "john@example.com",
      "firstName": "John",
      "lastName": "Doe",
      "status": "subscribed",
      "tags": ["customer", "vip"],
      "customFields": {
        "company": "Acme Corp",
        "lifetime_value": 5000
      },
      "createdAt": "2024-01-15T10:30:00Z",
      "updatedAt": "2024-02-20T14:45:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 1500,
    "pages": 75
  }
}
Create Contact
POST /v1/contacts

Request Body:

{
  "email": "jane@example.com",
  "firstName": "Jane",
  "lastName": "Smith",
  "tags": ["prospect"],
  "customFields": {
    "source": "website",
    "interest": "email-marketing"
  },
  "lists": ["lst_newsletter", "lst_prospects"]
}

Response:

{
  "data": {
    "id": "cnt_xyz789",
    "email": "jane@example.com",
    "status": "pending",
    "confirmationUrl": "https://app.nudgecampaign.com/confirm/xyz789"
  }
}
Update Contact
PATCH /v1/contacts/{id}

Request Body:

{
  "firstName": "Jane",
  "lastName": "Johnson",
  "customFields": {
    "company": "New Company"
  },
  "tags": {
    "add": ["customer"],
    "remove": ["prospect"]
  }
}
Delete Contact
DELETE /v1/contacts/{id}
Bulk Operations
POST /v1/contacts/bulk

Request Body:

{
  "operation": "upsert",
  "contacts": [
    {
      "email": "contact1@example.com",
      "firstName": "Contact",
      "lastName": "One"
    },
    {
      "email": "contact2@example.com",
      "firstName": "Contact",
      "lastName": "Two"
    }
  ],
  "options": {
    "updateExisting": true,
    "skipValidation": false
  }
}

Campaigns API

List Campaigns
GET /v1/campaigns

Query Parameters:

  • status (string): draft, scheduled, sending, sent, paused
  • type (string): regular, automated, ab_test
  • from_date (string): ISO 8601 date
  • to_date (string): ISO 8601 date
Create Campaign
POST /v1/campaigns

Request Body:

{
  "name": "Summer Sale Campaign",
  "subject": "Exclusive Summer Deals Inside! β˜€οΈ",
  "preheader": "Save up to 50% on selected items",
  "from": {
    "email": "sales@example.com",
    "name": "Sales Team"
  },
  "replyTo": "support@example.com",
  "lists": ["lst_customers"],
  "segments": ["seg_high_value"],
  "content": {
    "html": "<html>...</html>",
    "text": "Plain text version..."
  },
  "schedule": {
    "sendAt": "2024-06-01T10:00:00Z",
    "timezone": "America/New_York"
  }
}
Send Test Email
POST /v1/campaigns/{id}/test

Request Body:

{
  "recipients": [
    "test1@example.com",
    "test2@example.com"
  ],
  "personalization": {
    "firstName": "Test",
    "company": "Test Company"
  }
}
Campaign Analytics
GET /v1/campaigns/{id}/analytics

Response:

{
  "data": {
    "sent": 10000,
    "delivered": 9850,
    "bounced": 150,
    "opened": 3500,
    "clicked": 850,
    "unsubscribed": 25,
    "complained": 5,
    "metrics": {
      "deliveryRate": 98.5,
      "openRate": 35.5,
      "clickRate": 8.6,
      "clickToOpenRate": 24.3,
      "unsubscribeRate": 0.25,
      "complaintRate": 0.05
    },
    "engagement": {
      "devices": {
        "desktop": 45,
        "mobile": 50,
        "tablet": 5
      },
      "clients": {
        "gmail": 30,
        "outlook": 25,
        "apple": 20,
        "other": 25
      }
    },
    "links": [
      {
        "url": "https://example.com/product",
        "clicks": 450,
        "uniqueClicks": 380
      }
    ]
  }
}

Lists API

Create List
POST /v1/lists

Request Body:

{
  "name": "VIP Customers",
  "description": "High-value customers for exclusive offers",
  "settings": {
    "doubleOptIn": true,
    "welcomeEmail": true,
    "confirmationEmail": "cmp_welcome123"
  }
}
Add Contacts to List
POST /v1/lists/{id}/contacts

Request Body:

{
  "contacts": [
    "cnt_abc123",
    "cnt_xyz789"
  ],
  "skipConfirmation": false
}

Automations API

Create Automation
POST /v1/automations

Request Body:

{
  "name": "Welcome Series",
  "trigger": {
    "type": "list_subscription",
    "config": {
      "listId": "lst_newsletter"
    }
  },
  "steps": [
    {
      "type": "email",
      "config": {
        "campaignId": "cmp_welcome1",
        "delay": 0
      }
    },
    {
      "type": "wait",
      "config": {
        "duration": 86400
      }
    },
    {
      "type": "email",
      "config": {
        "campaignId": "cmp_welcome2"
      }
    }
  ]
}
Automation Performance
GET /v1/automations/{id}/performance

Response:

{
  "data": {
    "enrolled": 5000,
    "active": 1200,
    "completed": 3750,
    "stopped": 50,
    "steps": [
      {
        "id": "step_1",
        "type": "email",
        "sent": 5000,
        "opened": 3500,
        "clicked": 1200
      }
    ],
    "conversionRate": 24.5,
    "averageTimeToComplete": 604800
  }
}

Rate Limiting

API requests are rate-limited to ensure fair usage:

  • Standard Tier: 1,000 requests per hour
  • Professional Tier: 5,000 requests per hour
  • Enterprise Tier: Custom limits

Rate limit headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 950
X-RateLimit-Reset: 1643723400

Handling rate limits:

async function makeApiRequest(url, options) {
  const response = await fetch(url, options);
  
  if (response.status === 429) {
    const retryAfter = response.headers.get('Retry-After');
    await sleep(retryAfter * 1000);
    return makeApiRequest(url, options);
  }
  
  return response;
}

Error Handling

Standard error response format:

{
  "error": {
    "type": "validation_error",
    "message": "Invalid request parameters",
    "details": [
      {
        "field": "email",
        "message": "Invalid email format"
      }
    ],
    "request_id": "req_abc123xyz",
    "documentation_url": "https://docs.nudgecampaign.com/api/errors#validation_error"
  }
}

Common HTTP status codes:

  • 200 OK: Request successful
  • 201 Created: Resource created
  • 204 No Content: Request successful, no content
  • 400 Bad Request: Invalid request
  • 401 Unauthorized: Authentication failed
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Resource not found
  • 409 Conflict: Resource conflict
  • 429 Too Many Requests: Rate limit exceeded
  • 500 Internal Server Error: Server error

Webhook System

Webhook Overview

Webhooks provide real-time notifications for events in your NudgeCampaign account.

Webhook Configuration

Create Webhook Endpoint

POST /v1/webhooks

Request Body:

{
  "url": "https://your-app.com/webhooks/nudgecampaign",
  "events": [
    "contact.created",
    "contact.updated",
    "contact.unsubscribed",
    "campaign.sent",
    "email.opened",
    "email.clicked"
  ],
  "headers": {
    "X-Custom-Header": "custom-value"
  },
  "secret": "webhook_secret_key"
}

Webhook Events

Contact Events

contact.created

Triggered when a new contact is created:

{
  "event": "contact.created",
  "timestamp": "2024-03-15T10:30:00Z",
  "data": {
    "id": "cnt_abc123",
    "email": "new@example.com",
    "source": "api",
    "lists": ["lst_newsletter"]
  }
}
contact.updated

Triggered when contact information changes:

{
  "event": "contact.updated",
  "timestamp": "2024-03-15T10:35:00Z",
  "data": {
    "id": "cnt_abc123",
    "changes": {
      "firstName": {
        "old": "John",
        "new": "Jonathan"
      },
      "customFields.company": {
        "old": "Old Corp",
        "new": "New Corp"
      }
    }
  }
}
contact.unsubscribed

Triggered when a contact unsubscribes:

{
  "event": "contact.unsubscribed",
  "timestamp": "2024-03-15T10:40:00Z",
  "data": {
    "id": "cnt_abc123",
    "email": "user@example.com",
    "reason": "user_request",
    "campaignId": "cmp_xyz789",
    "listId": "lst_newsletter"
  }
}

Email Events

email.opened

Triggered when an email is opened:

{
  "event": "email.opened",
  "timestamp": "2024-03-15T11:00:00Z",
  "data": {
    "contactId": "cnt_abc123",
    "campaignId": "cmp_xyz789",
    "messageId": "msg_123456",
    "userAgent": "Mozilla/5.0...",
    "ipAddress": "192.168.1.1",
    "location": {
      "country": "US",
      "region": "CA",
      "city": "San Francisco"
    }
  }
}
email.clicked

Triggered when a link is clicked:

{
  "event": "email.clicked",
  "timestamp": "2024-03-15T11:05:00Z",
  "data": {
    "contactId": "cnt_abc123",
    "campaignId": "cmp_xyz789",
    "messageId": "msg_123456",
    "url": "https://example.com/product",
    "position": 3,
    "userAgent": "Mozilla/5.0..."
  }
}

Webhook Security

Signature Verification

Verify webhook authenticity using HMAC-SHA256:

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express.js middleware
app.post('/webhooks/nudgecampaign', (req, res) => {
  const signature = req.headers['x-nudgecampaign-signature'];
  const payload = JSON.stringify(req.body);
  
  if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process webhook
  processWebhook(req.body);
  res.status(200).send('OK');
});

Retry Logic

Webhook delivery follows exponential backoff:

  • Attempt 1: Immediate
  • Attempt 2: 1 minute
  • Attempt 3: 5 minutes
  • Attempt 4: 30 minutes
  • Attempt 5: 2 hours
  • Attempt 6: 6 hours

Third-Party Integrations

Salesforce Integration

Setup Process

  1. Install NudgeCampaign Package

    Navigate to Salesforce AppExchange
    Search for "NudgeCampaign"
    Click "Get It Now"
    Follow installation wizard
    
  2. Configure Connected App

    Setup > App Manager > New Connected App
    Name: NudgeCampaign Integration
    API Name: NudgeCampaign_Integration
    Enable OAuth Settings: Yes
    Callback URL: https://app.nudgecampaign.com/oauth/salesforce/callback
    Selected OAuth Scopes:
    - Access and manage your data (api)
    - Access your basic information (id, profile, email)
    - Perform requests on your behalf at any time (refresh_token, offline_access)
    
  3. Field Mapping Configuration

    {
      "fieldMappings": {
        "Contact": {
          "Email": "email",
          "FirstName": "firstName",
          "LastName": "lastName",
          "Account.Name": "customFields.company",
          "LeadSource": "customFields.source"
        },
        "Lead": {
          "Email": "email",
          "FirstName": "firstName",
          "LastName": "lastName",
          "Company": "customFields.company",
          "LeadSource": "customFields.source"
        }
      }
    }
    

Data Synchronization

Real-time Sync (Apex Trigger)
trigger ContactSync on Contact (after insert, after update) {
    List<NudgeCampaign.Contact> nudgeContacts = new List<NudgeCampaign.Contact>();
    
    for (Contact c : Trigger.new) {
        if (Trigger.isUpdate) {
            Contact oldContact = Trigger.oldMap.get(c.Id);
            if (c.Email != oldContact.Email || 
                c.FirstName != oldContact.FirstName ||
                c.LastName != oldContact.LastName) {
                
                NudgeCampaign.Contact nc = new NudgeCampaign.Contact();
                nc.email = c.Email;
                nc.firstName = c.FirstName;
                nc.lastName = c.LastName;
                nc.salesforceId = c.Id;
                nudgeContacts.add(nc);
            }
        } else {
            NudgeCampaign.Contact nc = new NudgeCampaign.Contact();
            nc.email = c.Email;
            nc.firstName = c.FirstName;
            nc.lastName = c.LastName;
            nc.salesforceId = c.Id;
            nudgeContacts.add(nc);
        }
    }
    
    if (!nudgeContacts.isEmpty()) {
        NudgeCampaign.API.syncContacts(nudgeContacts);
    }
}

HubSpot Integration

OAuth Configuration

const HubSpotClient = require('@hubspot/api-client');

const hubspotClient = new HubSpotClient.Client({
  accessToken: process.env.HUBSPOT_ACCESS_TOKEN,
});

// Sync contacts from HubSpot to NudgeCampaign
async function syncHubSpotContacts() {
  try {
    const response = await hubspotClient.crm.contacts.basicApi.getPage(
      100,
      undefined,
      ['email', 'firstname', 'lastname', 'company']
    );
    
    const contacts = response.results.map(contact => ({
      email: contact.properties.email,
      firstName: contact.properties.firstname,
      lastName: contact.properties.lastname,
      customFields: {
        company: contact.properties.company,
        hubspotId: contact.id
      }
    }));
    
    // Bulk import to NudgeCampaign
    await nudgeCampaignAPI.contacts.bulkCreate(contacts);
    
  } catch (error) {
    console.error('Sync failed:', error);
  }
}

Shopify Integration

Webhook Setup

// Register Shopify webhooks
const webhookTopics = [
  'customers/create',
  'customers/update',
  'orders/create',
  'orders/fulfilled'
];

async function registerShopifyWebhooks(shop, accessToken) {
  for (const topic of webhookTopics) {
    const webhook = {
      webhook: {
        topic: topic,
        address: `https://api.nudgecampaign.com/integrations/shopify/webhook`,
        format: 'json'
      }
    };
    
    await fetch(`https://${shop}/admin/api/2024-01/webhooks.json`, {
      method: 'POST',
      headers: {
        'X-Shopify-Access-Token': accessToken,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(webhook)
    });
  }
}

Order Tracking

// Process Shopify order webhook
async function processShopifyOrder(order) {
  // Update contact in NudgeCampaign
  const contact = {
    email: order.email,
    customFields: {
      lastOrderDate: order.created_at,
      totalOrders: order.order_number,
      totalSpent: order.total_price,
      averageOrderValue: order.total_price / order.line_items.length
    },
    tags: ['customer', 'shopify']
  };
  
  await nudgeCampaignAPI.contacts.upsert(contact);
  
  // Trigger abandoned cart recovery if applicable
  if (order.financial_status === 'pending') {
    await nudgeCampaignAPI.automations.trigger('abandoned_cart', {
      contactEmail: order.email,
      cartUrl: order.abandoned_checkout_url,
      cartValue: order.total_price,
      items: order.line_items
    });
  }
}

Stripe Integration

Payment Events

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

// Stripe webhook endpoint
app.post('/webhooks/stripe', express.raw({type: 'application/json'}), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  let event;
  
  try {
    event = stripe.webhooks.constructEvent(req.body, sig, STRIPE_WEBHOOK_SECRET);
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }
  
  switch (event.type) {
    case 'customer.created':
      await syncStripeCustomer(event.data.object);
      break;
      
    case 'customer.subscription.created':
      await updateSubscriptionStatus(event.data.object);
      break;
      
    case 'invoice.payment_succeeded':
      await recordPayment(event.data.object);
      break;
      
    case 'customer.subscription.deleted':
      await handleChurn(event.data.object);
      break;
  }
  
  res.json({received: true});
});

async function syncStripeCustomer(customer) {
  const contact = {
    email: customer.email,
    customFields: {
      stripeCustomerId: customer.id,
      currency: customer.currency,
      created: new Date(customer.created * 1000)
    },
    tags: ['stripe_customer']
  };
  
  await nudgeCampaignAPI.contacts.upsert(contact);
}

SDK Documentation

JavaScript/TypeScript SDK

Installation

npm install @nudgecampaign/sdk

Basic Usage

import { NudgeCampaign } from '@nudgecampaign/sdk';

const client = new NudgeCampaign({
  apiKey: process.env.NUDGECAMPAIGN_API_KEY,
  organizationId: process.env.ORGANIZATION_ID
});

// Create a contact
const contact = await client.contacts.create({
  email: 'user@example.com',
  firstName: 'John',
  lastName: 'Doe',
  customFields: {
    company: 'Acme Corp'
  }
});

// Send a campaign
const campaign = await client.campaigns.create({
  name: 'Newsletter',
  subject: 'Weekly Update',
  content: {
    html: '<h1>Hello {{firstName}}</h1>',
    text: 'Hello {{firstName}}'
  },
  lists: ['lst_newsletter']
});

await client.campaigns.send(campaign.id);

Advanced Features

// Batch operations with error handling
try {
  const results = await client.contacts.batch({
    operations: [
      { method: 'create', data: { email: 'user1@example.com' } },
      { method: 'update', id: 'cnt_abc123', data: { firstName: 'Jane' } },
      { method: 'delete', id: 'cnt_xyz789' }
    ]
  });
  
  results.forEach((result, index) => {
    if (result.error) {
      console.error(`Operation ${index} failed:`, result.error);
    }
  });
} catch (error) {
  console.error('Batch operation failed:', error);
}

// Stream large datasets
const contactStream = client.contacts.stream({
  filter: { status: 'subscribed' },
  batchSize: 100
});

contactStream.on('data', (contacts) => {
  console.log(`Processing ${contacts.length} contacts`);
});

contactStream.on('error', (error) => {
  console.error('Stream error:', error);
});

contactStream.on('end', () => {
  console.log('Stream completed');
});

Python SDK

Installation

pip install nudgecampaign

Usage

from nudgecampaign import Client
from nudgecampaign.exceptions import NudgeCampaignError

client = Client(
    api_key='YOUR_API_KEY',
    organization_id='YOUR_ORG_ID'
)

# Create contact with error handling
try:
    contact = client.contacts.create(
        email='user@example.com',
        first_name='John',
        last_name='Doe',
        custom_fields={'company': 'Acme Corp'}
    )
    print(f"Contact created: {contact.id}")
except NudgeCampaignError as e:
    print(f"Error: {e.message}")

# Query contacts
contacts = client.contacts.list(
    filter={'tags': 'customer'},
    sort='created_at:desc',
    limit=50
)

for contact in contacts:
    print(f"{contact.email}: {contact.first_name} {contact.last_name}")

# Async operations
import asyncio

async def send_campaigns():
    campaigns = await client.campaigns.list_async(status='draft')
    
    tasks = []
    for campaign in campaigns:
        task = client.campaigns.send_async(campaign.id)
        tasks.append(task)
    
    results = await asyncio.gather(*tasks)
    return results

asyncio.run(send_campaigns())

PHP SDK

Installation

composer require nudgecampaign/php-sdk

Usage

<?php
use NudgeCampaign\Client;
use NudgeCampaign\Resources\Contact;
use NudgeCampaign\Exceptions\ApiException;

$client = new Client([
    'apiKey' => $_ENV['NUDGECAMPAIGN_API_KEY'],
    'organizationId' => $_ENV['ORGANIZATION_ID']
]);

// Create contact
try {
    $contact = $client->contacts->create([
        'email' => 'user@example.com',
        'firstName' => 'John',
        'lastName' => 'Doe',
        'customFields' => [
            'company' => 'Acme Corp'
        ]
    ]);
    
    echo "Contact created: " . $contact->id . "\n";
} catch (ApiException $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

// List campaigns
$campaigns = $client->campaigns->list([
    'status' => 'sent',
    'from_date' => '2024-01-01',
    'limit' => 10
]);

foreach ($campaigns as $campaign) {
    $analytics = $client->campaigns->analytics($campaign->id);
    echo sprintf(
        "%s: Sent %d, Opens %d (%.1f%%)\n",
        $campaign->name,
        $analytics->sent,
        $analytics->opened,
        $analytics->metrics->openRate
    );
}

Data Synchronization

Synchronization Patterns

Real-time Sync

// WebSocket connection for real-time updates
const WebSocket = require('ws');

const ws = new WebSocket('wss://sync.nudgecampaign.com/v1/stream', {
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'X-Organization-ID': ORG_ID
  }
});

ws.on('open', () => {
  // Subscribe to events
  ws.send(JSON.stringify({
    action: 'subscribe',
    events: ['contact.*', 'campaign.*']
  }));
});

ws.on('message', (data) => {
  const event = JSON.parse(data);
  
  switch (event.type) {
    case 'contact.created':
      syncContactToExternalSystem(event.data);
      break;
    case 'campaign.sent':
      updateCampaignMetrics(event.data);
      break;
  }
});

ws.on('error', (error) => {
  console.error('WebSocket error:', error);
  // Implement reconnection logic
});

Batch Synchronization

// Scheduled batch sync job
const cron = require('node-cron');

cron.schedule('0 */4 * * *', async () => {
  console.log('Starting batch synchronization');
  
  const lastSyncTime = await getLastSyncTime();
  
  // Export modified contacts
  const modifiedContacts = await client.contacts.list({
    filter: `updated_at > ${lastSyncTime}`,
    limit: 1000
  });
  
  // Process in chunks
  const chunks = chunk(modifiedContacts, 100);
  
  for (const contactChunk of chunks) {
    await syncContactsToExternalSystem(contactChunk);
  }
  
  await updateLastSyncTime(new Date());
  console.log('Batch synchronization completed');
});

Conflict Resolution

// Conflict resolution strategies
class ConflictResolver {
  constructor(strategy = 'last_write_wins') {
    this.strategy = strategy;
  }
  
  async resolve(localData, remoteData) {
    switch (this.strategy) {
      case 'last_write_wins':
        return this.lastWriteWins(localData, remoteData);
        
      case 'merge':
        return this.mergeChanges(localData, remoteData);
        
      case 'manual':
        return this.requireManualResolution(localData, remoteData);
        
      default:
        throw new Error(`Unknown strategy: ${this.strategy}`);
    }
  }
  
  lastWriteWins(local, remote) {
    const localTime = new Date(local.updatedAt);
    const remoteTime = new Date(remote.updatedAt);
    
    return localTime > remoteTime ? local : remote;
  }
  
  mergeChanges(local, remote) {
    // Deep merge with field-level timestamps
    const merged = { ...local };
    
    for (const field in remote) {
      if (remote[field]._updated > local[field]._updated) {
        merged[field] = remote[field];
      }
    }
    
    return merged;
  }
  
  async requireManualResolution(local, remote) {
    // Queue for manual review
    await queueConflict({
      type: 'data_conflict',
      local: local,
      remote: remote,
      timestamp: new Date()
    });
    
    throw new Error('Manual resolution required');
  }
}

Integration Patterns

Event-Driven Architecture

// Event bus for decoupled integrations
class IntegrationEventBus {
  constructor() {
    this.handlers = new Map();
  }
  
  on(event, handler) {
    if (!this.handlers.has(event)) {
      this.handlers.set(event, []);
    }
    this.handlers.get(event).push(handler);
  }
  
  async emit(event, data) {
    const eventHandlers = this.handlers.get(event) || [];
    
    const results = await Promise.allSettled(
      eventHandlers.map(handler => handler(data))
    );
    
    results.forEach((result, index) => {
      if (result.status === 'rejected') {
        console.error(
          `Handler ${index} for ${event} failed:`,
          result.reason
        );
      }
    });
  }
}

const eventBus = new IntegrationEventBus();

// Register integration handlers
eventBus.on('contact.created', async (contact) => {
  await syncToSalesforce(contact);
  await addToMailchimp(contact);
  await updateAnalytics(contact);
});

eventBus.on('order.completed', async (order) => {
  await updateContactLifetimeValue(order);
  await triggerPostPurchaseFlow(order);
});

Data Transformation

// Transform data between systems
class DataTransformer {
  constructor(mappings) {
    this.mappings = mappings;
  }
  
  transform(source, targetSystem) {
    const mapping = this.mappings[targetSystem];
    if (!mapping) {
      throw new Error(`No mapping for ${targetSystem}`);
    }
    
    const transformed = {};
    
    for (const [sourceField, targetField] of Object.entries(mapping.fields)) {
      const value = this.getNestedValue(source, sourceField);
      
      if (value !== undefined) {
        const transformedValue = mapping.transforms?.[sourceField]
          ? mapping.transforms[sourceField](value)
          : value;
        
        this.setNestedValue(transformed, targetField, transformedValue);
      }
    }
    
    return transformed;
  }
  
  getNestedValue(obj, path) {
    return path.split('.').reduce((acc, part) => acc?.[part], obj);
  }
  
  setNestedValue(obj, path, value) {
    const parts = path.split('.');
    const last = parts.pop();
    const nested = parts.reduce((acc, part) => {
      if (!acc[part]) acc[part] = {};
      return acc[part];
    }, obj);
    nested[last] = value;
  }
}

// Usage
const transformer = new DataTransformer({
  salesforce: {
    fields: {
      'email': 'Email',
      'firstName': 'FirstName',
      'lastName': 'LastName',
      'customFields.company': 'Account.Name',
      'tags': 'Tags__c'
    },
    transforms: {
      'tags': (tags) => tags.join(';')
    }
  }
});

const salesforceContact = transformer.transform(nudgeContact, 'salesforce');

Testing & Debugging

Integration Testing

// Test webhook endpoints
const request = require('supertest');
const app = require('./app');

describe('Webhook Integration', () => {
  test('handles contact.created webhook', async () => {
    const webhook = {
      event: 'contact.created',
      data: {
        id: 'cnt_test123',
        email: 'test@example.com'
      }
    };
    
    const signature = generateWebhookSignature(webhook);
    
    const response = await request(app)
      .post('/webhooks/nudgecampaign')
      .set('X-NudgeCampaign-Signature', signature)
      .send(webhook);
    
    expect(response.status).toBe(200);
    // Verify side effects
    const contact = await getContactFromDatabase('test@example.com');
    expect(contact).toBeDefined();
    expect(contact.nudgeId).toBe('cnt_test123');
  });
  
  test('rejects invalid webhook signature', async () => {
    const response = await request(app)
      .post('/webhooks/nudgecampaign')
      .set('X-NudgeCampaign-Signature', 'invalid')
      .send({ event: 'test' });
    
    expect(response.status).toBe(401);
  });
});

Debugging Tools

// Request/Response logger middleware
class IntegrationLogger {
  constructor(options = {}) {
    this.logLevel = options.logLevel || 'info';
    this.logFile = options.logFile || './integration.log';
  }
  
  logRequest(request) {
    const log = {
      timestamp: new Date().toISOString(),
      type: 'request',
      method: request.method,
      url: request.url,
      headers: this.sanitizeHeaders(request.headers),
      body: this.sanitizeBody(request.body)
    };
    
    this.writeLog(log);
  }
  
  logResponse(response) {
    const log = {
      timestamp: new Date().toISOString(),
      type: 'response',
      status: response.status,
      headers: response.headers,
      body: this.sanitizeBody(response.body),
      duration: response.duration
    };
    
    this.writeLog(log);
  }
  
  sanitizeHeaders(headers) {
    const sanitized = { ...headers };
    if (sanitized.authorization) {
      sanitized.authorization = 'Bearer [REDACTED]';
    }
    return sanitized;
  }
  
  sanitizeBody(body) {
    if (!body) return body;
    
    const sanitized = JSON.parse(JSON.stringify(body));
    const sensitiveFields = ['password', 'apiKey', 'secret'];
    
    const sanitizeObject = (obj) => {
      for (const key in obj) {
        if (sensitiveFields.includes(key)) {
          obj[key] = '[REDACTED]';
        } else if (typeof obj[key] === 'object') {
          sanitizeObject(obj[key]);
        }
      }
    };
    
    sanitizeObject(sanitized);
    return sanitized;
  }
  
  writeLog(log) {
    console.log(JSON.stringify(log));
    // Also write to file
    fs.appendFileSync(this.logFile, JSON.stringify(log) + '\n');
  }
}

Migration Guides

Migrating from MailChimp

Step 1: Export MailChimp Data

const Mailchimp = require('@mailchimp/mailchimp_marketing');

Mailchimp.setConfig({
  apiKey: process.env.MAILCHIMP_API_KEY,
  server: process.env.MAILCHIMP_SERVER_PREFIX,
});

async function exportMailchimpData() {
  // Export lists
  const lists = await Mailchimp.lists.getAllLists();
  
  for (const list of lists.lists) {
    // Export list members
    const members = await Mailchimp.lists.getListMembersInfo(
      list.id,
      { count: 1000 }
    );
    
    // Transform to NudgeCampaign format
    const contacts = members.members.map(member => ({
      email: member.email_address,
      firstName: member.merge_fields.FNAME,
      lastName: member.merge_fields.LNAME,
      status: member.status === 'subscribed' ? 'subscribed' : 'unsubscribed',
      tags: member.tags.map(t => t.name),
      customFields: member.merge_fields,
      mailchimpId: member.id
    }));
    
    // Import to NudgeCampaign
    await nudgeCampaignAPI.contacts.bulkCreate(contacts);
    
    // Export campaigns
    const campaigns = await Mailchimp.campaigns.list({ list_id: list.id });
    
    for (const campaign of campaigns.campaigns) {
      await migrateCampaign(campaign);
    }
  }
}

Step 2: Map Custom Fields

const fieldMapping = {
  'FNAME': 'firstName',
  'LNAME': 'lastName',
  'COMPANY': 'customFields.company',
  'PHONE': 'customFields.phone',
  'ADDRESS': 'customFields.address',
  'BIRTHDAY': 'customFields.birthday'
};

function mapMailchimpFields(mergeFields) {
  const mapped = {};
  
  for (const [mcField, value] of Object.entries(mergeFields)) {
    const nudgeField = fieldMapping[mcField];
    if (nudgeField) {
      if (nudgeField.includes('.')) {
        const [parent, child] = nudgeField.split('.');
        if (!mapped[parent]) mapped[parent] = {};
        mapped[parent][child] = value;
      } else {
        mapped[nudgeField] = value;
      }
    }
  }
  
  return mapped;
}

Migrating from SendGrid

const sgClient = require('@sendgrid/client');
sgClient.setApiKey(process.env.SENDGRID_API_KEY);

async function migrateSendGridContacts() {
  // Export all contacts
  const [response] = await sgClient.request({
    method: 'POST',
    url: '/v3/marketing/contacts/exports',
    body: {
      file_type: 'json',
      max_file_size: 5000
    }
  });
  
  // Poll for export completion
  const exportId = response.body.id;
  let exportReady = false;
  
  while (!exportReady) {
    const [status] = await sgClient.request({
      method: 'GET',
      url: `/v3/marketing/contacts/exports/${exportId}`
    });
    
    if (status.body.status === 'ready') {
      exportReady = true;
      const downloadUrl = status.body.urls[0];
      
      // Download and process contacts
      const contacts = await downloadExport(downloadUrl);
      
      // Transform and import
      const nudgeContacts = contacts.map(contact => ({
        email: contact.email,
        firstName: contact.first_name,
        lastName: contact.last_name,
        customFields: contact.custom_fields,
        lists: contact.list_ids,
        createdAt: contact.created_at,
        updatedAt: contact.updated_at
      }));
      
      await nudgeCampaignAPI.contacts.bulkCreate(nudgeContacts);
    }
    
    await sleep(5000); // Wait 5 seconds before polling again
  }
}

Best Practices

API Usage Best Practices

  1. Use Batch Operations: For bulk operations, use batch endpoints instead of making individual requests
  2. Implement Retry Logic: Handle transient failures with exponential backoff
  3. Cache Responses: Cache frequently accessed data to reduce API calls
  4. Use Webhooks: Prefer webhooks over polling for real-time updates
  5. Paginate Large Datasets: Always paginate when fetching large amounts of data

Security Best Practices

  1. Secure API Keys: Never expose API keys in client-side code
  2. Use HTTPS: Always use HTTPS for API communication
  3. Validate Webhooks: Always verify webhook signatures
  4. Implement Rate Limiting: Respect rate limits to avoid service disruption
  5. Audit Integration Access: Regularly review and audit integration permissions

Data Management Best Practices

  1. Handle Duplicates: Implement deduplication logic for contact syncing
  2. Map Fields Carefully: Document and maintain field mappings between systems
  3. Monitor Sync Status: Track synchronization status and handle failures
  4. Backup Before Migration: Always backup data before major migrations
  5. Test in Staging: Test integrations in a staging environment first

Troubleshooting

Common Integration Issues

Authentication Failures

  • Verify API key is correct and active
  • Check organization ID matches
  • Ensure proper OAuth scopes are granted
  • Verify webhook secrets match

Data Sync Issues

  • Check field mapping configuration
  • Verify data types match between systems
  • Ensure required fields are populated
  • Monitor rate limits and quotas

Webhook Delivery Failures

  • Verify endpoint URL is accessible
  • Check SSL certificate validity
  • Ensure response times are under 30 seconds
  • Implement proper error handling

Debug Checklist

  1. Check API Logs: Review API request/response logs
  2. Verify Credentials: Ensure all credentials are valid
  3. Test Connectivity: Verify network connectivity
  4. Review Error Messages: Check detailed error responses
  5. Monitor Rate Limits: Check rate limit headers
  6. Validate Data Format: Ensure data meets API requirements
  7. Check Webhook Logs: Review webhook delivery attempts
  8. Test in Isolation: Test integration components separately

Support Resources

Documentation

Developer Tools

Community & Support

Conclusion

This integration documentation provides comprehensive guidance for connecting NudgeCampaign with your existing systems. Whether you're using our REST API, webhooks, SDKs, or pre-built integrations, you have the tools needed to create powerful, automated marketing workflows.

Remember to follow best practices for security, error handling, and data management. Our support team is available to help with complex integration scenarios or custom requirements.

For the latest updates and new integration features, subscribe to our developer newsletter at developers.nudgecampaign.com/newsletter.