Skip to content

Invoice Management

This example demonstrates how to integrate with the Engagifii API using JavaScript.

Code Example

javascript
/**
 * Engagifii Revenue API - Node.js Integration Example
 * Invoice Management System
 * 
 * This example demonstrates a complete invoice management integration
 * including authentication, invoice creation, payment processing, and error handling.
 */

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

// Load environment variables
dotenv.config();

/**
 * Revenue API Client Class
 * Handles authentication, request management, and error handling
 */
class RevenueAPIClient {
  constructor(config) {
    this.baseURL = config.baseURL || 'https://engagifii-prod-revenue.azurewebsites.net';
    this.clientId = config.clientId;
    this.clientSecret = config.clientSecret;
    this.tenantCode = config.tenantCode;
    this.apiVersion = config.apiVersion || '1.0';
    
    this.accessToken = null;
    this.tokenExpiry = null;
    
    // Create axios instance with defaults
    this.client = axios.create({
      baseURL: this.baseURL,
      timeout: 30000,
      headers: {
        'Content-Type': 'application/json',
        'tenant-code': this.tenantCode,
        'api-version': this.apiVersion
      }
    });
    
    // Add request interceptor for authentication
    this.client.interceptors.request.use(
      async (config) => {
        const token = await this.getValidToken();
        config.headers.Authorization = `Bearer ${token}`;
        return config;
      },
      (error) => Promise.reject(error)
    );
    
    // Add response interceptor for error handling
    this.client.interceptors.response.use(
      (response) => response,
      async (error) => {
        if (error.response?.status === 401) {
          // Token expired, refresh and retry
          this.accessToken = null;
          const originalRequest = error.config;
          const token = await this.getValidToken();
          originalRequest.headers.Authorization = `Bearer ${token}`;
          return this.client(originalRequest);
        }
        
        // Format error for better handling
        const formattedError = this.formatError(error);
        return Promise.reject(formattedError);
      }
    );
  }
  
  /**
   * Get valid access token (refresh if needed)
   */
  async getValidToken() {
    if (!this.accessToken || Date.now() >= this.tokenExpiry - 60000) {
      await this.refreshToken();
    }
    return this.accessToken;
  }
  
