Skip to main content

Node.js Examples

Complete examples showing how to use the Posthoot API with Node.js.

📦 Installation

First, install the required dependencies:
npm install axios dotenv

🔧 Setup

Create a .env file for your configuration:
POSTHOOT_API_URL=https://api.posthoot.com
POSTHOOT_EMAIL=your-email@example.com
POSTHOOT_PASSWORD=your-secure-password

🚀 Basic Setup

const axios = require('axios');
require('dotenv').config();

class PosthootAPI {
  constructor() {
    this.baseURL = process.env.POSTHOOT_API_URL || 'https://api.posthoot.com';
    this.tokens = null;
  }

  // Set default headers for all requests
  setAuthHeaders() {
    if (this.tokens?.access_token) {
      axios.defaults.headers.common['Authorization'] = `Bearer ${this.tokens.access_token}`;
    }
  }

  // Handle API errors
  handleError(error) {
    if (error.response) {
      const { status, data } = error.response;
      switch (status) {
        case 401:
          throw new Error('Authentication failed. Please log in again.');
        case 403:
          throw new Error('Insufficient permissions.');
        case 429:
          throw new Error('Rate limit exceeded. Please wait before trying again.');
        default:
          throw new Error(data.message || 'An error occurred');
      }
    } else {
      throw new Error('Network error');
    }
  }
}

🔐 Authentication Examples

Register New User

async register(email, password, firstName, lastName) {
  try {
    const response = await axios.post(`${this.baseURL}/auth/register`, {
      email,
      password,
      first_name: firstName,
      last_name: lastName
    });

    this.tokens = {
      access_token: response.data.access_token,
      refresh_token: response.data.refresh_token
    };

    this.setAuthHeaders();
    return response.data;
  } catch (error) {
    this.handleError(error);
  }
}

// Usage
const api = new PosthootAPI();
await api.register(
  'john.doe@example.com',
  'secure_password123',
  'John',
  'Doe'
);

Login Existing User

async login(email, password) {
  try {
    const response = await axios.post(`${this.baseURL}/auth/login`, {
      email,
      password
    });

    this.tokens = {
      access_token: response.data.access_token,
      refresh_token: response.data.refresh_token
    };

    this.setAuthHeaders();
    return response.data;
  } catch (error) {
    this.handleError(error);
  }
}

// Usage
await api.login('john.doe@example.com', 'secure_password123');

Refresh Token

async refreshToken() {
  try {
    const response = await axios.post(`${this.baseURL}/auth/refresh`, {
      refresh_token: this.tokens.refresh_token
    });

    this.tokens = {
      access_token: response.data.access_token,
      refresh_token: response.data.refresh_token
    };

    this.setAuthHeaders();
    return response.data;
  } catch (error) {
    // If refresh fails, redirect to login
    this.tokens = null;
    throw new Error('Session expired. Please log in again.');
  }
}

📧 Email Examples

Send Simple Email

async sendEmail(to, subject, html, options = {}) {
  try {
    const response = await axios.post(`${this.baseURL}/email`, {
      to,
      subject,
      html,
      provider: options.provider || 'CUSTOM',
      data: options.data || [],
      cc: options.cc,
      bcc: options.bcc,
      replyTo: options.replyTo,
      test: options.test || false
    });

    return response.data;
  } catch (error) {
    this.handleError(error);
  }
}

// Usage
const emailResult = await api.sendEmail(
  'recipient@example.com',
  'Welcome to Posthoot!',
  '<h1>Hello!</h1><p>This is a test email sent via the Posthoot API.</p>',
  {
    test: true // Send as test email
  }
);

Send Email with Template

async sendEmailWithTemplate(to, templateId, data, options = {}) {
  try {
    const response = await axios.post(`${this.baseURL}/email`, {
      to,
      templateId,
      data,
      provider: options.provider || 'CUSTOM',
      cc: options.cc,
      bcc: options.bcc,
      replyTo: options.replyTo,
      test: options.test || false
    });

    return response.data;
  } catch (error) {
    this.handleError(error);
  }
}

// Usage
const templateData = [
  { name: 'John', company: 'Acme Corp' },
  { name: 'Jane', company: 'Tech Inc' }
];

const emailResult = await api.sendEmailWithTemplate(
  'recipient@example.com',
  'template_123',
  templateData,
  { test: true }
);

Send Bulk Email

