Constant Contact
Constant Contact API integration with managed OAuth. This is a write-capable integration — it can read, create, update, delete, and bulk-modify contacts, email campaigns, contact l…
byungkyu
@byungkyu
Install
$ openclaw skills install @byungkyu/constant-contactConstant Contact
Access the Constant Contact V3 API with managed OAuth authentication. Manage contacts, email campaigns, contact lists, tags, custom fields, segments, bulk operations, and marketing analytics.
Quick Start
# List contacts
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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://api.maton.ai/constant-contact/v3/{resource}
Maton 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://api.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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://api.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://api.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": "{connection_id}",
"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://api.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://api.maton.ai/constant-contact/v3/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Always include the Maton-Connection header to ensure requests go to the intended account, especially before any write operation. If you have multiple connections and omit this header, the gateway uses the default connection, which may not be the intended account.
Security & Permissions
- Access is scoped to contacts, email campaigns, lists, segments, tags, custom fields, and marketing analytics within the connected Constant Contact account. Only install if you need Constant Contact administration. Revoke unused connections promptly.
- Default to read-only operations. Always start by listing or retrieving resources to confirm identifiers before proposing any changes.
- All write operations require explicit user approval with specific identifiers. Before executing any POST, PUT, PATCH, or DELETE call:
- Retrieve and display the target resource (contact email, list name, campaign name/ID) so the user can verify.
- Clearly describe the intended effect (e.g., "This will delete contact 'john@example.com' (ID: abc123) from your account").
- Wait for explicit user confirmation before proceeding.
- High-impact operations require extra caution. Sending/scheduling email campaigns, bulk contact deletions, bulk list membership changes, and importing contacts can affect large numbers of marketing contacts and external recipients. These actions must include a summary of consequences and require confirmation.
- Campaign sending is irreversible — emails are delivered to external recipients immediately. Always preview the campaign and confirm recipients, subject, and content before sending or scheduling.
API Reference
Account
Get Account Summary
GET /constant-contact/v3/account/summary
Response:
{
"contact_email": "user@example.com",
"contact_phone": "5551234567",
"country_code": "us",
"encoded_account_id": "abc123",
"first_name": "John",
"last_name": "Doe",
"organization_name": "Acme Inc",
"state_code": "CA",
"time_zone_id": "US/Eastern"
}
Update Account Summary
PUT /constant-contact/v3/account/summary
Content-Type: application/json
{
"first_name": "John",
"last_name": "Doe",
"organization_name": "Acme Inc",
"time_zone_id": "US/Eastern"
}
Get Account Emails
Returns confirmed sender email addresses for the account.
GET /constant-contact/v3/account/emails
Response:
[
{
"email_id": 1,
"email_address": "marketing@example.com",
"roles": ["BILLING", "CONTACT", "DEFAULT_FROM", "REPLY_TO"],
"confirm_status": "CONFIRMED",
"confirm_time": "2026-02-05T07:32:49.766+0000",
"confirm_source_type": "SITE_OWNER"
}
]
Add Account Email
POST /constant-contact/v3/account/emails
Content-Type: application/json
{
"email_address": "newsender@example.com"
}
A confirmation email will be sent to the address. The email must be confirmed before it can be used as a sender.
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 exact email addresslists- Filter by list ID(s), comma-separatedsegment_id- Filter by segment IDtags- Filter by tag ID(s), comma-separatedupdated_after- ISO-8601 date filter (e.g.,2026-04-01T00:00:00Z)include- Include subresources:custom_fields,list_memberships,taggings,notes(comma-separated)limit- Results per page (default 50, max 500)
Example with filters:
GET /constant-contact/v3/contacts?email=john@example.com&status=all
GET /constant-contact/v3/contacts?updated_after=2026-04-01T00:00:00Z&limit=100
GET /constant-contact/v3/contacts?include=custom_fields,list_memberships,taggings&limit=50
Get Contact
GET /constant-contact/v3/contacts/{contact_id}
Query parameters:
include- Include subresources:custom_fields,list_memberships,taggings,notes(comma-separated)
Example:
GET /constant-contact/v3/contacts/{contact_id}?include=custom_fields,list_memberships,taggings,notes
Response:
{
"contact_id": "uuid",
"email_address": {
"address": "john@example.com",
"permission_to_send": "implicit",
"created_at": "2026-04-28T21:46:22Z",
"updated_at": "2026-04-28T21:46:22Z",
"opt_in_source": "Account",
"opt_in_date": "2026-04-28T21:46:22Z",
"confirm_status": "off"
},
"first_name": "John",
"last_name": "Doe",
"create_source": "Account",
"created_at": "2026-04-28T21:46:22Z",
"updated_at": "2026-04-28T21:46:22Z",
"custom_fields": [],
"list_memberships": ["list-uuid"],
"taggings": [],
"notes": []
}
Create Contact
IMPORTANT: The create_source field is required.
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",
"create_source": "Account",
"list_memberships": ["list-uuid-here"]
}
Valid create_source values: Account, Contact, Landing Page
Update Contact
IMPORTANT: The update_source field is required.
PUT /constant-contact/v3/contacts/{contact_id}
Content-Type: application/json
{
"email_address": {
"address": "john@example.com"
},
"first_name": "John",
"last_name": "Smith",
"update_source": "Account"
}
Valid update_source values: Account, Contact, Landing Page
Delete Contact
DELETE /constant-contact/v3/contacts/{contact_id}
Returns 204 No Content on success.
Create or Update Contact (Sign-Up Form)
Use this endpoint to create a new contact or update an existing one by email address 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"]
}
Response:
{
"contact_id": "uuid",
"action": "created"
}
The action field indicates whether the contact was created or updated.
Get Contact Counts
GET /constant-contact/v3/contacts/counts
Response:
{
"total": 150,
"explicit": 100,
"implicit": 40,
"pending": 5,
"unsubscribed": 5
}
Contact Lists
List Contact Lists
GET /constant-contact/v3/contact_lists
Query parameters:
include_count- Include total list count (true/false)include_membership_count- Include contact count per list:all,active,unsubscribedlimit- Results per page
Example:
GET /constant-contact/v3/contact_lists?include_membership_count=all
Response:
{
"lists": [
{
"list_id": "uuid",
"name": "Newsletter Subscribers",
"description": "Main newsletter",
"favorite": false,
"created_at": "2026-02-05T07:19:59Z",
"updated_at": "2026-02-05T07:19:59Z",
"membership_count": 150
}
],
"lists_count": 1
}
Get Contact List
GET /constant-contact/v3/contact_lists/{list_id}
Query parameters:
include_membership_count- Include membership count:all,active,unsubscribed
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}
Returns 202 Accepted (deletion is asynchronous).
Tags
List Tags
GET /constant-contact/v3/contact_tags
Query parameters:
limit- Results per page
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}
Returns 202 Accepted (deletion is asynchronous).
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"
}
Valid types: string, date
Response:
{
"custom_field_id": "uuid",
"label": "Customer ID",
"name": "customer_id",
"type": "string",
"version": 1,
"created_at": "2026-04-28T21:45:57Z",
"updated_at": "2026-04-28T21:45:57Z"
}
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)before_date- ISO-8601 date filterafter_date- ISO-8601 date filter
Response:
{
"campaigns": [
{
"campaign_id": "uuid",
"name": "March Newsletter",
"current_status": "Draft",
"type": "CUSTOM_CODE_EMAIL",
"type_code": 26,
"created_at": "2026-04-28T21:47:35.000Z",
"updated_at": "2026-04-28T21:47:35.000Z"
}
]
}
Get Email Campaign
GET /constant-contact/v3/emails/{campaign_id}
Response includes campaign activity IDs:
{
"campaign_activities": [
{
"campaign_activity_id": "uuid",
"role": "primary_email"
},
{
"campaign_activity_id": "uuid",
"role": "permalink"
}
],
"campaign_id": "uuid",
"current_status": "DRAFT",
"name": "March Newsletter",
"type": "CUSTOM_CODE_EMAIL"
}
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>"
}
]
}
The from_email must be a confirmed account email address (see Account Emails).
Rename Email Campaign
PATCH /constant-contact/v3/emails/{campaign_id}
Content-Type: application/json
{
"name": "New Campaign Name"
}
Delete Email Campaign
DELETE /constant-contact/v3/emails/{campaign_id}
Returns 204 No Content on success.
Email Campaign Activities
Campaign activities are the content/configuration of a campaign. Use the campaign_activity_id with role primary_email from the campaign response.
Get Campaign Activity
GET /constant-contact/v3/emails/activities/{campaign_activity_id}
Response:
{
"campaign_activity_id": "uuid",
"campaign_id": "uuid",
"role": "primary_email",
"contact_list_ids": [],
"segment_ids": [],
"current_status": "DRAFT",
"format_type": 5,
"from_email": "marketing@example.com",
"from_name": "Company",
"reply_to_email": "reply@example.com",
"subject": "Newsletter"
}
Update Campaign Activity
Updates the email content, targeting, and sender information. All fields in the request body are replaced.
PUT /constant-contact/v3/emails/activities/{campaign_activity_id}
Content-Type: application/json
{
"from_name": "Updated Name",
"from_email": "marketing@example.com",
"reply_to_email": "reply@example.com",
"subject": "Updated Subject",
"html_content": "<html><body><h1>Updated Content</h1></body></html>",
"contact_list_ids": ["list-uuid-here"]
}
IMPORTANT: from_email is required in the update body. Omitting it returns a validation error.
Preview Campaign Activity
Returns the rendered HTML and text preview of the email.
GET /constant-contact/v3/emails/activities/{campaign_activity_id}/previews
Response:
{
"campaign_activity_id": "uuid",
"from_email": "marketing@example.com",
"from_name": "Company",
"preview_html_content": "<html>...</html>",
"preview_text_content": "Plain text version...",
"reply_to_email": "reply@example.com",
"subject": "Newsletter"
}
Send Test Email
Sends a test/proof version of the email to specified addresses.
POST /constant-contact/v3/emails/activities/{campaign_activity_id}/tests
Content-Type: application/json
{
"email_addresses": ["test@example.com"],
"personal_message": "Please review this draft"
}
Returns 204 No Content on success.
Schedule Email Campaign
POST /constant-contact/v3/emails/activities/{campaign_activity_id}/schedules
Content-Type: application/json
{
"scheduled_date": "2026-06-01T10:00:00Z"
}
Note: The campaign activity must have a valid from_email, a physical address on the account, and at least one target list or segment before scheduling.
Get Campaign Schedule
GET /constant-contact/v3/emails/activities/{campaign_activity_id}/schedules
Unschedule Email Campaign
DELETE /constant-contact/v3/emails/activities/{campaign_activity_id}/schedules
Get Non-Opener Resend
GET /constant-contact/v3/emails/activities/{campaign_activity_id}/non_opener_resends
Returns resend details for sent campaigns. Returns empty array if no resend is configured.
Get A/B Test
GET /constant-contact/v3/emails/activities/{campaign_activity_id}/abtest
Segments
List Segments
GET /constant-contact/v3/segments
Query parameters:
sort_by- Sort field (e.g.,name,date)sort_order-ascordesc
Get Segment
GET /constant-contact/v3/segments/{segment_id}
Create Segment
Segments use a criteria object to define the audience filter:
POST /constant-contact/v3/segments
Content-Type: application/json
{
"name": "Engaged Subscribers",
"segment_criteria": {
"version": "3.0.0",
"criteria": { ... }
}
}
Note: The segment_criteria must be a JSON object (not a string). The criteria schema is complex and version-dependent. Refer to the Constant Contact Segments Documentation for the full criteria format.
Update Segment
PUT /constant-contact/v3/segments/{segment_id}
Content-Type: application/json
{
"name": "Updated Segment Name",
"segment_criteria": { ... }
}
Delete Segment
DELETE /constant-contact/v3/segments/{segment_id}
Bulk Activities
Bulk activities run asynchronously. After creating a bulk activity, poll the activity status endpoint until completion.
List Activities
GET /constant-contact/v3/activities
Query parameters:
limit- Results per pagestate- Filter by state:processing,completed,cancelled,failed,timed_out
Get Activity Status
GET /constant-contact/v3/activities/{activity_id}
Response:
{
"activity_id": "uuid",
"state": "completed",
"started_at": "2026-04-28T21:48:16Z",
"completed_at": "2026-04-28T21:48:16Z",
"created_at": "2026-04-28T21:48:15Z",
"updated_at": "2026-04-28T21:48:16Z",
"percent_done": 100,
"activity_errors": [],
"status": {
"items_total_count": 1,
"items_completed_count": 1
}
}
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"]
}
The source can also use list_ids to copy contacts from other lists:
{
"source": {
"list_ids": ["source-list-uuid"]
},
"list_ids": ["target-list-uuid"]
}
Remove Contacts from Lists
POST /constant-contact/v3/activities/remove_list_memberships
Content-Type: application/json
{
"source": {
"contact_ids": ["contact-uuid-1", "contact-uuid-2"]
},
"list_ids": ["target-list-uuid"]
}
Add Tags to Contacts
POST /constant-contact/v3/activities/contacts_taggings_add
Content-Type: application/json
{
"source": {
"contact_ids": ["contact-uuid-1", "contact-uuid-2"]
},
"tag_ids": ["tag-uuid"]
}
Remove Tags from Contacts
POST /constant-contact/v3/activities/contacts_taggings_remove
Content-Type: application/json
{
"source": {
"contact_ids": ["contact-uuid-1", "contact-uuid-2"]
},
"tag_ids": ["tag-uuid"]
}
Export Contacts
POST /constant-contact/v3/activities/contact_exports
Content-Type: application/json
{
"contact_ids": ["contact-uuid-1", "contact-uuid-2"],
"fields": ["first_name", "last_name", "email"]
}
The response includes a results link to download the export:
{
"activity_id": "uuid",
"state": "initialized",
"_links": {
"self": { "href": "/v3/activities/{activity_id}" },
"results": { "href": "/v3/contact_exports/{export_id}" }
}
}
Download Contact Export
After the export activity completes, download the CSV:
GET /constant-contact/v3/contact_exports/{export_id}
Returns CSV data.
Import Contacts
POST /constant-contact/v3/activities/contacts_file_import
Content-Type: multipart/form-data
{file: contacts.csv, list_ids: ["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"]
}
Reporting
Email Campaign Summaries
GET /constant-contact/v3/reports/summary_reports/email_campaign_summaries
Response:
{
"bulk_email_campaign_summaries": [...],
"aggregate_percents": {
"click": 5.2,
"open": 22.1,
"did_not_open": 72.7,
"bounce": 1.3,
"unsubscribe": 0.2
}
}
Get Email Campaign Report
Returns detailed metrics for a specific sent campaign activity.
GET /constant-contact/v3/reports/email_reports/{campaign_activity_id}
Note: Only available for sent campaigns. Draft campaigns return 404.
Contact Activity Summary
GET /constant-contact/v3/reports/contact_reports/{contact_id}/activity_summary
Response:
{
"contact_id": "uuid",
"campaign_activities": [
{
"campaign_activity_id": "uuid",
"sends": 1,
"opens": 1,
"clicks": 0,
"bounces": 0
}
]
}
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
When there are no more pages, the _links.next field is absent from the response.
Code Examples
JavaScript
const response = await fetch(
'https://api.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://api.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 confirmed sender email addresses
format_type: 5for custom HTML emailscreate_sourceis required when creating contacts;update_sourceis required when updating- Scheduling a campaign requires a valid physical address on the account and at least one target list
- Delete operations on tags and lists return
202 Accepted(asynchronous); contacts and campaigns return204 No Content - 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": "contacts.api.validation.error",
"error_message": "create_source is missing, create_source does not have a valid value"
}
]
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://api.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://api.maton.ai/constant-contact/v3/contacts - Incorrect:
https://api.maton.ai/v3/contacts
Resources
Related skills
Klaviyo
@byungkyuKlaviyo API integration with managed OAuth. Access profiles, lists, segments, campaigns, flows, events, metrics, templates, catalogs, and webhooks. Use this...
Kit
@byungkyuKit (formerly ConvertKit) API integration with managed OAuth. Manage email subscribers, forms, tags, sequences, broadcasts, and custom fields. Use this skill...
SendGrid
@byungkyuSendGrid API integration with managed OAuth. Send emails, manage contacts, templates, suppressions, statistics, sender identities, unsubscribe groups, and SendGrid API keys. All write operations require explicit user approval. Sending emails delivers messages to real recipients
Mailchimp
@byungkyuMailchimp Marketing API integration with managed OAuth. Access audiences, campaigns, templates, automations, reports, and manage subscribers. Use this skill...
Instantly
@byungkyuInstantly API integration with managed OAuth. Cold email outreach platform for managing campaigns, leads, accounts, and analytics. Use this skill when users want to create campaigns, manage leads, send emails, or view analytics. For other third party apps, use the api-gateway skill
Zoho Mail
@byungkyuZoho Mail API integration with managed OAuth. Send, receive, and manage emails, folders, and labels. Use this skill when users want to send emails, read mess...