Integrations

Connect external services and APIs with Appivo

Integrations Example

Learn to integrate external services with your Appivo applications.

What You'll Build

Integration patterns including:

  • Calling external REST APIs
  • Receiving webhooks from external systems
  • Sending notifications via third-party services
  • Synchronizing data with external platforms

Prerequisites

Example 1: Call External API

Fetch customer credit score from external service.

Create the Rule

Rule: Check Customer Credit
Type: DATA
Trigger: When Customer is created

Add SCRIPT Action with HTTP Call

exports.execute = async function(context, params) {
    const customer = params.record;

    // Call external credit API
    const response = await context.http({
        url: 'https://creditcheck.example.com/api/check',
        method: 'POST',
        headers: {
            'Authorization': 'Bearer ' + context.getConfig('credit_api_key'),
            'Content-Type': 'application/json'
        },
        data: {
            name: customer.name,
            tax_id: customer.tax_id
        }
    });

    if (response.status === 200) {
        // Update customer with credit score
        await context.updateRecord('Customer', customer.id, {
            credit_score: response.data.score,
            credit_checked_at: new Date()
        });

        return { success: true, score: response.data.score };
    }

    return {
        success: false,
        error: 'Credit check failed: ' + response.status
    };
};

Example 2: Receive Webhooks

Accept incoming data from external systems.

Create REST Rule

Rule: Receive External Order
Type: REST
Endpoint: /api/external-orders
Method: POST
Authentication: API Key

Add SCRIPT Action

exports.execute = async function(context, params) {
    // Access incoming webhook data
    const webhookData = params.body;

    // Validate required fields
    if (!webhookData.order_id || !webhookData.customer_id) {
        return {
            status: 400,
            error: 'Missing required fields: order_id, customer_id'
        };
    }

    // Check if order already exists
    const existing = await context.findOne('Order', {
        filter: { external_id: webhookData.order_id }
    });

    if (existing) {
        return {
            status: 200,
            message: 'Order already exists',
            order_id: existing.id
        };
    }

    // Create new order
    const order = await context.createRecord('Order', {
        external_id: webhookData.order_id,
        customer_id: webhookData.customer_id,
        items: webhookData.items,
        total: webhookData.total,
        status: 'New',
        source: 'External API'
    });

    return {
        status: 201,
        message: 'Order created',
        order_id: order.id
    };
};

Using the Endpoint

External systems call your endpoint:

POST https://your-app.appivo.com/api/external-orders
Headers:
  X-API-Key: your-api-key
  Content-Type: application/json
Body:
  {
    "order_id": "EXT-12345",
    "customer_id": "CUST-789",
    "items": [...],
    "total": 99.99
  }

Example 3: Send to Slack

Post notifications to Slack channel.

Create WEBHOOK Action

Action: Notify Slack
Type: WEBHOOK
URL: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
Method: POST
Headers:
  Content-Type: application/json
Body:
  {
    "text": "New order received!",
    "blocks": [
      {
        "type": "section",
        "text": {
          "type": "mrkdwn",
          "text": "*Order:* {{order.order_number}}\n*Customer:* {{order.customer_name}}\n*Total:* ${{order.total}}"
        }
      }
    ]
  }

Example 4: Payment Gateway Integration

Process payments through external gateway.

Create Payment Rule

Rule: Process Payment
Type: MANUAL
Triggered by: User clicks "Charge Card" button

Add SCRIPT Action

exports.execute = async function(context, params) {
    const order = params.record;

    // Get payment method (stored separately for security)
    const paymentMethod = await context.getRecord(
        'PaymentMethod',
        order.payment_method_id
    );

    try {
        // Call payment gateway
        const response = await context.http({
            url: 'https://api.paymentgateway.com/v1/charges',
            method: 'POST',
            headers: {
                'Authorization': 'Bearer ' + context.getConfig('payment_secret_key'),
                'Content-Type': 'application/json'
            },
            data: {
                amount: Math.round(order.total * 100), // cents
                currency: 'usd',
                payment_method: paymentMethod.token,
                description: 'Order ' + order.order_number
            }
        });

        if (response.data.status === 'succeeded') {
            // Update order with payment info
            await context.updateRecord('Order', order.id, {
                payment_status: 'Paid',
                payment_id: response.data.id,
                paid_at: new Date()
            });

            return { success: true, payment_id: response.data.id };
        }

        return {
            success: false,
            error: 'Payment failed: ' + response.data.failure_message
        };

    } catch (error) {
        // Log error and return failure
        context.log.error('Payment processing error', error);

        await context.updateRecord('Order', order.id, {
            payment_status: 'Failed',
            payment_error: error.message
        });

        return { success: false, error: error.message };
    }
};

