TL;DR
The Make (formerly Integromat) API lets you automate workflows, manage scenarios, trigger executions, configure webhooks, and manage teams programmatically. It supports API key and OAuth 2.0 authentication, uses REST endpoints for scenarios, executions, webhooks, and organizations, and applies plan-based rate limits of 60–600 requests per minute.
Introduction
Make processes over 2 billion operations monthly for more than 1 million users across 100+ countries. If you are building automation tooling, managing client workflows, or integrating across Make's 1000+ apps, the API is the control plane for scalable automation.
For example, an agency managing 50+ client automations can use the API to automate scenario deployments, execution monitoring, error handling, and client reporting instead of updating each workflow manually.
This guide covers:
- API key and OAuth 2.0 authentication
- Scenario CRUD operations
- Manual scenario execution and monitoring
- Webhook management
- Team management
- Rate-limit handling
- Production deployment practices
💡 Apidog simplifies API integration testing. Use it to test Make endpoints, validate OAuth flows, inspect execution responses, mock responses, and share test scenarios with your team.
What Is the Make API?
Make provides a RESTful API for managing automation workflows programmatically.
You can use it to:
- Create, update, and delete scenarios
- Trigger scenarios manually
- Read execution history and execution details
- Create and manage webhooks
- Manage organization users and roles
- Manage connections, apps, organization settings, and workspaces
Key features
| Feature | Description |
|---|---|
| RESTful API | JSON-based endpoints |
| OAuth 2.0 + API keys | Flexible authentication options |
| Webhooks | Real-time execution notifications |
| Rate limiting | 60–600 requests/minute, depending on plan |
| Scenario management | Full CRUD operations |
| Execution control | Start, stop, and 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 and learning |
| Core | Full API | 120/min | Small businesses |
| Pro | Full API + priority | 300/min | Growing teams |
| Teams | Full API + admin | 600/min | Agencies and enterprises |
| Enterprise | Custom limits | Custom | Large organizations |
API base URL
https://api.make.com/api/v2/
API versions
| Version | Status | Use case |
|---|---|---|
| v2 | Current | New integrations |
| v1 | Deprecated | Legacy integrations; migrate when possible |
Getting Started: Authentication Setup
1. Create Make API credentials
- Sign in to Make.
- Go to Settings > Developer settings.
- Generate API credentials.
- Store secrets outside source control.
2. Choose an authentication method
| Method | Best for | Security model |
|---|---|---|
| API key | Internal scripts and single-organization integrations | Secure secret storage required |
| OAuth 2.0 | Multi-tenant apps and client integrations | User-scoped tokens |
3. Configure an API key
Use an API key for internal services.
# .env
MAKE_API_KEY="your_api_key_here"
MAKE_ORGANIZATION_ID="your_org_id"
Do not commit this file. Load secrets through your deployment platform or a secret manager.
4. Configure OAuth 2.0
Use OAuth when your application connects to multiple customer Make accounts.
- Go to Settings > Developer settings > OAuth apps.
- Create an OAuth application.
- Configure the redirect URI.
- Save the client ID and client secret.
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;
function getAuthUrl(state) {
const params = new URLSearchParams({
client_id: MAKE_CLIENT_ID,
redirect_uri: MAKE_REDIRECT_URI,
scope: "read write execute",
state,
response_type: "code",
});
return `https://www.make.com/oauth/authorize?${params.toString()}`;
}
Use a cryptographically secure, short-lived state value and validate it in the callback before exchanging the authorization code.
5. Exchange the authorization code for tokens
async function exchangeCodeForToken(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,
}),
});
if (!response.ok) {
throw new Error(`Token exchange failed: ${response.status}`);
}
const data = await response.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
};
}
app.get("/oauth/callback", async (req, res) => {
const { code, state } = req.query;
try {
// Validate state before continuing.
const tokens = await exchangeCodeForToken(code);
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");
}
});
6. Create a reusable API client
Centralize authentication and error handling so every endpoint behaves consistently.
const MAKE_BASE_URL = "https://api.make.com/api/v2";
async function makeRequest(endpoint, options = {}) {
const token = options.useOAuth
? await getOAuthToken()
: process.env.MAKE_API_KEY;
const response = await fetch(`${MAKE_BASE_URL}${endpoint}`, {
...options,
headers: {
Authorization: `Token ${token}`,
"Content-Type": "application/json",
...options.headers,
},
});
if (!response.ok) {
let details = {};
try {
details = await response.json();
} catch {
// Keep the HTTP status when the response has no JSON body.
}
const error = new Error(
`Make API error (${response.status}): ${details.message || "Request failed"}`
);
error.status = response.status;
error.rateLimit = {
limit: response.headers.get("X-RateLimit-Limit"),
remaining: response.headers.get("X-RateLimit-Remaining"),
reset: response.headers.get("X-RateLimit-Reset"),
};
throw error;
}
if (response.status === 204) {
return null;
}
return response.json();
}
// Example
const scenarios = await makeRequest("/scenarios");
console.log(`Found ${scenarios.data.length} scenarios`);
Scenario Management
List scenarios
Use pagination from the beginning. Do not assume every scenario fits in one response.
async function listScenarios(filters = {}) {
const params = new URLSearchParams({
limit: String(filters.limit || 50),
offset: String(filters.offset || 0),
});
if (filters.folder) {
params.set("folder", filters.folder);
}
return makeRequest(`/scenarios?${params.toString()}`);
}
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"}`);
});
Get scenario details
Fetch the scenario before updating it when you need to inspect its current configuration.
async function getScenario(scenarioId) {
return makeRequest(`/scenarios/${scenarioId}`);
}
const scenario = await getScenario("12345");
console.log(`Name: ${scenario.name}`);
console.log(`Modules: ${scenario.modules.length}`);
console.log(`Schedule: ${scenario.schedule?.cronExpression || "Manual"}`);
Create a scenario
Create scenarios from a known blueprint, such as a blueprint exported from the Make editor.
async function createScenario(scenarioData) {
return makeRequest("/scenarios", {
method: "POST",
body: JSON.stringify({
name: scenarioData.name,
blueprint: scenarioData.blueprint,
active: scenarioData.active || false,
priority: scenarioData.priority || 1,
maxErrors: scenarioData.maxErrors || 3,
autoCommit: scenarioData.autoCommit || true,
description: scenarioData.description || "",
}),
});
}
const newScenario = await createScenario({
name: "Lead Sync to CRM",
blueprint: {
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}`);
Update a scenario
Use PATCH for targeted changes, such as pausing a scenario or changing its schedule.
async function updateScenario(scenarioId, updates) {
return makeRequest(`/scenarios/${scenarioId}`, {
method: "PATCH",
body: JSON.stringify(updates),
});
}
// Pause a scenario.
await updateScenario("12345", { active: false });
// Run every six hours.
await updateScenario("12345", {
schedule: {
cronExpression: "0 */6 * * *",
timezone: "America/New_York",
},
});
Delete a scenario
Use deletion carefully. Export or back up critical scenario definitions first.
async function deleteScenario(scenarioId) {
await makeRequest(`/scenarios/${scenarioId}`, {
method: "DELETE",
});
console.log(`Scenario ${scenarioId} deleted`);
}
Execution Management
Trigger a scenario manually
Use manual execution when an external system needs to invoke a scenario or when you need to re-run a workflow from an application.
async function executeScenario(scenarioId, inputData = null) {
return makeRequest(`/scenarios/${scenarioId}/execute`, {
method: "POST",
body: inputData ? JSON.stringify(inputData) : undefined,
});
}
// Run without input.
const execution = await executeScenario("12345");
console.log(`Execution started: ${execution.id}`);
// Run with input.
const executionWithData = await executeScenario("12345", {
lead: {
email: "prospect@example.com",
name: "John Doe",
company: "Acme Corp",
},
});
Read execution history
Filter by status and time range to build monitoring jobs that focus on failures.
async function getExecutionHistory(scenarioId, filters = {}) {
const params = new URLSearchParams({
limit: String(filters.limit || 50),
});
if (filters.from) params.set("from", filters.from);
if (filters.to) params.set("to", filters.to);
if (filters.status) params.set("status", filters.status);
return makeRequest(
`/scenarios/${scenarioId}/executions?${params.toString()}`
);
}
const failedExecutions = await getExecutionHistory("12345", {
from: new Date(Date.now() - 86_400_000).toISOString(),
status: "error",
limit: 100,
});
failedExecutions.data.forEach((execution) => {
console.log(`Execution ${execution.id}: ${execution.error?.message}`);
});
Get execution details
async function getExecution(executionId) {
return makeRequest(`/executions/${executionId}`);
}
const execution = await getExecution("98765");
console.log(`Status: ${execution.status}`);
console.log(`Duration: ${execution.duration}ms`);
console.log(`Modules executed: ${execution.modulesExecuted}`);
Stop a running execution
async function stopExecution(executionId) {
await makeRequest(`/executions/${executionId}`, {
method: "DELETE",
});
console.log(`Execution ${executionId} stopped`);
}
Webhook Management
Create a webhook
Create a webhook and attach it to a scenario that should process incoming events.
async function createWebhook(webhookData) {
return makeRequest("/webhooks", {
method: "POST",
body: JSON.stringify({
name: webhookData.name,
scenarioId: webhookData.scenarioId,
type: "custom",
hookType: "HEAD",
security: {
type: "none",
},
}),
});
}
const webhook = await createWebhook({
name: "Lead Capture Webhook",
scenarioId: "12345",
type: "custom",
hookType: "HEAD",
security: { type: "none" },
});
console.log(`Webhook URL: ${webhook.url}`);
List webhooks
async function listWebhooks() {
return makeRequest("/webhooks");
}
const webhooks = await listWebhooks();
webhooks.data.forEach((webhook) => {
console.log(`${webhook.name}: ${webhook.url}`);
});
Delete a webhook
async function deleteWebhook(webhookId) {
await makeRequest(`/webhooks/${webhookId}`, {
method: "DELETE",
});
console.log(`Webhook ${webhookId} deleted`);
}
Team and User Management
List organization users
async function listTeamMembers(organizationId) {
return makeRequest(`/organizations/${organizationId}/users`);
}
const members = await listTeamMembers("org-123");
members.data.forEach((member) => {
console.log(`${member.email} — ${member.role}`);
});
Invite a team member
async function addTeamMember(organizationId, email, role) {
return makeRequest(`/organizations/${organizationId}/users`, {
method: "POST",
body: JSON.stringify({
email,
role,
}),
});
}
await addTeamMember("org-123", "newuser@example.com", "builder");
Update a user role
async function updateUserRole(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 and edit scenarios |
| Manager | Manage team and billing |
| Admin | Full organization access |
Rate Limiting
Understand plan limits
| Plan | Requests/minute | Burst limit |
|---|---|---|
| Free | 60 | 100 |
| Core | 120 | 200 |
| Pro | 300 | 500 |
| Teams | 600 | 1000 |
| Enterprise | Custom | Custom |
Inspect rate-limit headers
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests per minute |
X-RateLimit-Remaining |
Remaining requests |
X-RateLimit-Reset |
Seconds until reset |
Retry rate-limited requests
Retry 429 responses with exponential backoff. Keep retries bounded so a failing upstream service does not create an unbounded queue.
async function makeRateLimitedRequest(
endpoint,
options = {},
maxRetries = 3
) {
for (let attempt = 1; attempt <= maxRetries; attempt += 1) {
try {
return await makeRequest(endpoint, options);
} catch (error) {
const canRetry = error.status === 429 && attempt < maxRetries;
if (!canRetry) {
throw error;
}
const delay = 2 ** attempt * 1000;
console.warn(
`Rate limited. Retrying in ${delay}ms. ` +
`Remaining: ${error.rateLimit?.remaining ?? "unknown"}`
);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}
For high-volume workloads, add request queuing and throttle calls before you reach the limit.
Production Deployment Checklist
Before going live:
- [ ] Use API keys for internal integrations and OAuth 2.0 for client integrations
- [ ] Store credentials in an encrypted database or secret manager
- [ ] Implement rate limiting and request queuing
- [ ] Monitor scenario executions and configure alerts
- [ ] Configure error notifications through email or Slack
- [ ] Add retry logic for failed executions
- [ ] Log API requests, responses, and execution identifiers
- [ ] Export or back up critical scenarios before major changes
Real-World Use Cases
Agency client management
A marketing agency managing 100+ client automations can build a central dashboard on top of the Make API.
Challenge: Manual scenario updates across client accounts.
Implementation:
- Connect each client account through OAuth
- Deploy scenario blueprints in bulk
- Poll execution history for failed runs
- Generate client usage reports
Result: More consistent deployments and less time spent on repetitive administration.
E-commerce order processing
An online store can use a webhook-triggered scenario to automate order fulfillment.
Challenge: Manual order entry into a warehouse system.
Implementation:
- Receive an order event through a Shopify webhook.
- Trigger a Make scenario.
- Process the order and update the warehouse system.
- Monitor failed executions and retry when appropriate.
Result: Reduced manual entry and more reliable order processing.
Conclusion
The Make API provides the building blocks for managing workflow automation from your own application or internal tooling.
Key implementation takeaways:
- Use API keys for internal services and OAuth 2.0 for multi-tenant applications.
- Use scenario endpoints for workflow CRUD operations.
- Trigger and monitor executions to build operational visibility.
- Manage webhooks and organization users through the API.
- Design around plan-based rate limits of 60–600 requests per minute.
- Test authentication flows, payloads, and error responses before production deployment.
FAQ
How do I authenticate with the Make API?
Use an API key from Developer settings for internal integrations. Use OAuth 2.0 when users connect their own Make accounts to your application.
Can I trigger scenarios programmatically?
Yes. Use the /scenarios/{id}/execute endpoint to trigger a scenario, optionally with input data.
What are Make rate limits?
Rate limits range from 60 requests per minute on the Free plan to 600 requests per minute on the Teams plan. Enterprise limits are custom.
How do I get execution logs?
Use /scenarios/{id}/executions to retrieve execution history and filter it by date range or status.
Can I create webhooks via the API?
Yes. Use the /webhooks endpoint to create, list, and delete webhooks associated with scenarios.
Top comments (0)