  /**
   * Refresh OAuth access token
   */
  async refreshToken() {
    try {
      const response = await axios.post(
        `${this.baseURL}/oauth/token`,
        new URLSearchParams({
          grant_type: 'client_credentials',
          client_id: this.clientId,
          client_secret: this.clientSecret,
          scope: 'revenue.api.full'
        }),
        {
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
          }
        }
      );
      
      this.accessToken = response.data.access_token;
      this.tokenExpiry = Date.now() + (response.data.expires_in * 1000);
      
      console.log('✓ Token refreshed successfully');
    } catch (error) {
      console.error('Failed to refresh token:', error.message);
      throw error;
    }
  }
  
  /**
   * Format API errors for better debugging
   */
  formatError(error) {
    if (error.response?.data?.error) {
      const apiError = error.response.data.error;
      const err = new Error(apiError.message || 'API Error');
      err.code = apiError.code;
      err.details = apiError.details;
      err.requestId = apiError.requestId;
      err.status = error.response.status;
      return err;
    }
    return error;
  }
  
  // ============= Invoice Operations =============
  
  /**
   * Create a new invoice
   */
  async createInvoice(invoiceData) {
    const response = await this.client.post('/api/1.0/invoice/manual', {
      customerType: invoiceData.customerType,
      customerId: invoiceData.customerId,
      invoiceDate: invoiceData.invoiceDate || new Date().toISOString().split('T')[0],
      dueDate: invoiceData.dueDate,
      items: invoiceData.items,
      notes: invoiceData.notes,
      sendEmail: invoiceData.sendEmail || false,
      emailTo: invoiceData.emailTo
    });
    
    return response.data;
  }
  
  /**
   * Get invoice details
   */
  async getInvoice(invoiceId) {
    const response = await this.client.get(`/api/1.0/invoice/${invoiceId}`);
    return response.data;
  }
  
  /**
   * List invoices with filtering
   */
  async listInvoices(filters = {}) {
    const response = await this.client.get('/api/1.0/invoice', {
      params: {
        page: filters.page || 1,
        pageSize: filters.pageSize || 20,
        status: filters.status,
        customerId: filters.customerId,
        fromDate: filters.fromDate,
        toDate: filters.toDate,
        sortBy: filters.sortBy || 'invoiceDate',
        sortOrder: filters.sortOrder || 'desc'
      }
    });
    
    return response.data;
  }
  
  /**
   * Send invoice to customer
   */
  async sendInvoice(invoiceId, emailOptions = {}) {
    const response = await this.client.post(`/api/1.0/invoice/send/${invoiceId}`, {
      emailTo: emailOptions.to,
      emailCc: emailOptions.cc,
      emailSubject: emailOptions.subject,
      emailMessage: emailOptions.message,
      attachPdf: emailOptions.attachPdf !== false
    });
    
    return response.data;
  }
  
  /**
   * Mark invoice as void
   */
  async voidInvoice(invoiceId, reason) {
    const response = await this.client.post(`/api/1.0/invoice/${invoiceId}/void`, {
      reason: reason,
      notifyCustomer: true
    });
    
    return response.data;
  }
  
  // ============= Payment Operations =============
  
  /**
   * Process payment for invoices
   */
  async processPayment(paymentData) {
    const response = await this.client.post('/api/1.0/payment', {
      paymentMethod: paymentData.method,
      amount: paymentData.amount,
      paymentDate: paymentData.date || new Date().toISOString().split('T')[0],
      invoices: paymentData.invoices,
      creditCard: paymentData.creditCard,
      billingAddress: paymentData.billingAddress,
      notes: paymentData.notes
    });
    
    return response.data;
  }
  
  /**
   * Get payment details
   */
  async getPayment(paymentId) {
    const response = await this.client.get(`/api/1.0/payment/${paymentId}`);
    return response.data;
  }
  
  /**
   * Process refund
   */
  async processRefund(paymentId, amount, reason) {
    const response = await this.client.post(`/api/1.0/payment/${paymentId}/refund`, {
      amount: amount,
      reason: reason,
      notifyCustomer: true
    });
    
    return response.data;
  }
  
  // ============= Credit Note Operations =============
  
  /**
   * Create credit note
   */
  async createCreditNote(creditNoteData) {
    const response = await this.client.post('/api/1.0/creditNote', {
      customerId: creditNoteData.customerId,
      customerType: creditNoteData.customerType,
      creditNoteDate: creditNoteData.date || new Date().toISOString().split('T')[0],
      creditNoteType: creditNoteData.type || 'Refund',
      items: creditNoteData.items,
      reason: creditNoteData.reason,
      relatedInvoiceId: creditNoteData.invoiceId
    });
    
    return response.data;
  }
  
  /**
   * Apply credit note to invoices
   */
  async applyCreditNote(creditNoteId, applications) {
    const response = await this.client.post(`/api/1.0/creditNote/${creditNoteId}/apply`, {
      invoices: applications
    });
    
    return response.data;
  }
  
  // ============= Subscription Operations =============
  
  /**
   * Create subscription
   */
  async createSubscription(subscriptionData) {
    const response = await this.client.post('/api/1.0/subscription', {
      customerId: subscriptionData.customerId,
      customerType: subscriptionData.customerType,
      planId: subscriptionData.planId,
      startDate: subscriptionData.startDate,
      billingCycle: subscriptionData.billingCycle || 'Monthly',
      price: subscriptionData.price,
      autoRenew: subscriptionData.autoRenew !== false,
      paymentMethodId: subscriptionData.paymentMethodId
    });
    
    return response.data;
  }
  
  /**
   * Cancel subscription
   */
  async cancelSubscription(subscriptionId, reason, type = 'EndOfBillingPeriod') {
    const response = await this.client.post(`/api/1.0/subscription/${subscriptionId}/cancel`, {
      cancellationType: type,
      reason: reason
    });
    
    return response.data;
  }
  
  // ============= Reporting Operations =============
  
  /**
   * Generate report
   */
  async generateReport(reportType, parameters) {
    const response = await this.client.post('/api/1.0/report/generate', {
      reportId: reportType,
      parameters: parameters,
      format: 'json'
    });
    
    return response.data;
  }
  
  /**
   * Get account balance
   */
  async getAccountBalance(customerId, customerType) {
    const response = await this.client.get(
      `/api/1.0/account/balance/statistics/${customerType}/${customerId}`
    );
    
    return response.data;
  }
}

/**
 * Example Usage - Complete Invoice Workflow
 */
async function exampleInvoiceWorkflow() {
  // Initialize API client
  const api = new RevenueAPIClient({
    clientId: process.env.ENGAGIFII_CLIENT_ID,
    clientSecret: process.env.ENGAGIFII_CLIENT_SECRET,
    tenantCode: process.env.ENGAGIFII_TENANT_CODE
  });
  
  try {
    console.log('Starting Invoice Management Workflow\n');
    console.log('=====================================\n');
    
    // 1. Create a new invoice
    console.log('1. Creating new invoice...');
    const invoice = await api.createInvoice({
      customerType: 'Person',
      customerId: '123e4567-e89b-12d3-a456-426614174000',
      dueDate: '2024-02-15',
      items: [
        {
          itemName: 'Professional Services',
          description: 'Consulting services for January 2024',
          quantity: 10,
          unitPrice: 150.00
        },
        {
          itemName: 'Support Package',
          description: 'Monthly support package',
          quantity: 1,
          unitPrice: 500.00
        }
      ],
      notes: 'Payment due within 30 days'
    });
    
    console.log(`✓ Invoice created: ${invoice.invoiceNumber}`);
    console.log(`  Amount: $${invoice.totalAmount}`);
    console.log(`  Status: ${invoice.status}\n`);
    
    // 2. Send invoice to customer
    console.log('2. Sending invoice to customer...');
    await api.sendInvoice(invoice.invoiceId, {
      to: ['customer@example.com'],
      subject: `Invoice ${invoice.invoiceNumber} from Your Company`,
      message: 'Please find attached your invoice. Thank you for your business!'
    });
    
    console.log('✓ Invoice sent successfully\n');
    
    // 3. Process payment
    console.log('3. Processing payment...');
    const payment = await api.processPayment({
      method: 'CreditCard',
      amount: invoice.totalAmount,
      invoices: [
        {
          invoiceId: invoice.invoiceId,
          amount: invoice.totalAmount
        }
      ],
      creditCard: {
        cardNumber: '4111111111111111',
        cardholderName: 'John Doe',
        expiryMonth: '12',
        expiryYear: '2025',
        cvv: '123'
      },
      billingAddress: {
        street1: '123 Main St',
        city: 'New York',
        state: 'NY',
        postalCode: '10001',
        country: 'US'
      }
    });
    
    console.log(`✓ Payment processed: ${payment.paymentId}`);
    console.log(`  Transaction ID: ${payment.transactionId}`);
    console.log(`  Status: ${payment.status}\n`);
    
    // 4. Verify invoice is paid
    console.log('4. Verifying invoice status...');
    const updatedInvoice = await api.getInvoice(invoice.invoiceId);
    console.log(`✓ Invoice status: ${updatedInvoice.status}`);
    console.log(`  Paid amount: $${updatedInvoice.paidAmount}`);
    console.log(`  Balance: $${updatedInvoice.balanceAmount}\n`);
    
    // 5. Generate invoice report
    console.log('5. Generating revenue report...');
    const report = await api.generateReport('revenue-summary', {
      fromDate: '2024-01-01',
      toDate: '2024-01-31',
      groupBy: 'customer'
    });
    
    console.log(`✓ Report generated: ${report.reportId}\n`);
    
    // 6. Check customer balance
    console.log('6. Checking customer account balance...');
    const balance = await api.getAccountBalance(
      '123e4567-e89b-12d3-a456-426614174000',
      'Person'
    );
    
    console.log(`✓ Customer Balance:`);
    console.log(`  Total Revenue: $${balance.totalRevenue}`);
    console.log(`  Outstanding: $${balance.outstandingBalance}`);
    console.log(`  Available Credit: $${balance.availableCredit}\n`);
    
    console.log('=====================================');
    console.log('Workflow completed successfully!');
    
  } catch (error) {
    console.error('\n❌ Error occurred:');
    console.error(`  Code: ${error.code}`);
    console.error(`  Message: ${error.message}`);
    
    if (error.details) {
      console.error('  Details:');
      error.details.forEach(detail => {
        console.error(`    - ${detail.field}: ${detail.message}`);
      });
    }
    
    if (error.requestId) {
      console.error(`  Request ID: ${error.requestId}`);
    }
  }
}

// Run example if this file is executed directly
if (require.main === module) {
  exampleInvoiceWorkflow();
}

// Export for use in other modules
module.exports = {
  RevenueAPIClient,
  exampleInvoiceWorkflow
};

Usage Notes

  • Make sure to replace placeholder values with your actual API credentials
  • Install required dependencies before running this code
  • Refer to the main API documentation for detailed endpoint information

Download

Download this example: invoice-management.js