ActiveCampaign
Access the ActiveCampaign API with managed OAuth authentication. Manage contacts, deals, tags, lists, automations, and email campaigns.
Quick Start
# List all contacts
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/active-campaign/api/3/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://gateway.maton.ai/active-campaign/{native-api-path}
Replace {native-api-path} with the actual ActiveCampaign API endpoint path. The gateway proxies requests to {account}.api-us1.com and automatically injects your OAuth token.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
- Sign in or create an account at maton.ai
- Go to maton.ai/settings
- Copy your API key
Connection Management
Manage your ActiveCampaign OAuth connections at https://ctrl.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=active-campaign&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Create Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'active-campaign'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Get Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
json
{
"connection": {
"connection_id": "9e8ba2aa-25ec-4ba0-8815-3068be304dca",
"status": "ACTIVE",
"creation_time": "2026-02-09T20:03:16.595823Z",
"last_updated_time": "2026-02-09T20:04:09.550767Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "active-campaign",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Specifying Connection
If you have multiple ActiveCampaign connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/active-campaign/api/3/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '9e8ba2aa-25ec-4ba0-8815-3068be304dca')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If omitted, the gateway uses the default (oldest) active connection.
API Reference
Contacts
List Contacts
GET /active-campaign/api/3/contacts
Query Parameters:
- limit - Number of results (default: 20)
- offset - Starting index
- search - Search by email
- filters[email] - Filter by email
- filters[listid] - Filter by list ID
Response:
json
{
"contacts": [
{
"id": "1",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"phone": "",
"cdate": "2026-02-09T14:03:19-06:00",
"udate": "2026-02-09T14:03:19-06:00"
}
],
"meta": {
"total": "1"
}
}
Get Contact
GET /active-campaign/api/3/contacts/{contactId}
Returns contact with related data including lists, tags, deals, and field values.
Create Contact
POST /active-campaign/api/3/contacts
Content-Type: application/json
{
"contact": {
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"phone": "555-1234"
}
}
Response:
json
{
"contact": {
"id": "2",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"cdate": "2026-02-09T17:51:39-06:00",
"udate": "2026-02-09T17:51:39-06:00"
}
}
Update Contact
PUT /active-campaign/api/3/contacts/{contactId}
Content-Type: application/json
{
"contact": {
"firstName": "Updated",
"lastName": "Name"
}
}
Delete Contact
DELETE /active-campaign/api/3/contacts/{contactId}
Returns 200 OK on success.
Sync Contact (Create or Update)
POST /active-campaign/api/3/contact/sync
Content-Type: application/json
{
"contact": {
"email": "[email protected]",
"firstName": "Updated Name"
}
}
Creates the contact if it doesn't exist, updates if it does.
Tags
List Tags
GET /active-campaign/api/3/tags
Response:
json
{
"tags": [
{
"id": "1",
"tag": "VIP Customer",
"tagType": "contact",
"description": "High-value customers",
"cdate": "2026-02-09T17:51:39-06:00"
}
],
"meta": {
"total": "1"
}
}
Get Tag
GET /active-campaign/api/3/tags/{tagId}
Create Tag
POST /active-campaign/api/3/tags
Content-Type: application/json
{
"tag": {
"tag": "New Tag",
"tagType": "contact",
"description": "Tag description"
}
}
Update Tag
PUT /active-campaign/api/3/tags/{tagId}
Content-Type: application/json
{
"tag": {
"tag": "Updated Tag Name"
}
}
Delete Tag
DELETE /active-campaign/api/3/tags/{tagId}
Contact Tags
Add Tag to Contact
POST /active-campaign/api/3/contactTags
Content-Type: application/json
{
"contactTag": {
"contact": "2",
"tag": "1"
}
}
Remove Tag from Contact
DELETE /active-campaign/api/3/contactTags/{contactTagId}
Get Contact's Tags
GET /active-campaign/api/3/contacts/{contactId}/contactTags
Lists
List All Lists
GET /active-campaign/api/3/lists
Response:
json
{
"lists": [
{
"id": "1",
"stringid": "master-contact-list",
"name": "Master Contact List",
"cdate": "2026-02-09T14:03:20-06:00"
}
],
"meta": {
"total": "1"
}
}
Get List
GET /active-campaign/api/3/lists/{listId}
Create List
POST /active-campaign/api/3/lists
Content-Type: application/json
{
"list": {
"name": "New List",
"stringid": "new-list",
"sender_url": "https://example.com",
"sender_reminder": "You signed up on our website"
}
}
Update List
PUT /active-campaign/api/3/lists/{listId}
Content-Type: application/json
{
"list": {
"name": "Updated List Name"
}
}
Delete List
DELETE /active-campaign/api/3/lists/{listId}
Contact Lists
Subscribe Contact to List
POST /active-campaign/api/3/contactLists
Content-Type: application/json
{
"contactList": {
"contact": "2",
"list": "1",
"status": "1"
}
}
Status values: 1 = subscribed, 2 = unsubscribed
Deals
List Deals
GET /active-campaign/api/3/deals
Query Parameters:
- search - Search by title, contact, or org
- filters[stage] - Filter by stage ID
- filters[owner] - Filter by owner ID
Response:
json
{
"deals": [
{
"id": "1",
"title": "New Deal",
"value": "10000",
"currency": "usd",
"stage": "1",
"owner": "1"
}
],
"meta": {
"total": 0,
"currencies": []
}
}
Get Deal
GET /active-campaign/api/3/deals/{dealId}
Create Deal
POST /active-campaign/api/3/deals
Content-Type: application/json
{
"deal": {
"title": "New Deal",
"value": "10000",
"currency": "usd",
"contact": "2",
"stage": "1",
"owner": "1"
}
}
Update Deal
PUT /active-campaign/api/3/deals/{dealId}
Content-Type: application/json
{
"deal": {
"title": "Updated Deal",
"value": "15000"
}
}
Delete Deal
DELETE /active-campaign/api/3/deals/{dealId}
Deal Stages
List Deal Stages
GET /active-campaign/api/3/dealStages
Create Deal Stage
POST /active-campaign/api/3/dealStages
Content-Type: application/json
{
"dealStage": {
"title": "New Stage",
"group": "1",
"order": "1"
}
}
Deal Groups (Pipelines)
List Pipelines
GET /active-campaign/api/3/dealGroups
Create Pipeline
POST /active-campaign/api/3/dealGroups
Content-Type: application/json
{
"dealGroup": {
"title": "Sales Pipeline",
"currency": "usd"
}
}
Automations
List Automations
GET /active-campaign/api/3/automations
Response:
json
{
"automations": [
{
"id": "1",
"name": "Welcome Series",
"cdate": "2026-02-09T14:00:00-06:00",
"mdate": "2026-02-09T14:00:00-06:00",
"status": "1"
}
],
"meta": {
"total": "1"
}
}
Get Automation
GET /active-campaign/api/3/automations/{automationId}
Campaigns
List Campaigns
GET /active-campaign/api/3/campaigns
Response:
json
{
"campaigns": [
{
"id": "1",
"name": "Newsletter",
"type": "single",
"status": "0"
}
],
"meta": {
"total": "1"
}
}
Get Campaign
GET /active-campaign/api/3/campaigns/{campaignId}
Users
List Users
GET /active-campaign/api/3/users
Response:
json
{
"users": [
{
"id": "1",
"username": "admin",
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]"
}
]
}
Get User
GET /active-campaign/api/3/users/{userId}
Accounts
List Accounts
GET /active-campaign/api/3/accounts
Create Account
POST /active-campaign/api/3/accounts
Content-Type: application/json
{
"account": {
"name": "Acme Inc"
}
}
Custom Fields
List Fields
GET /active-campaign/api/3/fields
Create Field
POST /active-campaign/api/3/fields
Content-Type: application/json
{
"field": {
"type": "text",
"title": "Custom Field",
"descript": "A custom field"
}
}
Field Values
Update Contact Field Value
PUT /active-campaign/api/3/fieldValues/{fieldValueId}
Content-Type: application/json
{
"fieldValue": {
"value": "New Value"
}
}
Notes
List Notes
GET /active-campaign/api/3/notes
Create Note
POST /active-campaign/api/3/notes
Content-Type: application/json
{
"note": {
"note": "This is a note",
"relid": "2",
"reltype": "Subscriber"
}
}
Webhooks
List Webhooks
GET /active-campaign/api/3/webhooks
Create Webhook
POST /active-campaign/api/3/webhooks
Content-Type: application/json
{
"webhook": {
"name": "My Webhook",
"url": "https://example.com/webhook",
"events": ["subscribe", "unsubscribe"],
"sources": ["public", "admin"]
}
}
Pagination
ActiveCampaign uses offset-based pagination:
GET /active-campaign/api/3/contacts?limit=20&offset=0
Parameters:
- limit - Results per page (default: 20)
- offset - Starting index
Response includes meta:
json
{
"contacts": [...],
"meta": {
"total": "150"
}
}
For large datasets, use orders[id]=ASC and id_greater parameter for better performance:
bash
GET /active-campaign/api/3/contacts?orders[id]=ASC&id_greater=100
Code Examples
JavaScript
const response = await fetch(
'https://gateway.maton.ai/active-campaign/api/3/contacts',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
console.log(data.contacts);
Python
import os
import requests
response = requests.get(
'https://gateway.maton.ai/active-campaign/api/3/contacts',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()
print(data['contacts'])
Python (Create Contact with Tag)
import os
import requests
headers = {
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
}
# Create contact
contact_response = requests.post(
'https://gateway.maton.ai/active-campaign/api/3/contacts',
headers=headers,
json={
'contact': {
'email': '[email protected]',
'firstName': 'New',
'lastName': 'User'
}
}
)
contact = contact_response.json()['contact']
print(f"Created contact ID: {contact['id']}")
# Add tag to contact
tag_response = requests.post(
'https://gateway.maton.ai/active-campaign/api/3/contactTags',
headers=headers,
json={
'contactTag': {
'contact': contact['id'],
'tag': '1'
}
}
)
print("Tag added to contact")
Notes
- All endpoints require the
/api/3/prefix - Request bodies use singular resource names wrapped in an object (e.g.,
{"contact": {...}}) - IDs are returned as strings
- Timestamps are in ISO 8601 format with timezone
- Rate limit: 5 requests per second per account
- DELETE operations return 200 OK (not 204)
- IMPORTANT: When piping curl output to
jqor other commands, environment variables like$MATON_API_KEYmay not expand correctly in some shell environments
Error Handling
| Status | Meaning |
|---|---|
| 400 | Missing ActiveCampaign connection or bad request |
| 401 | Invalid or missing Maton API key |
| 404 | Resource not found |
| 422 | Validation error |
| 429 | Rate limited (5 req/sec) |
| 4xx/5xx | Passthrough error from ActiveCampaign API |
Error responses include details:
json
{
"errors": [
{
"title": "The contact email is required",
"source": {
"pointer": "/data/attributes/email"
}
}
]
}
Troubleshooting: Invalid API Key
When you receive an "Invalid API key" error, ALWAYS follow these steps before concluding there is an issue:
- Check that the
MATON_API_KEYenvironment variable is set:
echo $MATON_API_KEY
- Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF