Constant Contact
Verified@byungkyu
npx machina-cli add skill @byungkyu/constant-contact --openclawConstant 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:
{
"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,unsubscribedemail- Filter by email addresslists- Filter by list ID(s)segment_id- Filter by segment IDtags- Filter by tag ID(s)updated_after- ISO-8601 date filterinclude- Include subresources:custom_fields,list_memberships,taggings,noteslimit- 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": "john@example.com",
"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": "john@example.com"
},
"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": "john@example.com",
"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 listinclude_membership_count- Include membership countlimit- 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": "marketing@example.com",
"reply_to_email": "reply@example.com",
"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": ["test@example.com"]
}
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
Resources
Overview
Leverage the Constant Contact V3 API through the Maton gateway with managed OAuth. You can manage contacts, email campaigns, lists, segments, and marketing analytics using a MATON_API_KEY. The gateway proxies requests to api.cc.email/v3 and supports multiple connections via Maton-Connection.
How This Skill Works
Requests are sent to the Maton gateway at gateway.maton.ai/constant-contact/v3/{resource} and are proxied to api.cc.email/v3 with the OAuth token injected. Authenticate each request with Authorization: Bearer $MATON_API_KEY and, when using multiple accounts, specify the target connection with the Maton-Connection header.
When to Use It
- You need to create, update, or fetch Constant Contact contacts, lists, or segments for an email campaign.
- You want to analyze campaign performance data through Constant Contact analytics endpoints.
- You are integrating Constant Contact into a larger automation workflow using the Maton gateway.
- You manage multiple Constant Contact accounts and must switch between them programmatically.
- You require secure, authenticated access via a MATON_API_KEY without embedding credentials in code.
Quick Start
- Step 1: Export MATON_API_KEY in your environment (e.g., export MATON_API_KEY="YOUR_API_KEY").
- Step 2: List contacts via the gateway: send a GET request to https://gateway.maton.ai/constant-contact/v3/contacts with header Authorization: Bearer $MATON_API_KEY.
- Step 3: If you have multiple connections, include the Maton-Connection header with the desired connection ID to target a specific Constant Contact account.
Best Practices
- Store MATON_API_KEY securely as an environment variable and never hard-code it in code.
- Use the Maton-Connection header to target the correct Constant Contact account when multiple connections exist.
- Paginate responses for large datasets (contacts, campaigns) and implement retry logic for transient errors.
- Validate all resource IDs and endpoints before requests to avoid invalid operations.
- Regularly rotate API keys and monitor the Ctrl panel for connection health and status.
Example Use Cases
- List all active contacts via GET https://gateway.maton.ai/constant-contact/v3/contacts with Authorization: Bearer $MATON_API_KEY.
- Create a new contact and add them to a specific list using the Constant Contact API through the gateway.
- Retrieve account connection status to confirm an ACTIVE OAuth session for a given connection.
- Switch between two Constant Contact accounts by adding Maton-Connection: <connection_id> to your requests.
- Query campaign analytics to evaluate open rates and click-through metrics through the gateway.