Make.com API Tutorial: Build and Manage Scenarios Programmatically
Yes, Make.com has a full REST API. You can create scenarios, activate them, trigger runs, and pull execution logs — all without touching the visual editor.
Most developers discover this too late. They build elaborate Make workflows manually, then wonder how to replicate them across environments, monitor them in a dashboard, or trigger them conditionally from their own code. The Make API solves all three.
This tutorial covers the complete lifecycle: authentication, scenario management, programmatic execution, and log retrieval. Every example runs with curl and Python.
What the Make API Can Do
The Make REST API (v2) exposes every resource you interact with in the UI:
| Resource | What You Can Do |
|---|---|
| Scenarios | Create, read, update, delete, clone, activate, deactivate |
| Scenario Runs | Trigger on-demand, pass input data, retrieve outputs |
| Execution Logs | List runs, filter by status, get per-module detail |
| Webhooks (Hooks) | Create and manage webhook triggers |
| Connections | List and verify app credentials |
| Data Stores | Read and write structured data |
| Organizations & Teams | List users, manage team settings |
The API follows standard REST conventions. Every request hits:
https://{zone_url}/api/v2/{endpoint}
For example: https://eu1.make.com/api/v2/scenarios
Step 1: Find Your Zone URL
Make uses regional zones. Your zone URL determines your base URL for every API call. Check the address bar in your Make dashboard — it will show something like https://eu1.make.com/ or https://us1.make.com/.
Available zones:
| Zone | URL |
|---|---|
| Europe 1 | https://eu1.make.com |
| Europe 2 | https://eu2.make.com |
| US 1 | https://us1.make.com |
| US 2 | https://us2.make.com |
| Celonis EU | https://eu1.make.celonis.com |
| Celonis US | https://us1.make.celonis.com |
If you call the wrong zone, every request returns an authentication error — even with a valid token. Always confirm your zone first.
Step 2: Create an API Token
The Make API authenticates via bearer tokens. To create one:
- Open your Make dashboard and click your avatar → Profile
- Select the API tab
- Click Add token
- Set a Label (e.g.,
my-dashboard-token) - Select the scopes you need (see table below)
- Copy the token immediately — Make hides it after you navigate away
Token scopes reference:
| Scope | Grants |
|---|---|
scenarios:read | List scenarios, get details, get logs and blueprints |
scenarios:write | Create, update, clone, activate, deactivate, delete |
scenarios:run | Trigger scenario runs via API |
hooks:read | List webhooks |
hooks:write | Create and manage webhooks |
connections:read | View app connections |
For a management dashboard, you need scenarios:read, scenarios:write, and scenarios:run.
Store your token in an environment variable, not in source code:
export MAKE_TOKEN="your-api-token-here"
export MAKE_ZONE="eu1.make.com"
export MAKE_BASE_URL="https://${MAKE_ZONE}/api/v2"
Step 3: Make Your First API Call
Every request passes the token in the Authorization header:
Authorization: Token your-api-token
Verify your setup by fetching your user profile:
curl -X GET "https://${MAKE_ZONE}/api/v2/users/me" \
-H "Authorization: Token ${MAKE_TOKEN}"
Expected response:
{
"user": {
"id": 12345,
"name": "Your Name",
"email": "you@example.com",
"timezone": "Europe/London"
}
}
If you get a 401, the token is wrong. If you get a 404, check your zone URL.
Step 4: List All Scenarios
Scenarios belong to teams. You need your team ID to list them. Get it from the URL in the Make UI (/team/{teamId}/dashboard) or from the API:
curl -X GET "${MAKE_BASE_URL}/teams?organizationId=YOUR_ORG_ID" \
-H "Authorization: Token ${MAKE_TOKEN}"
Then list scenarios for that team:
curl -X GET "${MAKE_BASE_URL}/scenarios?teamId=YOUR_TEAM_ID" \
-H "Authorization: Token ${MAKE_TOKEN}"
Response:
{
"scenarios": [
{
"id": 98765,
"name": "Lead Sync to HubSpot",
"isActive": true,
"teamId": 11111,
"scheduling": { "type": "indefinitely", "interval": 900 },
"lastEdit": "2026-03-10T14:23:00.000Z",
"nextExec": "2026-03-15T15:00:00.000Z",
"dlqCount": 0
}
],
"pg": { "limit": 10, "offset": 0 }
}
Key fields:
isActive— whether the scenario is currently running on schedulescheduling.interval— run frequency in secondsdlqCount— number of failed executions in the dead-letter queuenextExec— timestamp of the next scheduled run
Python equivalent:
import os
import requests
BASE_URL = f"https://{os.environ['MAKE_ZONE']}/api/v2"
HEADERS = {"Authorization": f"Token {os.environ['MAKE_TOKEN']}"}
def list_scenarios(team_id: int) -> list[dict]:
response = requests.get(
f"{BASE_URL}/scenarios",
headers=HEADERS,
params={"teamId": team_id}
)
response.raise_for_status()
return response.json()["scenarios"]
scenarios = list_scenarios(team_id=11111)
for s in scenarios:
status = "✅ active" if s["isActive"] else "⏸ inactive"
print(f"{s['id']} | {s['name']} | {status}")
Step 5: Create a Scenario Programmatically
Creating a scenario via API requires three fields: teamId, blueprint, and scheduling.
The blueprint is a JSON string that defines the scenario's modules and connections. The easiest way to get a valid blueprint: build a scenario in the UI, then export it via:
curl -X GET "${MAKE_BASE_URL}/scenarios/YOUR_SCENARIO_ID/blueprint" \
-H "Authorization: Token ${MAKE_TOKEN}"
Then pass that blueprint to the create endpoint:
curl -X POST "${MAKE_BASE_URL}/scenarios" \
-H "Authorization: Token ${MAKE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"teamId": 11111,
"blueprint": "{\"name\":\"My API Scenario\",\"flow\":[],\"metadata\":{\"version\":1,\"scenario\":{\"roundtrips\":1,\"maxErrors\":3}}}",
"scheduling": "{\"type\":\"indefinitely\",\"interval\":3600}"
}'
Scheduling types:
| Type | Meaning |
|---|---|
indefinitely | Run every N seconds (set interval) |
on-demand | Only run when triggered via API |
once | Run once at a specific time |
immediately | Run as fast as possible |
For scenarios you plan to trigger via API, use on-demand:
"scheduling": "{\"type\":\"on-demand\"}"
Python helper to clone an existing scenario:
def clone_scenario(source_id: int, team_id: int, new_name: str) -> dict:
response = requests.post(
f"{BASE_URL}/scenarios/{source_id}/clone",
headers=HEADERS,
json={"teamId": team_id, "name": new_name}
)
response.raise_for_status()
return response.json()["scenario"]
new_scenario = clone_scenario(
source_id=98765,
team_id=11111,
new_name="Lead Sync to HubSpot — Staging"
)
print(f"Cloned scenario ID: {new_scenario['id']}")
Step 6: Activate and Deactivate Scenarios
Activating a scenario schedules it to run. Deactivating stops all future scheduled runs (without deleting it).
Activate:
curl -X POST "${MAKE_BASE_URL}/scenarios/YOUR_SCENARIO_ID/start" \
-H "Authorization: Token ${MAKE_TOKEN}"
Deactivate:
curl -X POST "${MAKE_BASE_URL}/scenarios/YOUR_SCENARIO_ID/stop" \
-H "Authorization: Token ${MAKE_TOKEN}"
Both return the scenario ID and the updated isActive flag:
{ "scenario": { "id": 98765, "isActive": true } }
Practical use case: deploy a new scenario in inactive state, run a validation check, then activate only if the check passes:
def deploy_and_validate(scenario_id: int) -> bool:
# Run a test execution first
result = run_scenario(scenario_id, responsive=True)
if result.get("status") == "1": # 1 = success
activate_scenario(scenario_id)
print(f"Scenario {scenario_id} validated and activated")
return True
print(f"Validation failed: {result}")
return False
Step 7: Trigger a Scenario Run
The most powerful feature: trigger an on-demand run from your own code. The scenario must be active and set to on-demand scheduling.
curl -X POST "${MAKE_BASE_URL}/scenarios/YOUR_SCENARIO_ID/run" \
-H "Authorization: Token ${MAKE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"responsive": true,
"data": {
"email": "lead@example.com",
"company": "Acme Corp"
}
}'
The responsive flag controls execution mode:
responsive | Behavior |
|---|---|
false (default) | Returns executionId immediately; run happens async |
true | Waits up to 40 seconds; returns final status and outputs |
Response when responsive: true:
{
"executionId": "abc123xyz",
"status": "1"
}
Status codes: 1 = success, 2 = warning, 3 = error.
You can also pass a callbackUrl — Make will POST the result to that URL when the run finishes. This is ideal for runs that exceed the 40-second timeout:
curl -X POST "${MAKE_BASE_URL}/scenarios/YOUR_SCENARIO_ID/run" \
-H "Authorization: Token ${MAKE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"responsive": false,
"callbackUrl": "https://yourapp.com/webhooks/make-callback",
"data": { "batchId": "2026-03-15" }
}'
Full Python wrapper:
def run_scenario(
scenario_id: int,
data: dict | None = None,
responsive: bool = True,
callback_url: str | None = None
) -> dict:
payload: dict = {"responsive": responsive}
if data:
payload["data"] = data
if callback_url:
payload["callbackUrl"] = callback_url
response = requests.post(
f"{BASE_URL}/scenarios/{scenario_id}/run",
headers={**HEADERS, "Content-Type": "application/json"},
json=payload
)
response.raise_for_status()
return response.json()
# Trigger with input data, wait for result
result = run_scenario(
scenario_id=98765,
data={"email": "lead@example.com", "source": "website"},
responsive=True
)
print(f"Execution ID: {result['executionId']}, Status: {result['status']}")
Step 8: Read Execution Logs
Pull the last N execution logs for a scenario:
curl -X GET "${MAKE_BASE_URL}/scenarios/YOUR_SCENARIO_ID/logs?pg[limit]=20" \
-H "Authorization: Token ${MAKE_TOKEN}"
Filter by status (3 = errors only):
curl -X GET "${MAKE_BASE_URL}/scenarios/YOUR_SCENARIO_ID/logs?status=3&pg[limit]=50" \
-H "Authorization: Token ${MAKE_TOKEN}"
Log response fields:
{
"scenarioLogs": [
{
"imtId": "abc123",
"timestamp": "2026-03-15T14:30:00.000Z",
"status": 1,
"duration": 1240,
"operations": 3,
"transfer": 4096,
"instant": false
}
]
}
status: 1 = success, 2 = warning, 3 = errorduration: execution time in millisecondsoperations: number of module executions (billable units)transfer: data processed in bytes
Get the full detail of a specific execution:
curl -X GET "${MAKE_BASE_URL}/scenarios/YOUR_SCENARIO_ID/executions/EXECUTION_ID" \
-H "Authorization: Token ${MAKE_TOKEN}"
Step 9: Build a Scenario Health Dashboard
Combine the endpoints above into a monitoring script. This example prints a status table for all scenarios in a team:
import os
from datetime import datetime, timezone
import requests
BASE_URL = f"https://{os.environ['MAKE_ZONE']}/api/v2"
HEADERS = {"Authorization": f"Token {os.environ['MAKE_TOKEN']}"}
TEAM_ID = int(os.environ["MAKE_TEAM_ID"])
def get_scenarios() -> list[dict]:
r = requests.get(f"{BASE_URL}/scenarios", headers=HEADERS, params={"teamId": TEAM_ID})
r.raise_for_status()
return r.json()["scenarios"]
def get_recent_logs(scenario_id: int, limit: int = 5) -> list[dict]:
r = requests.get(
f"{BASE_URL}/scenarios/{scenario_id}/logs",
headers=HEADERS,
params={"pg[limit]": limit}
)
r.raise_for_status()
return r.json().get("scenarioLogs", [])
def health_report():
scenarios = get_scenarios()
print(f"\n{'ID':<10} {'Name':<35} {'Active':<8} {'Last Status':<14} {'DLQ':<5}")
print("-" * 80)
for s in scenarios:
logs = get_recent_logs(s["id"], limit=1)
last_status = "—"
if logs:
code = logs[0]["status"]
last_status = {1: "✅ success", 2: "⚠️ warning", 3: "❌ error"}.get(code, str(code))
active = "✅" if s["isActive"] else "⏸"
dlq = s.get("dlqCount", 0)
dlq_flag = f"🔴 {dlq}" if dlq > 0 else "0"
print(f"{s['id']:<10} {s['name'][:34]:<35} {active:<8} {last_status:<14} {dlq_flag:<5}")
health_report()
Sample output:
ID Name Active Last Status DLQ
--------------------------------------------------------------------------------
98765 Lead Sync to HubSpot ✅ ✅ success 0
98766 Daily Report Email ✅ ⚠️ warning 0
98767 Slack Alerts (Staging) ⏸ ❌ error 3
Scenarios with dlqCount > 0 have executions that failed and need inspection. You can retrieve and retry them via the incomplete executions API (/scenarios/{id}/incomplete-executions).
Make API vs Zapier API: When to Use Each
Both platforms offer APIs, but they differ significantly in depth:
| Feature | Make API | Zapier API |
|---|---|---|
| Create automations via API | ✅ Full scenario blueprints | ❌ Limited; no Zap creation |
| Trigger runs programmatically | ✅ Native endpoint | ✅ Via webhooks only |
| Pass input data on trigger | ✅ Structured data object | ✅ Via webhook payload |
| Read execution logs | ✅ Full log history | ⚠️ Basic only |
| Manage connections/credentials | ✅ | ❌ |
| Pagination, filtering | ✅ Full support | ⚠️ Limited |
| Best for | Teams managing 10+ scenarios programmatically | Simple webhook triggers |
If you're building tooling on top of your automation layer — staging environments, deployment pipelines, monitoring dashboards — Make's API is the better foundation.
Rate Limits
Make applies a per-organization request limit for most API endpoints. One important exception: the /scenarios/{id}/run endpoint is not subject to the standard rate limit. You can trigger scenario runs as frequently as your plan allows.
For other endpoints, Make uses sliding window limits. If you exceed them, you receive a 429 Too Many Requests response. Implement exponential backoff:
import time
def api_call_with_retry(func, *args, max_retries: int = 3, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except requests.HTTPError as e:
if e.response.status_code == 429 and attempt < max_retries - 1:
wait = 2 ** attempt
print(f"Rate limited. Retrying in {wait}s...")
time.sleep(wait)
else:
raise
FAQ
Yes. Make.com has a full REST API (v2) that lets you create, manage, and execute scenarios programmatically. The API is documented at https://developers.make.com/api-documentation/ and supports token-based authentication as well as OAuth 2.0.
Generate an API token from your Make profile (Profile → API → Add token). Pass it in the Authorization header as: Authorization: Token your-token. Each token has scopes you select at creation time — you cannot add scopes later without creating a new token.
Send a POST request to /api/v2/scenarios with a JSON body containing teamId, blueprint (a JSON string), and scheduling (a JSON string). The easiest way to get a valid blueprint is to export one from an existing scenario using GET /api/v2/scenarios/{id}/blueprint.
Use POST /api/v2/scenarios/{id}/run. The scenario must be active and set to on-demand scheduling. Pass responsive: true to wait for the result synchronously, or use callbackUrl for async notification. You can pass input data in the data object.
Make hosts data in separate regional zones (eu1, eu2, us1, us2). Your zone URL is the base for all API calls — e.g., https://eu1.make.com/api/v2/. Using the wrong zone returns auth errors even with a valid token. Find your zone in the URL of your Make dashboard.
Yes. Use GET /api/v2/scenarios/{id}/logs to retrieve execution history, filtered by status (1=success, 2=warning, 3=error), date range, and duration. For detailed per-execution data including outputs and error messages, use GET /api/v2/scenarios/{id}/executions/{executionId}.
The Make API is available on all plans. However, certain features — like Scenario Inputs (required for passing data to runs) — require the Pro plan or higher. See https://www.make.com/en/pricing for current plan limits.
Next Steps
You now have everything you need to integrate Make.com into your development workflow:
- Deployment pipelines: clone a template scenario, configure connections, activate on deploy
- Multi-environment management: maintain separate staging and production scenarios programmatically
- Monitoring dashboards: pull execution logs and DLQ counts into your existing observability stack
- Conditional automation: trigger Make scenarios from your application logic in response to events
Start building with Make.com — the free plan includes 1,000 operations per month and full API access.
If you're combining Make with data extraction workflows, the Apify + Make.com integration guide shows how to trigger Apify scrapers from Make scenarios and pipe the resulting datasets into downstream apps.