async sendBulkEmails(recipients, subject, html, options = {}) {
  const results = [];
  const batchSize = options.batchSize || 100;
  
  for (let i = 0; i < recipients.length; i += batchSize) {
    const batch = recipients.slice(i, i + batchSize);
    
    const promises = batch.map(recipient => 
      this.sendEmail(recipient.email, subject, html, {
        ...options,
        data: recipient.data || []
      })
    );
    
    const batchResults = await Promise.allSettled(promises);
    results.push(...batchResults);
    
    // Rate limiting - wait between batches
    if (i + batchSize < recipients.length) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
  
  return results;
}

// Usage
const recipients = [
  { email: 'user1@example.com', data: [{ name: 'John' }] },
  { email: 'user2@example.com', data: [{ name: 'Jane' }] },
  { email: 'user3@example.com', data: [{ name: 'Bob' }] }
];

const results = await api.sendBulkEmails(
  recipients,
  'Special Offer!',
  '<h1>Hello {{name}}!</h1><p>Check out our special offer.</p>',
  { batchSize: 50 }
);

📊 Analytics Examples

Get Email Analytics

async getEmailAnalytics(emailId) {
  try {
    const response = await axios.get(`${this.baseURL}/api/v1/analytics/email`, {
      params: { emailId }
    });

    return response.data;
  } catch (error) {
    this.handleError(error);
  }
}

// Usage
const analytics = await api.getEmailAnalytics('email_123');
console.log('Open Rate:', analytics.openRate);
console.log('Click Rate:', analytics.clickRate);
console.log('Engagement Score:', analytics.engagementScore);

Get Campaign Analytics

async getCampaignAnalytics(campaignId) {
  try {
    const response = await axios.get(`${this.baseURL}/api/v1/analytics/campaign`, {
      params: { campaignId }
    });

    return response.data;
  } catch (error) {
    this.handleError(error);
  }
}

// Usage
const campaignAnalytics = await api.getCampaignAnalytics('campaign_123');

// Create charts data
const geoData = Object.entries(campaignAnalytics.geoBreakdown).map(([country, count]) => ({
  country,
  opens: count
}));

const deviceData = Object.entries(campaignAnalytics.deviceBreakdown).map(([device, count]) => ({
  device,
  opens: count
}));

console.log('Geographic Data:', geoData);
console.log('Device Data:', deviceData);

Compare Campaigns

async compareCampaigns(campaignIds) {
  try {
    const response = await axios.get(`${this.baseURL}/api/v1/analytics/campaign/compare`, {
      params: { campaignIds: campaignIds.join(',') }
    });

    return response.data;
  } catch (error) {
    this.handleError(error);
  }
}

// Usage
const comparison = await api.compareCampaigns(['campaign_1', 'campaign_2', 'campaign_3']);

Object.entries(comparison).forEach(([campaignId, analytics]) => {
  console.log(`Campaign ${campaignId}:`);
  console.log(`  Open Rate: ${analytics.openRate}`);
  console.log(`  Click Rate: ${analytics.clickRate}`);
  console.log(`  Engagement Score: ${analytics.engagementScore}`);
});

🔄 Webhook Examples

Set Up Webhook Server

const express = require('express');
const crypto = require('crypto');

const app = express();
app.use(express.json());

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

// Handle email events
app.post('/webhook/email-events', (req, res) => {
  const signature = req.headers['x-posthoot-signature'];
  const secret = process.env.WEBHOOK_SECRET;
  
  if (!verifyWebhookSignature(req.body, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }
  
  const { event, data } = req.body;
  
  switch (event) {
    case 'email.opened':
      console.log('Email opened:', data.emailId, data.recipient);
      break;
    case 'email.clicked':
      console.log('Email clicked:', data.emailId, data.recipient, data.url);
      break;
    case 'email.bounced':
      console.log('Email bounced:', data.emailId, data.recipient, data.reason);
      break;
    case 'email.complained':
      console.log('Email complained:', data.emailId, data.recipient);
      break;
  }
  
  res.status(200).send('OK');
});

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});

📁 File Upload Examples

Upload File

const FormData = require('form-data');
const fs = require('fs');

async uploadFile(filePath, options = {}) {
  try {
    const formData = new FormData();
    formData.append('file', fs.createReadStream(filePath));
    
    const response = await axios.post(`${this.baseURL}/api/v1/files/upload`, formData, {
      headers: {
        ...formData.getHeaders(),
        'Authorization': `Bearer ${this.tokens.access_token}`
      }
    });

    return response.data;
  } catch (error) {
    this.handleError(error);
  }
}

// Usage
const fileResult = await api.uploadFile('./logo.png', {
  description: 'Company logo'
});
console.log('File uploaded:', fileResult.fileId);

🛡️ Error Handling & Retry Logic

