Constant Contact
Access the Constant Contact V3 API with managed OAuth authentication. Manage contacts, email campaigns, contact lists, segments, and marketing analytics.
Quick Start
# List contacts
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/constant-contact/v3/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/constant-contact/v3/{resource}
The gateway proxies requests to api.cc.email/v3 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 Constant Contact 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=constant-contact&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': 'constant-contact'}).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": "4314bd0f-fd56-40ab-8c65-2676dd2c23c4",
"status": "ACTIVE",
"creation_time": "2026-02-07T07:41:05.859244Z",
"last_updated_time": "2026-02-07T07:41:32.658230Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "constant-contact",
"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 Constant Contact 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/constant-contact/v3/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '4314bd0f-fd56-40ab-8c65-2676dd2c23c4')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If omitted, the gateway uses the default (oldest) active connection.
API Reference
Account
Get Account Summary
GET /constant-contact/v3/account/summary
Get Account Emails
GET /constant-contact/v3/account/emails
Get User Privileges
GET /constant-contact/v3/account/user/privileges
Contacts
List Contacts
GET /constant-contact/v3/contacts
Query parameters:
- status - Filter by status: all, active, deleted, not_set, pending_confirmation, temp_hold, unsubscribed
- email - Filter by email address
- lists - Filter by list ID(s)
- segment_id - Filter by segment ID
- tags - Filter by tag ID(s)
- updated_after - ISO-8601 date filter
- include - Include subresources: custom_fields, list_memberships, taggings, notes
- limit - Results per page (default 50, max 500)
Get Contact
GET /constant-contact/v3/contacts/{contact_id}
Create Contact
POST /constant-contact/v3/contacts
Content-Type: application/json
{
"email_address": {
"address": "[email protected]",
"permission_to_send": "implicit"
},
"first_name": "John",
"last_name": "Doe",
"job_title": "Developer",
"company_name": "Acme Inc",
"list_memberships": ["list-uuid-here"]
}
Update Contact
PUT /constant-contact/v3/contacts/{contact_id}
Content-Type: application/json
{
"email_address": {
"address": "[email protected]"
},
"first_name": "John",
"last_name": "Smith"
}
Delete Contact
DELETE /constant-contact/v3/contacts/{contact_id}
Create or Update Contact (Sign-Up Form)
Use this endpoint to create a new contact or update an existing one without checking if they exist first:
POST /constant-contact/v3/contacts/sign_up_form
Content-Type: application/json
{
"email_address": "[email protected]",
"first_name": "John",
"last_name": "Doe",
"list_memberships": ["list-uuid-here"]
}
Get Contact Counts
GET /constant-contact/v3/contacts/counts
Contact Lists
List Contact Lists
GET /constant-contact/v3/contact_lists
Query parameters:
- include_count - Include contact count per list
- include_membership_count - Include membership count
- limit - Results per page
Get Contact List
GET /constant-contact/v3/contact_lists/{list_id}
Create Contact List
POST /constant-contact/v3/contact_lists
Content-Type: application/json
{
"name": "Newsletter Subscribers",
"description": "Main newsletter list",
"favorite": false
}
Update Contact List
PUT /constant-contact/v3/contact_lists/{list_id}
Content-Type: application/json
{
"name": "Updated List Name",
"description": "Updated description",
"favorite": true
}
Delete Contact List
DELETE /constant-contact/v3/contact_lists/{list_id}
Tags
List Tags
GET /constant-contact/v3/contact_tags
Create Tag
POST /constant-contact/v3/contact_tags
Content-Type: application/json
{
"name": "VIP Customer"
}
Update Tag
PUT /constant-contact/v3/contact_tags/{tag_id}
Content-Type: application/json
{
"name": "Premium Customer"
}
Delete Tag
DELETE /constant-contact/v3/contact_tags/{tag_id}
Custom Fields
List Custom Fields
GET /constant-contact/v3/contact_custom_fields
Create Custom Field
POST /constant-contact/v3/contact_custom_fields
Content-Type: application/json
{
"label": "Customer ID",
"type": "string"
}
Delete Custom Field
DELETE /constant-contact/v3/contact_custom_fields/{custom_field_id}
Email Campaigns
List Email Campaigns
GET /constant-contact/v3/emails
Query parameters:
- limit - Results per page (default 50)
Get Email Campaign
GET /constant-contact/v3/emails/{campaign_id}
Create Email Campaign
POST /constant-contact/v3/emails
Content-Type: application/json
{
"name": "March Newsletter",
"email_campaign_activities": [
{
"format_type": 5,
"from_name": "Company Name",
"from_email": "[email protected]",
"reply_to_email": "[email protected]",
"subject": "March Newsletter",
"html_content": "<html><body><h1>Hello!</h1></body></html>"
}
]
}
Update Email Campaign Activity
PUT /constant-contact/v3/emails/activities/{campaign_activity_id}
Content-Type: application/json
{
"contact_list_ids": ["list-uuid-here"],
"from_name": "Updated Name",
"subject": "Updated Subject"
}
Send Test Email
POST /constant-contact/v3/emails/activities/{campaign_activity_id}/tests
Content-Type: application/json
{
"email_addresses": ["[email protected]"]
}
Schedule Email Campaign
POST /constant-contact/v3/emails/activities/{campaign_activity_id}/schedules
Content-Type: application/json
{
"scheduled_date": "2026-03-01T10:00:00Z"
}
Segments
List Segments
GET /constant-contact/v3/segments
Get Segment
GET /constant-contact/v3/segments/{segment_id}
Create Segment
POST /constant-contact/v3/segments
Content-Type: application/json
{
"name": "Engaged Subscribers",
"segment_criteria": "..."
}
Delete Segment
DELETE /constant-contact/v3/segments/{segment_id}
Bulk Activities
Import Contacts
POST /constant-contact/v3/activities/contacts_file_import
Content-Type: multipart/form-data
{file: contacts.csv, list_ids: ["list-uuid"]}
Add Contacts to Lists
POST /constant-contact/v3/activities/add_list_memberships
Content-Type: application/json
{
"source": {
"contact_ids": ["contact-uuid-1", "contact-uuid-2"]
},
"list_ids": ["list-uuid"]
}
Remove Contacts from Lists
POST /constant-contact/v3/activities/remove_list_memberships
Content-Type: application/json
{
"source": {
"list_ids": ["source-list-uuid"]
},
"list_ids": ["target-list-uuid"]
}
Delete Contacts in Bulk
POST /constant-contact/v3/activities/contact_delete
Content-Type: application/json
{
"contact_ids": ["contact-uuid-1", "contact-uuid-2"]
}
Get Activity Status
GET /constant-contact/v3/activities/{activity_id}
List Activities
GET /constant-contact/v3/activities
Reporting
Email Campaign Summaries
GET /constant-contact/v3/reports/summary_reports/email_campaign_summaries
Query parameters:
- start - Start date (ISO-8601)
- end - End date (ISO-8601)
Get Email Campaign Report
GET /constant-contact/v3/reports/email_reports/{campaign_activity_id}
Contact Activity Summary
GET /constant-contact/v3/reports/contact_reports/{contact_id}/activity_summary
Pagination
The API uses cursor-based pagination with a limit parameter:
GET /constant-contact/v3/contacts?limit=50
Response includes pagination links:
{
"contacts": [...],
"_links": {
"next": {
"href": "/v3/contacts?cursor=abc123"
}
}
}
Use the cursor from the next link for subsequent pages:
GET /constant-contact/v3/contacts?cursor=abc123
Code Examples
JavaScript
const response = await fetch(
'https://gateway.maton.ai/constant-contact/v3/contacts?limit=50',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
Python
import os
import requests
response = requests.get(
'https://gateway.maton.ai/constant-contact/v3/contacts',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
params={'limit': 50}
)
data = response.json()
Notes
- Resource IDs use UUID format (36 characters with hyphens)
- All dates use ISO-8601 format:
YYYY-MM-DDThh:mm:ss.sZ - Maximum 1,000 contact lists per account
- A contact can belong to up to 50 lists
- Bulk operations are asynchronous - check activity status for completion
- Email campaigns require verified sender email addresses
format_type: 5for custom HTML emails- IMPORTANT: When using curl commands, use
curl -gwhen URLs contain brackets to disable glob parsing - 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 Constant Contact connection or invalid request |
| 401 | Invalid or missing Maton API key, or OAuth token expired |
| 403 | Insufficient permissions for the requested operation |
| 404 | Resource not found |
| 409 | Conflict (e.g., duplicate email address) |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Constant Contact API |
Error Response Format
{
"error_key": "unauthorized",
"error_message": "Unauthorized"
}
Troubleshooting: API Key Issues
- 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
Troubleshooting: Invalid App Name
- Ensure your URL path starts with
constant-contact. For example:
- Correct:
https://gateway.maton.ai/constant-contact/v3/contacts - Incorrect:
https://gateway.maton.ai/v3/contacts