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
- Completed the Rules and Actions example
- Understanding of REST APIs and webhooks
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
- Store credentials in configuration, not code
- Use HTTPS for all external calls
- Validate incoming webhook signatures
- Implement rate limiting
Reliability
- Implement retry logic
- Handle timeouts gracefully
- Log all integration activity
- Monitor for failures
Performance
- Use async processing for slow APIs
- Batch requests when possible
- Cache responses when appropriate
- Set reasonable timeouts
Monitoring
- Log all API calls
- Track success/failure rates
- Alert on repeated failures
- Review integration health regularly
Next Steps
- AI Integration - Add intelligent automation
- API Integration Guide - Complete integration reference
- Rules and Actions - More automation patterns
- Security Guide - Securing integrations