Example 5: Two-Way Data Sync

Synchronize data with external CRM.

Outbound Sync (Appivo → External)

Rule: Sync Customer to CRM
Type: DATA
Trigger: When Customer is created or updated
exports.execute = async function(context, params) {
    const customer = params.record;

    // Prepare data for CRM
    const crmData = {
        email: customer.email,
        first_name: customer.first_name,
        last_name: customer.last_name,
        company: customer.company,
        phone: customer.phone
    };

    // Determine if create or update
    const method = customer.crm_id ? 'PUT' : 'POST';
    const url = customer.crm_id
        ? `https://api.crm.com/contacts/${customer.crm_id}`
        : 'https://api.crm.com/contacts';

    const response = await context.http({
        url: url,
        method: method,
        headers: {
            'Authorization': 'Bearer ' + context.getConfig('crm_api_key'),
            'Content-Type': 'application/json'
        },
        data: crmData
    });

    // Store CRM ID if new contact
    if (!customer.crm_id && response.status === 201) {
        await context.updateRecord('Customer', customer.id, {
            crm_id: response.data.id,
            synced_at: new Date()
        });
    }

    return { success: true };
};

Inbound Sync (External → Appivo)

Rule: Receive CRM Update
Type: REST
Endpoint: /api/crm-webhook
Method: POST
exports.execute = async function(context, params) {
    const crmData = params.body;

    // Find matching customer
    const customer = await context.findOne('Customer', {
        filter: { crm_id: crmData.id }
    });

    if (!customer) {
        return { status: 404, error: 'Customer not found' };
    }

    // Update customer with CRM data
    await context.updateRecord('Customer', customer.id, {
        email: crmData.email,
        first_name: crmData.first_name,
        last_name: crmData.last_name,
        company: crmData.company,
        synced_at: new Date()
    });

    return { status: 200, message: 'Customer updated' };
};

Example 6: File Upload to Cloud Storage

Upload documents to external storage.

exports.execute = async function(context, params) {
    const document = params.record;

    // Get file content
    const fileContent = await context.getFile(document.file_id);

    // Upload to cloud storage
    const response = await context.http({
        url: 'https://storage.example.com/upload',
        method: 'POST',
        headers: {
            'Authorization': 'Bearer ' + context.getConfig('storage_api_key'),
            'Content-Type': 'multipart/form-data'
        },
        data: {
            file: fileContent,
            filename: document.filename,
            folder: 'documents/' + document.customer_id
        }
    });

    // Store external URL
    await context.updateRecord('Document', document.id, {
        external_url: response.data.url,
        uploaded_at: new Date()
    });

    return { success: true, url: response.data.url };
};

Storing API Credentials

Never hardcode API keys. Use configuration:

Setting Configuration

Application Settings → Configuration
  - payment_api_key: sk_live_xxx...
  - crm_api_key: abc123...
  - slack_webhook: https://hooks.slack.com/...

Accessing in Scripts

const apiKey = context.getConfig('payment_api_key');

Error Handling

Retry Configuration

WEBHOOK Action:
  Retry: 3 attempts
  Backoff: Exponential (1s, 2s, 4s)
  On failure: Log and alert

Script Error Handling

try {
    const response = await context.http({...});

    if (response.status >= 400) {
        throw new Error(`API error: ${response.status}`);
    }

    return { success: true, data: response.data };

} catch (error) {
    context.log.error('Integration failed', {
        error: error.message,
        record_id: params.record.id
    });

    // Optionally create error record for monitoring
    await context.createRecord('IntegrationError', {
        type: 'API Call Failed',
        message: error.message,
        record_type: 'Order',
        record_id: params.record.id
    });

    return { success: false, error: error.message };
}

Best Practices

Security

  1. Store credentials in configuration, not code
  2. Use HTTPS for all external calls
  3. Validate incoming webhook signatures
  4. Implement rate limiting

Reliability

  1. Implement retry logic
  2. Handle timeouts gracefully
  3. Log all integration activity
  4. Monitor for failures

Performance

  1. Use async processing for slow APIs
  2. Batch requests when possible
  3. Cache responses when appropriate
  4. Set reasonable timeouts

Monitoring

  1. Log all API calls
  2. Track success/failure rates
  3. Alert on repeated failures
  4. Review integration health regularly

Next Steps