TL;DR
The Make (formerly Integromat) API enables developers to automate workflows, manage scenarios, and execute integrations programmatically. It uses OAuth 2.0 and API key authentication, RESTful endpoints for scenarios, executions, webhooks, and teams, with rate limits of 60-600 requests per minute depending on plan. This guide covers authentication setup, scenario management, webhook triggers, execution monitoring, and production automation strategies.
Introduction
Make (Integromat) processes over 2 billion operations monthly for 1+ million users across 100+ countries. For developers building automation tools, managing client workflows, or integrating with 1000+ apps, Make API integration isn’t optional—it’s essential for scalable automation.
Here’s the reality: agencies managing 50+ client automations lose 15-25 hours weekly on manual scenario updates, execution monitoring, and client reporting. A solid Make API integration automates scenario deployment, execution tracking, error handling, and white-label reporting.
This guide walks through the complete Make API integration process. You’ll learn OAuth 2.0 and API key authentication, scenario management, webhook triggers, execution monitoring, team management, and production deployment strategies. By the end, you’ll have a production-ready Make integration.
What Is the Make API?
Make provides a RESTful API for managing automation workflows programmatically. The API handles:
- Scenario creation, updates, and deletion
- Scenario execution (manual triggering)
- Execution history and monitoring
- Webhook management
- Team and user management
- Connection and app management
- Organization and workspace settings
Key Features
| Feature | Description |
|---|---|
| RESTful API | JSON-based endpoints |
| OAuth 2.0 + API Keys | Flexible authentication |
| Webhooks | Real-time execution notifications |
| Rate Limiting | 60-600 requests/minute by plan |
| Scenario Management | Full CRUD operations |
| Execution Control | Start, stop, monitor runs |
| Team API | User and permission management |
Make Plans and API Access
| Plan | API Access | Rate Limit | Best For |
|---|---|---|---|
| Free | Limited | 60/min | Testing, learning |
| Core | Full API | 120/min | Small businesses |
| Pro | Full API + Priority | 300/min | Growing teams |
| Teams | Full API + Admin | 600/min | Agencies, enterprises |
| Enterprise | Custom limits | Custom | Large organizations |
API Architecture Overview
Make uses RESTful API structure:
https://api.make.com/api/v2/
API Versions
| Version | Status | Use Case |
|---|---|---|
| v2 | Current | All new integrations |
| v1 | Deprecated | Legacy integrations (migrate) |
Getting Started: Authentication Setup
Step 1: Create Make Account
Before accessing the API:
- Visit Make.com
- Sign up for account
- Navigate to Settings > Developer settings
- Generate API credentials
Step 2: Choose Authentication Method
Make supports two authentication methods:
| Method | Best For | Security Level |
|---|---|---|
| API Key | Internal integrations, scripts | High (store securely) |
| OAuth 2.0 | Multi-tenant apps, client integrations | Higher (user-scoped tokens) |
Step 3: Get API Key (Simplest Method)
Generate API key for internal use:
- Go to Settings > Developer settings
- Click Create API key
- Copy and store securely
# .env file
MAKE_API_KEY="your_api_key_here"
MAKE_ORGANIZATION_ID="your_org_id"
Step 4: Set Up OAuth 2.0 (For Multi-Tenant Apps)
Configure OAuth for client integrations:
- Go to Settings > Developer settings > OAuth apps
- Click Create OAuth app
- Configure redirect URI
- Get client credentials
const MAKE_CLIENT_ID = process.env.MAKE_CLIENT_ID;
const MAKE_CLIENT_SECRET = process.env.MAKE_CLIENT_SECRET;
const MAKE_REDIRECT_URI = process.env.MAKE_REDIRECT_URI;
// Build authorization URL
const getAuthUrl = (state) => {
const params = new URLSearchParams({
client_id: MAKE_CLIENT_ID,
redirect_uri: MAKE_REDIRECT_URI,
scope: 'read write execute',
state: state,
response_type: 'code'
});
return `https://www.make.com/oauth/authorize?${params.toString()}`;
};
Step 5: Exchange Code for Access Token
Handle OAuth callback:
const exchangeCodeForToken = async (code) => {
const response = await fetch('https://www.make.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: MAKE_CLIENT_ID,
client_secret: MAKE_CLIENT_SECRET,
redirect_uri: MAKE_REDIRECT_URI,
code: code
})
});
const data = await response.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in
};
};
// Handle callback
app.get('/oauth/callback', async (req, res) => {
const { code, state } = req.query;
try {
const tokens = await exchangeCodeForToken(code);
// Store tokens securely
await db.integrations.create({
userId: req.session.userId,
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
tokenExpiry: Date.now() + (tokens.expiresIn * 1000)
});
res.redirect('/success');
} catch (error) {
console.error('OAuth error:', error);
res.status(500).send('Authentication failed');
}
});
Step 6: Make Authenticated API Calls
Create reusable API client:
const MAKE_BASE_URL = 'https://api.make.com/api/v2';
const makeRequest = async (endpoint, options = {}) => {
const apiKey = options.useOAuth ? await getOAuthToken() : process.env.MAKE_API_KEY;
const response = await fetch(`${MAKE_BASE_URL}${endpoint}`, {
...options,
headers: {
'Authorization': `Token ${apiKey}`,
'Content-Type': 'application/json',
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Make API Error: ${error.message}`);
}
return response.json();
};
// Usage
const scenarios = await makeRequest('/scenarios');
console.log(`Found ${scenarios.data.length} scenarios`);
Scenario Management
Listing Scenarios
Fetch all scenarios:
const listScenarios = async (filters = {}) => {
const params = new URLSearchParams({
limit: filters.limit || 50,
offset: filters.offset || 0
});
if (filters.folder) {
params.append('folder', filters.folder);
}
const response = await makeRequest(`/scenarios?${params.toString()}`);
return response;
};
// Usage
const scenarios = await listScenarios({ limit: 100 });
scenarios.data.forEach(scenario => {
console.log(`${scenario.name} - ${scenario.active ? 'Active' : 'Paused'}`);
console.log(` Last run: ${scenario.lastRunDate || 'Never'}`);
});
Getting Scenario Details
Fetch single scenario:
const getScenario = async (scenarioId) => {
const response = await makeRequest(`/scenarios/${scenarioId}`);
return response;
};
// Usage
const scenario = await getScenario('12345');
console.log(`Name: ${scenario.name}`);
console.log(`Modules: ${scenario.modules.length}`);
console.log(`Schedule: ${scenario.schedule?.cronExpression || 'Manual'}`);
Creating a Scenario
Create new scenario:
const createScenario = async (scenarioData) => {
const scenario = {
name: scenarioData.name,
blueprint: scenarioData.blueprint, // Scenario JSON blueprint
active: scenarioData.active || false,
priority: scenarioData.priority || 1,
maxErrors: scenarioData.maxErrors || 3,
autoCommit: scenarioData.autoCommit || true,
description: scenarioData.description || ''
};
const response = await makeRequest('/scenarios', {
method: 'POST',
body: JSON.stringify(scenario)
});
return response;
};
// Usage - Create from blueprint
const newScenario = await createScenario({
name: 'Lead Sync to CRM',
blueprint: {
// Scenario blueprint JSON
// Export from Make editor or build programmatically
modules: [
{
id: 1,
app: 'webhooks',
action: 'customWebhook',
parameters: { /* ... */ }
},
{
id: 2,
app: 'salesforce',
action: 'createRecord',
parameters: { /* ... */ }
}
],
connections: [
{ from: 1, to: 2 }
]
},
active: true,
description: 'Sync webhook leads to Salesforce'
});
console.log(`Scenario created: ${newScenario.id}`);
Updating a Scenario
Modify scenario configuration:
const updateScenario = async (scenarioId, updates) => {
const response = await makeRequest(`/scenarios/${scenarioId}`, {
method: 'PATCH',
body: JSON.stringify(updates)
});
return response;
};
// Usage - Pause scenario
await updateScenario('12345', { active: false });
// Usage - Update schedule
await updateScenario('12345', {
schedule: {
cronExpression: '0 */6 * * *', // Every 6 hours
timezone: 'America/New_York'
}
});
Deleting a Scenario
Remove scenario:
const deleteScenario = async (scenarioId) => {
await makeRequest(`/scenarios/${scenarioId}`, {
method: 'DELETE'
});
console.log(`Scenario ${scenarioId} deleted`);
};
Execution Management
Triggering Scenario Execution
Manually run scenario:
const executeScenario = async (scenarioId, inputData = null) => {
const response = await makeRequest(`/scenarios/${scenarioId}/execute`, {
method: 'POST',
body: inputData ? JSON.stringify(inputData) : undefined
});
return response;
};
// Usage - Run without input
const execution = await executeScenario('12345');
console.log(`Execution started: ${execution.id}`);
// Usage - Run with input data
const executionWithData = await executeScenario('12345', {
lead: {
email: 'prospect@example.com',
name: 'John Doe',
company: 'Acme Corp'
}
});
Getting Execution History
Fetch execution logs:
const getExecutionHistory = async (scenarioId, filters = {}) => {
const params = new URLSearchParams({
limit: filters.limit || 50,
from: filters.from,
to: filters.to,
status: filters.status // 'success', 'error', 'running'
});
const response = await makeRequest(`/scenarios/${scenarioId}/executions?${params.toString()}`);
return response;
};
// Usage - Get failed executions from last 24 hours
const failedExecutions = await getExecutionHistory('12345', {
from: new Date(Date.now() - 86400000).toISOString(),
status: 'error',
limit: 100
});
failedExecutions.data.forEach(exec => {
console.log(`Execution ${exec.id}: ${exec.error?.message}`);
});
Getting Execution Details
Fetch single execution:
const getExecution = async (executionId) => {
const response = await makeRequest(`/executions/${executionId}`);
return response;
};
// Usage
const execution = await getExecution('98765');
console.log(`Status: ${execution.status}`);
console.log(`Duration: ${execution.duration}ms`);
console.log(`Modules executed: ${execution.modulesExecuted}`);
Stopping Running Execution
Cancel execution:
const stopExecution = async (executionId) => {
await makeRequest(`/executions/${executionId}`, {
method: 'DELETE'
});
console.log(`Execution ${executionId} stopped`);
};
Webhook Management
Creating Webhook
Set up incoming webhook:
const createWebhook = async (webhookData) => {
const webhook = {
name: webhookData.name,
scenarioId: webhookData.scenarioId,
type: 'custom', // 'custom' or 'raw'
hookType: 'HEAD', // 'HEAD' or 'GET'
security: {
type: 'none' // 'none', 'basic', 'token'
}
};
const response = await makeRequest('/webhooks', {
method: 'POST',
body: JSON.stringify(webhook)
});
return response;
};
// Usage
const webhook = await createWebhook({
name: 'Lead Capture Webhook',
scenarioId: '12345',
type: 'custom',
hookType: 'HEAD',
security: { type: 'none' }
});
console.log(`Webhook URL: ${hook.url}`);
Listing Webhooks
Fetch all webhooks:
const listWebhooks = async () => {
const response = await makeRequest('/webhooks');
return response;
};
// Usage
const webhooks = await listWebhooks();
webhooks.data.forEach(webhook => {
console.log(`${webhook.name}: ${webhook.url}`);
});
Deleting Webhook
Remove webhook:
const deleteWebhook = async (webhookId) => {
await makeRequest(`/webhooks/${webhookId}`, {
method: 'DELETE'
});
console.log(`Webhook ${webhookId} deleted`);
};
Team and User Management
Listing Team Members
Fetch users in organization:
const listTeamMembers = async (organizationId) => {
const response = await makeRequest(`/organizations/${organizationId}/users`);
return response;
};
// Usage
const members = await listTeamMembers('org-123');
members.data.forEach(member => {
console.log(`${member.email} - ${member.role}`);
});
Adding Team Member
Invite user to organization:
const addTeamMember = async (organizationId, email, role) => {
const response = await makeRequest(`/organizations/${organizationId}/users`, {
method: 'POST',
body: JSON.stringify({
email: email,
role: role // 'viewer', 'builder', 'manager', 'admin'
})
});
return response;
};
// Usage
await addTeamMember('org-123', 'newuser@example.com', 'builder');
Updating User Role
Change user permissions:
const updateUserRole = async (organizationId, userId, newRole) => {
await makeRequest(`/organizations/${organizationId}/users/${userId}`, {
method: 'PATCH',
body: JSON.stringify({ role: newRole })
});
console.log(`User ${userId} role updated to ${newRole}`);
};
User Roles
| Role | Permissions |
|---|---|
| Viewer | View scenarios, no edits |
| Builder | Create/edit scenarios |
| Manager | Manage team, billing |
| Admin | Full organization access |
Rate Limiting
Understanding Rate Limits
Make enforces rate limits by plan:
| Plan | Requests/Minute | Burst Limit |
|---|---|---|
| Free | 60 | 100 |
| Core | 120 | 200 |
| Pro | 300 | 500 |
| Teams | 600 | 1000 |
| Enterprise | Custom | Custom |
Rate Limit Headers
| Header | Description |
|---|---|
X-RateLimit-Limit |
Max requests per minute |
X-RateLimit-Remaining |
Remaining requests |
X-RateLimit-Reset |
Seconds until reset |
Implementing Rate Limit Handling
const makeRateLimitedRequest = async (endpoint, options = {}, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await makeRequest(endpoint, options);
const remaining = response.headers.get('X-RateLimit-Remaining');
if (remaining < 10) {
console.warn(`Low rate limit: ${remaining} remaining`);
}
return response;
} catch (error) {
if (error.message.includes('429') && attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
};
Production Deployment Checklist
Before going live:
- [ ] Use API keys for internal, OAuth for client integrations
- [ ] Store credentials securely (encrypted database)
- [ ] Implement rate limiting and request queuing
- [ ] Set up execution monitoring and alerting
- [ ] Configure error notifications (email, Slack)
- [ ] Implement retry logic for failed executions
- [ ] Add comprehensive logging
- [ ] Create backup/export of critical scenarios
Real-World Use Cases
Agency Client Management
A marketing agency manages 100+ client automations:
- Challenge: Manual scenario updates across client accounts
- Solution: Central dashboard with Make API
- Result: 70% time savings, consistent deployments
Key implementation:
- Multi-account OAuth integration
- Bulk scenario deployment
- Client usage reporting
E-commerce Order Processing
An online store automates order fulfillment:
- Challenge: Manual order entry to warehouse system
- Solution: Webhook-triggered Make scenario
- Result: Zero manual entry, 99.9% accuracy
Key implementation:
- Shopify webhook to Make
- Scenario processes order, updates warehouse
- Error handling with retry logic
Conclusion
The Make API provides comprehensive workflow automation capabilities. Key takeaways:
- API key for internal use, OAuth 2.0 for multi-tenant apps
- Full CRUD for scenarios, executions, webhooks
- Team management for organization control
- Rate limits vary by plan (60-600 requests/minute)
- Execution monitoring essential for production
- Apidog streamlines API testing and team collaboration
How do I authenticate with Make API?
Use API key from Developer settings for internal integrations, or OAuth 2.0 for multi-tenant applications.
Can I trigger scenarios programmatically?
Yes, use the /scenarios/{id}/execute endpoint to manually trigger scenario runs with optional input data.
What are Make rate limits?
Rate limits range from 60 requests/minute (Free) to 600 requests/minute (Teams/Enterprise).
How do I get execution logs?
Use /scenarios/{id}/executions to fetch execution history with filtering by date and status.
Can I create webhooks via API?
Yes, use /webhooks endpoint to create, list, and delete webhooks for scenarios.



