DEV Community

Preecha
Preecha

Posted on

How to Use Make (Integromat) API ?

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.

Try Apidog today

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/
Enter fullscreen mode Exit fullscreen mode

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

  1. Sign in to Make.
  2. Go to Settings > Developer settings.
  3. Generate API credentials.
  4. 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"
Enter fullscreen mode Exit fullscreen mode

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.

  1. Go to Settings > Developer settings > OAuth apps.
  2. Create an OAuth application.
  3. Configure the redirect URI.
  4. 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()}`;
}
Enter fullscreen mode Exit fullscreen mode

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");
  }
});
Enter fullscreen mode Exit fullscreen mode

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`);
Enter fullscreen mode Exit fullscreen mode

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"}`);
});
Enter fullscreen mode Exit fullscreen mode

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"}`);
Enter fullscreen mode Exit fullscreen mode

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}`);
Enter fullscreen mode Exit fullscreen mode

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",
  },
});
Enter fullscreen mode Exit fullscreen mode

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`);
}
Enter fullscreen mode Exit fullscreen mode

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",
  },
});
Enter fullscreen mode Exit fullscreen mode

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}`);
});
Enter fullscreen mode Exit fullscreen mode

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}`);
Enter fullscreen mode Exit fullscreen mode

Stop a running execution

async function stopExecution(executionId) {
  await makeRequest(`/executions/${executionId}`, {
    method: "DELETE",
  });

  console.log(`Execution ${executionId} stopped`);
}
Enter fullscreen mode Exit fullscreen mode

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}`);
Enter fullscreen mode Exit fullscreen mode

List webhooks

async function listWebhooks() {
  return makeRequest("/webhooks");
}

const webhooks = await listWebhooks();

webhooks.data.forEach((webhook) => {
  console.log(`${webhook.name}: ${webhook.url}`);
});
Enter fullscreen mode Exit fullscreen mode

Delete a webhook

async function deleteWebhook(webhookId) {
  await makeRequest(`/webhooks/${webhookId}`, {
    method: "DELETE",
  });

  console.log(`Webhook ${webhookId} deleted`);
}
Enter fullscreen mode Exit fullscreen mode

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}`);
});
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

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}`);
}
Enter fullscreen mode Exit fullscreen mode

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));
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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:

  1. Receive an order event through a Shopify webhook.
  2. Trigger a Make scenario.
  3. Process the order and update the warehouse system.
  4. 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)