class PosthootAPIWithRetry extends PosthootAPI {
  async makeRequestWithRetry(requestFn, maxRetries = 3) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await requestFn();
      } catch (error) {
        if (error.message.includes('rate_limit') && attempt < maxRetries) {
          const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
          console.log(`Rate limited. Retrying in ${delay}ms...`);
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
        
        if (error.message.includes('unauthorized') && attempt < maxRetries) {
          console.log('Token expired. Refreshing...');
          await this.refreshToken();
          continue;
        }
        
        throw error;
      }
    }
  }

  async sendEmailWithRetry(to, subject, html, options = {}) {
    return this.makeRequestWithRetry(() => 
      this.sendEmail(to, subject, html, options)
    );
  }
}

// Usage
const apiWithRetry = new PosthootAPIWithRetry();
await apiWithRetry.login('user@example.com', 'password');

const result = await apiWithRetry.sendEmailWithRetry(
  'recipient@example.com',
  'Test Email',
  '<h1>Hello!</h1>'
);

📊 Monitoring & Logging

const winston = require('winston');

// Set up logging
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.File({ filename: 'posthoot-api.log' }),
    new winston.transports.Console()
  ]
});

class PosthootAPIWithLogging extends PosthootAPI {
  async sendEmail(to, subject, html, options = {}) {
    const startTime = Date.now();
    
    try {
      logger.info('Sending email', { to, subject, options });
      
      const result = await super.sendEmail(to, subject, html, options);
      
      const duration = Date.now() - startTime;
      logger.info('Email sent successfully', { 
        emailId: result.emailId, 
        duration,
        to 
      });
      
      return result;
    } catch (error) {
      const duration = Date.now() - startTime;
      logger.error('Email send failed', { 
        error: error.message, 
        duration,
        to 
      });
      throw error;
    }
  }
}

📚 Complete Example

Here’s a complete working example:
const axios = require('axios');
const winston = require('winston');
require('dotenv').config();

// Set up logging
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.json()
  ),
  transports: [
    new winston.transports.Console()
  ]
});

class PosthootAPI {
  constructor() {
    this.baseURL = process.env.POSTHOOT_API_URL || 'https://api.posthoot.com';
    this.tokens = null;
  }

  setAuthHeaders() {
    if (this.tokens?.access_token) {
      axios.defaults.headers.common['Authorization'] = `Bearer ${this.tokens.access_token}`;
    }
  }

  handleError(error) {
    if (error.response) {
      const { status, data } = error.response;
      logger.error('API Error', { status, data });
      
      switch (status) {
        case 401:
          throw new Error('Authentication failed');
        case 403:
          throw new Error('Insufficient permissions');
        case 429:
          throw new Error('Rate limit exceeded');
        default:
          throw new Error(data.message || 'An error occurred');
      }
    } else {
      throw new Error('Network error');
    }
  }

  async login(email, password) {
    try {
      const response = await axios.post(`${this.baseURL}/auth/login`, {
        email,
        password
      });

      this.tokens = {
        access_token: response.data.access_token,
        refresh_token: response.data.refresh_token
      };

      this.setAuthHeaders();
      logger.info('Login successful', { email });
      return response.data;
    } catch (error) {
      this.handleError(error);
    }
  }

  async sendEmail(to, subject, html, options = {}) {
    try {
      const response = await axios.post(`${this.baseURL}/email`, {
        to,
        subject,
        html,
        provider: options.provider || 'CUSTOM',
        data: options.data || [],
        test: options.test || false
      });

      logger.info('Email sent', { emailId: response.data.emailId, to });
      return response.data;
    } catch (error) {
      this.handleError(error);
    }
  }

  async getEmailAnalytics(emailId) {
    try {
      const response = await axios.get(`${this.baseURL}/api/v1/analytics/email`, {
        params: { emailId }
      });

      return response.data;
    } catch (error) {
      this.handleError(error);
    }
  }
}

// Usage example
async function main() {
  const api = new PosthootAPI();
  
  try {
    // Login
    await api.login(process.env.POSTHOOT_EMAIL, process.env.POSTHOOT_PASSWORD);
    
    // Send email
    const emailResult = await api.sendEmail(
      'recipient@example.com',
      'Hello from Posthoot!',
      '<h1>Welcome</h1><p>This is a test email.</p>',
      { test: true }
    );
    
    // Check analytics
    const analytics = await api.getEmailAnalytics(emailResult.emailId);
    logger.info('Email analytics', analytics);
    
  } catch (error) {
    logger.error('Application error', { error: error.message });
  }
}

if (require.main === module) {
  main();
}

module.exports = PosthootAPI;