# MailerLogic API

Complete REST API for managing email delivery, tracking, and analytics.

Get started in minutes:
1. Get your API key from your customer dashboard
2. Send authenticated requests using the X-API-Key header
3. Start sending emails via SMTP or API

For detailed guides, see the Getting Started section in the navigation.


Version: 1.0.0

## Servers

US Data Center
```
https://api.mailerlogic.net
```

EU Data Center (coming soon)
```
https://eu-api.mailerlogic.net
```

## Security

### ApiKeyAuth

Customer API Key authentication (PRIMARY method for most endpoints).

**Use this for:**
- Customer portal endpoints (`/api/customer/*`)
- SMTP credentials (`/api/smtp-credentials`)
- Statistics endpoints (`/api/stats/*`)
- Domain management (`/api/customer/domains`)
- Health scores, unsubscribes, rate limits

Example:
```
X-API-Key: ml_live_1234567890abcdef...
```

Get your API key from your customer dashboard or use the `/api/customer/rotate-key` endpoint.


Type: apiKey
In: header
Name: X-API-Key

### BearerAuth

Customer API Key using Bearer token authentication.

**Use this ONLY for Events Tracking API:**
- `GET /api/v1/events`
- `GET /api/v1/emails/{email_id}/events`

Example:
```
Authorization: Bearer ml_live_1234567890abcdef...
```


Type: http
Scheme: bearer
Bearer Format: API Key

## Download OpenAPI description

[MailerLogic API](https://developers.mailerlogic.com/_bundle/customer-api.openapi.yaml)

## Email Sending

Send transactional and marketing emails via REST API.
Simple API for sending individual emails with full tracking support.

## Stream Types & IP Routing

MailerLogic uses **stream-based IP routing** to optimize deliverability by sending different types of emails through dedicated IP pools.

### Available Stream Types

- **`transactional`** - Time-sensitive, high-priority emails
  - Password resets, 2FA codes, order confirmations
  - Optimized for highest deliverability
  - Recommended for mission-critical emails

- **`broadcast`** - Marketing campaigns and newsletters
  - Newsletters, promotional emails, announcements
  - Optimized for high-volume sending
  - Ideal for promotional campaigns

- **`shared`** (default) - General purpose emails
  - Notifications, alerts, general correspondence
  - Balanced approach for mixed content types
  - Good default for most use cases

### How to Use Stream Types

1. **API**: Specify `stream_type` in request body or `metadata`
2. **SMTP**: Add `X-Stream-Type` header to your email (see SMTP section)
3. **Automatic Selection**: If not specified, defaults to `shared`

The system automatically optimizes delivery for each stream type to ensure the best inbox placement and deliverability for your emails.

### Tags vs Stream Types

- **Stream Type** (`stream_type`): Controls delivery optimization and inbox placement
- **Tags** (`tag`): Organizes emails for analytics and filtering

Example: Stream type `transactional` optimizes for maximum reliability, while tag `password-reset` helps you filter these emails in reports.

### Best Practices

✅ **DO:**
- Use `transactional` for password resets, 2FA, order confirmations
- Use `broadcast` for newsletters and marketing campaigns
- Combine stream types with tags for better organization
- Test your integration with different stream types

❌ **DON'T:**
- Send marketing emails through `transactional` stream
- Mix high-volume campaigns with transactional emails
- Use tags as a substitute for stream types

## Email Lifecycle Events

Email lifecycle events provide detailed tracking information about each stage of an email's journey — including delivery, opens, clicks, bounces, complaints, and other post-send activity. These events are stored as historical records and can be retrieved programmatically through the Lifecycle Events API.

### Important

**Access to historical lifecycle event data is available only for customers whose subscription tier includes this feature.**

All customers will still receive the standard send-time response from the `/api/send` endpoint, but only eligible tiers can query historical lifecycle data via the `/api/events` endpoint.

### Standard Send Response

The synchronous response from `POST /api/send` is available to all customers, regardless of subscription level.

Example standard response:
```json
{
  "messageId": "abcd1234",
  "status": "queued"
}
```

This response confirms that the email has been accepted for processing but does not include historical or post-send engagement data.

### Tracked Events

After sending an email, the following events are tracked automatically:

- **queued**: Email accepted and queued for delivery
- **sent**: Email handed off to recipient server
- **delivered**: Recipient server accepted the email
- **bounce**: Email rejected by recipient server
- **open**: Recipient opened the email (requires tracking enabled)
- **click**: Recipient clicked a link (requires tracking enabled)
- **complaint**: Recipient marked as spam
- **unsubscribe**: Recipient unsubscribed

Query these events via the `/api/events` endpoint (enterprise feature).

## Automatic Retry Policy

Failed emails are automatically retried with exponential backoff:

- **Soft bounces**: Retried up to 3 times over 24 hours
- **Temporary failures**: Retried up to 5 times over 48 hours
- **Hard bounces**: Not retried (permanent failure)

**Retry Schedule:**
1. Immediate retry (0 minutes)
2. Second attempt (15 minutes)
3. Third attempt (1 hour)
4. Fourth attempt (4 hours)
5. Final attempt (24 hours)

After all retries are exhausted, the email status becomes `failed`.


### Send a single email

 - [POST /api/v1/send](https://developers.mailerlogic.com/customer-api.openapi/email-sending/paths/~1api~1v1~1send/post.md): Send a single transactional or marketing email via REST API.

Simple API for sending emails with:
- Automatic queuing and delivery
- Built-in tracking (opens & clicks)
- File attachments (PDF, ZIP, images, documents)
- Calendar invites (iCal/RFC 5545)
- Template variable support
- Custom headers
- Full bounce and complaint handling

Requirements:
- Verified sending domain
- Active customer account
- Valid API key

Auto-domain selection: If you don't specify a domain, we'll automatically use your first verified domain.

### Send batch of different emails

 - [POST /api/v1/batch](https://developers.mailerlogic.com/customer-api.openapi/email-sending/paths/~1api~1v1~1batch/post.md): Send up to 500 completely different emails in a single API call.

Batch sending where each email can have:
- Different recipient
- Different subject
- Different content
- Different settings
- File attachments
- Calendar invites

Perfect for sending multiple transactional emails at once (order confirmations, password resets, etc.).

Limits:
- Maximum 500 emails per batch
- Each email validated independently
- Failed emails don't affect successful ones

Use cases:
- Sending different transactional emails simultaneously
- Mixed email types in one API call
- High-volume transactional sending

Not for: Newsletter-style emails with same content → Use /api/bulk-send instead

### Send bulk emails (mail merge)

 - [POST /api/v1/bulk-send](https://developers.mailerlogic.com/customer-api.openapi/email-sending/paths/~1api~1v1~1bulk-send/post.md): Send the same email template to multiple recipients with personalization.

Mail merge functionality for:
- Newsletters with personalized greetings
- Marketing campaigns with custom variables
- Bulk transactional emails with recipient-specific data

Features:
- Template variables: Use {{variable}} syntax in subject, HTML, and text
- Built-in placeholders: {{unsubscribe}} for unsubscribe links
- Per-recipient personalization via vars object
- Automatic variable substitution for each recipient
- Single template, many recipients
- File attachments (same for all recipients)
- Calendar invites (same for all recipients)

Limits:
- Recommended: Up to 10,000 recipients per call
- Each recipient gets their own personalized copy

Use cases:
- Newsletter campaigns: "Hi {{name}}, check out our new {{product}}..."
- Promotional emails with unique discount codes
- Event invitations with personalized details

Built-in Placeholders:
- {{unsubscribe}} - Secure unsubscribe link (unique per recipient)

Not for: Different emails to each recipient → Use /api/batch instead

### Send email to a segment

 - [POST /api/v1/send-segment](https://developers.mailerlogic.com/customer-api.openapi/email-sending/paths/~1api~1v1~1send-segment/post.md): Send emails to contacts matching segment criteria using dynamic segmentation or saved segments.

Features:
- Send to saved segments (by segment_id)
- Send with inline segment filters (dynamic targeting)
- NEW: Exclude unengaged contacts (improve deliverability & engagement metrics)
- Account-level merge fields (same for all recipients)
- Contact-level personalization (name, email, custom properties)
- Asynchronous processing (returns immediately, processes in background)

Unengaged Filtering (NEW):
Automatically exclude contacts who haven't opened or clicked any email in the last N days.
This improves sender reputation, reduces costs, and increases engagement rates.
- Set exclude_unengaged: true and unengaged_days: 90 (recommended)
- Contacts with NO email activity in the lookback period are excluded
- Perfect for newsletters, promotions, and regular campaigns
- Disable for transactional emails (password resets, receipts, etc.)

Merge Fields:
- Account-level: account_merge_fields - same value for all recipients (e.g., company_name, promo_code)
- Contact-level: Automatically available ({{name}}, {{email}}, {{first_name}}, {{last_name}}, plus all custom properties)

Segmentation Options:
- Option 1: Use existing segment → Provide segment_id
- Option 2: Dynamic filters → Provide segment_filters object with filter conditions

Segment Filter Structure:
json
{
  "match_type": "all",  // "all" (AND) or "any" (OR)
  "filter_conditions": [
    {
      "property": "status",
      "operator": "equals",
      "value": "subscribed"
    },
    {
      "property": "tags",
      "operator": "contains",
      "value": "vip"
    }
  ]
}


Available Operators:
- equals, not_equals, contains, not_contains
- greater_than, less_than, greater_than_or_equal, less_than_or_equal
- is_empty, is_not_empty, is_true, is_false

Limits:
- Max 10 filter groups
- Max 20 filters per group
- Max 100 total filters

Use Cases:
- Newsletter to all subscribed contacts
- Promotional email to contacts tagged "vip"
- Re-engagement campaign for inactive subscribers
- Product updates to contacts with specific custom properties

### Send test email

 - [POST /api/v1/customer/test-email](https://developers.mailerlogic.com/customer-api.openapi/email-sending/paths/~1api~1v1~1customer~1test-email/post.md): Send a test email with intelligent defaults based on domain health.

Features:
- Supports 3 test modes: basic, standard, full
- Auto-disables tracking based on test mode
- Basic spam word detection (not comprehensive scoring)
- Returns warnings and recommendations
- Provides next steps for new domains

Test Modes:
- basic: Disables all tracking regardless of request. Best for new domains.
- standard: Disables open tracking, enables click tracking. For warming domains.
- full: Honors your tracking preferences. For established domains.

Best Practice:
1. Call /api/v1/customer/domains/test-readiness/:domain_id first
2. Use the recommended test mode
3. Review warnings before sending
4. Follow next steps provided in response

Content Analysis:
Set analyze_content: true to receive basic spam word warnings.

> Note: This endpoint performs only basic spam detection. For comprehensive content
> scoring with detailed analysis, use POST /api/content-score (subject to tier limits).

### Test email deliverability

 - [POST /api/v1/test-deliverability](https://developers.mailerlogic.com/customer-api.openapi/email-sending/testdeliverability.md): Comprehensive email deliverability testing that analyzes your email content for:

- Spam score using SpamAssassin (industry standard)
- Blacklist status across major RBLs
- Link safety scanning (phishing, malware, redirects)
- Accessibility compliance (alt text, semantic HTML)
- Content analysis (word count, readability, image ratio)

Best Practices:
- Test emails BEFORE sending to large lists
- Fix high spam scores (aim for < 5.0)
- Ensure all links are safe and valid
- Add alt text to images for accessibility
- Balance text/image ratio (avoid image-only emails)

Performance:
- Average test time: 2-5 seconds
- Cached blacklist checks for speed
- Real-time spam scoring

## Campaign Reports

Track campaign performance with comprehensive reporting and analytics.

**Features:**
- Overview statistics (sends, opens, clicks, bounces, rates)
- Contact-level drill-down (who opened, who clicked)
- Timeline charts (hourly/daily breakdowns)
- Link click analysis
- Scanner vs human filtering for accurate metrics

**Supported Campaign Types:**

✅ **Send to Segment** (`/api/v1/send-segment`)
- Campaign ID = `job_id` returned from the API
- Sends to contacts matching segment filters
- Full campaign analytics available

✅ **Bulk Newsletter** (`/api/v1/bulk-send`)
- Campaign ID = `campaign_id` or `bulk_session_id` (UUID) returned from the API
- Both fields contain the same UUID value for campaign tracking
- Mail merge with personalized variables
- Full campaign analytics available

❌ **Batch Send** (`/api/v1/batch`)
- No unified campaign tracking (individual emails)
- Use Statistics API (`/api/v1/stats`) for aggregate analytics
- Use Events API (`/api/v1/events`) for individual email logs

**Example Workflows:**

```javascript
// Send to Segment Campaign
const { job_id } = await sendSegment({ segment_id, subject, html, from });
const report = await fetch(`/api/v1/campaigns/${job_id}/report?filter=human_only`);

// Bulk Newsletter Campaign
const { campaign_id } = await bulkSend({ recipients, subject, html, from });
// Note: bulk_session_id also available (same value as campaign_id)
const report = await fetch(`/api/v1/campaigns/${campaign_id}/report?filter=human_only`);

// View contacts who opened
const openers = await fetch(`/api/v1/campaigns/${campaignId}/contacts/opened`);
```

**Scanner Filtering:**
All endpoints support `filter` query parameter:
- `all` - Include all activity (default)
- `human_only` - Exclude scanner/bot activity (recommended for metrics)
- `scanner_only` - Only scanner/bot activity

**Use Cases:**
- Track newsletter performance
- Measure campaign ROI
- Identify engaged subscribers
- Optimize send times with timeline data
- Analyze link popularity


### Get campaign overview report

 - [GET /api/v1/campaigns/{campaignId}/report](https://developers.mailerlogic.com/customer-api.openapi/campaign-reports/paths/~1api~1v1~1campaigns~1%7Bcampaignid%7D~1report/get.md): Get comprehensive campaign statistics including sends, opens, clicks, bounces, and calculated rates.

Supported Campaign Types:
- Send to Segment: Use the job_id returned from /api/v1/send-segment
- Bulk Newsletter: Use the campaign_id (or bulk_session_id) UUID returned from /api/v1/bulk-send
- Batch Send: Not supported (use /api/v1/stats or /api/v1/events instead)

Important: For bulk-send campaigns, use the UUID directly (e.g., f1e2d3c4-b5a6-7890-cdef-123456789abc), NOT a prefixed string.

Metrics Included:
- Total sent, delivered, bounced (hard/soft breakdown)
- Unique opens, total opens, open rate
- Unique clicks, total clicks, click rate, click-to-open rate
- Complaints and unsubscribes
- Campaign date range (first/last sent)

Scanner Filtering:
Use the filter parameter to exclude bot/scanner activity for accurate engagement metrics.

### Get contacts who opened

 - [GET /api/v1/campaigns/{campaignId}/contacts/opened](https://developers.mailerlogic.com/customer-api.openapi/campaign-reports/paths/~1api~1v1~1campaigns~1%7Bcampaignid%7D~1contacts~1opened/get.md): Get list of contacts who opened the campaign email.

Perfect for drill-down functionality where clicking the opens count
shows the actual contacts who opened.

Returns:
- Contact details (email, name, company, phone)
- First and last open timestamps
- Total number of opens per contact

### Get contacts who clicked

 - [GET /api/v1/campaigns/{campaignId}/contacts/clicked](https://developers.mailerlogic.com/customer-api.openapi/campaign-reports/paths/~1api~1v1~1campaigns~1%7Bcampaignid%7D~1contacts~1clicked/get.md): Get list of contacts who clicked links in the campaign.

Perfect for drill-down functionality where clicking the clicks count
shows the actual contacts who clicked.

### Get contacts whose emails bounced

 - [GET /api/v1/campaigns/{campaignId}/contacts/bounced](https://developers.mailerlogic.com/customer-api.openapi/campaign-reports/paths/~1api~1v1~1campaigns~1%7Bcampaignid%7D~1contacts~1bounced/get.md): Get list of contacts whose emails bounced with bounce type and reason.

Useful for identifying invalid addresses and cleaning your contact list.

### Get contacts whose emails failed delivery

 - [GET /api/v1/campaigns/{campaignId}/contacts/failed](https://developers.mailerlogic.com/customer-api.openapi/campaign-reports/paths/~1api~1v1~1campaigns~1%7Bcampaignid%7D~1contacts~1failed/get.md): Get list of contacts whose emails failed delivery after exhausting retries.

These are temporary failures (like timeouts or throttling) that were retried multiple times but never succeeded.
Different from bounces which are permanent failures.

### Get all campaign recipients with status

 - [GET /api/v1/campaigns/{campaignId}/recipients](https://developers.mailerlogic.com/customer-api.openapi/campaign-reports/paths/~1api~1v1~1campaigns~1%7Bcampaignid%7D~1recipients/get.md): Get comprehensive list of all campaign recipients with their delivery status,
engagement data (opens/clicks), and bounce information.

Supports filtering by status and searching by email/name.

### Get opens timeline data (for charts)

 - [GET /api/v1/campaigns/{campaignId}/timeline/opens](https://developers.mailerlogic.com/customer-api.openapi/campaign-reports/paths/~1api~1v1~1campaigns~1%7Bcampaignid%7D~1timeline~1opens/get.md): Get hourly or daily breakdown of email opens for charting.

Perfect for creating timeline charts showing when recipients opened your campaign.

Returns both unique opens (distinct recipients) and total opens (includes repeat opens).

### Get clicks timeline data (for charts)

 - [GET /api/v1/campaigns/{campaignId}/timeline/clicks](https://developers.mailerlogic.com/customer-api.openapi/campaign-reports/paths/~1api~1v1~1campaigns~1%7Bcampaignid%7D~1timeline~1clicks/get.md): Get hourly or daily breakdown of link clicks for charting.

Perfect for creating timeline charts showing when recipients clicked links in your campaign.

### Get link click analysis

 - [GET /api/v1/campaigns/{campaignId}/links](https://developers.mailerlogic.com/customer-api.openapi/campaign-reports/paths/~1api~1v1~1campaigns~1%7Bcampaignid%7D~1links/get.md): Get all links clicked in the campaign with detailed click statistics.

Shows which links were most popular and how many unique recipients clicked each one.

Useful for understanding which CTAs and content resonated with your audience.

## Profile

Manage your customer profile, view usage limits, and rotate API keys.
Start here to understand your account settings and available resources.


### Get customer profile

 - [GET /api/v1/customer/profile](https://developers.mailerlogic.com/customer-api.openapi/profile/paths/~1api~1v1~1customer~1profile/get.md): Retrieve your account profile including:
- Current usage and remaining quota
- Domain limits and tracking settings
- API key (masked for security)

Use this to:
- Monitor monthly email usage
- Check available resources
- Verify account status

### Update customer profile

 - [PUT /api/v1/customer/profile](https://developers.mailerlogic.com/customer-api.openapi/profile/paths/~1api~1v1~1customer~1profile/put.md): Update customer profile settings.

Note: Webhook endpoints are now managed via the /api/v1/customer/webhooks endpoints.
See the Webhooks section for creating and managing multiple webhook endpoints.

### Rotate API key

 - [POST /api/v1/customer/rotate-key](https://developers.mailerlogic.com/customer-api.openapi/profile/paths/~1api~1v1~1customer~1rotate-key/post.md): Generate a new API key for the customer account. The old key will be immediately invalidated.
Important: Update all applications with the new key immediately.

## SMTP

Get SMTP credentials for sending emails directly through our mail servers.
Use these endpoints to retrieve and rotate your SMTP passwords.

## Stream Type Classification via SMTP

When sending via SMTP, you can specify the stream type using the `X-Stream-Type` header:

```
X-Stream-Type: transactional
```

**Available values:**
- `transactional` - Password resets, order confirmations, 2FA codes, receipts
- `broadcast` - Newsletters, marketing campaigns, bulk announcements
- `shared` - General purpose (default if not specified)

### Automatic Bulk Detection & Campaign Tracking

**Important:** SMTP traffic declared as `broadcast` or auto-detected as bulk receives automatic campaign-level protections:

- **Campaign Session Creation**: Broadcast emails are grouped into campaign sessions for performance monitoring
- **Bounce Rate Monitoring**: Per-campaign bounce thresholds enforced (15% overall, 10% hard bounce)
- **Auto-Pause Protection**: Campaigns automatically paused if bounce rates exceed thresholds
- **ISP-Specific Tracking**: Monitor bounce rates per ISP (Gmail, Outlook, Yahoo, etc.)

**Bulk Behavior Detection:**

If you send bulk-like traffic without declaring `X-Stream-Type: broadcast`, the system automatically detects and protects your reputation using these signals:

- Volume patterns (high email count in short time)
- Repeated subject lines (same/similar subjects to many recipients)
- Content/template similarity (same HTML sent repeatedly)
- Marketing indicators (unsubscribe headers, tracking pixels)
- Domain concentration (many emails to same domain)
- Velocity patterns (burst sending behavior)

**Enforcement Modes:**

The system operates in one of four modes:
- **Auto-Correct (Default)**: Bulk-like traffic is automatically reclassified to `broadcast` and receives campaign protections
- **Audit**: Violations logged but no enforcement applied
- **Strict**: Bulk-like traffic declared as `transactional` is rejected with clear error message
- **Permissive**: No enforcement (not recommended for production)

**Why This Matters:**

Proper stream classification protects your sender reputation. Bulk emails sent through transactional streams can damage IP reputation and reduce deliverability for important transactional emails.

### Example: PHPMailer

```php
use PHPMailer\PHPMailer\PHPMailer;

$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.mailerlogic.net';
$mail->SMTPAuth = true;
$mail->Username = 'your-email@domain.com';
$mail->Password = 'smtp_xxxxx';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;

// Specify stream type for IP routing
$mail->addCustomHeader('X-Stream-Type', 'transactional');

$mail->setFrom('from@domain.com', 'Sender Name');
$mail->addAddress('recipient@example.com');
$mail->Subject = 'Password Reset Request';
$mail->Body = 'Click here to reset your password...';

$mail->send();
```

### Example: Nodemailer

```javascript
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: 'smtp.mailerlogic.net',
  port: 587,
  secure: false,
  auth: {
    user: 'your-email@domain.com',
    pass: 'smtp_xxxxx'
  }
});

await transporter.sendMail({
  from: 'from@domain.com',
  to: 'recipient@example.com',
  subject: 'Password Reset Request',
  html: '<p>Click here to reset your password...</p>',
  headers: {
    'X-Stream-Type': 'transactional'
  }
});
```

### Example: Python (smtplib)

```python
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

msg = MIMEMultipart()
msg['From'] = 'from@domain.com'
msg['To'] = 'recipient@example.com'
msg['Subject'] = 'Password Reset Request'
msg['X-Stream-Type'] = 'transactional'

body = 'Click here to reset your password...'
msg.attach(MIMEText(body, 'plain'))

with smtplib.SMTP('smtp.mailerlogic.net', 587) as server:
    server.starttls()
    server.login('your-email@domain.com', 'smtp_xxxxx')
    server.send_message(msg)
```

**Best Practices:**

- Always declare `X-Stream-Type: broadcast` for marketing emails, newsletters, and bulk campaigns
- Use `X-Stream-Type: transactional` only for true 1:1 transactional messages
- If unsure, omit the header or use `shared` - the system will auto-detect bulk behavior
- For high-volume campaigns, consider using the Bulk Send API (`/api/v1/bulk-send`) for better performance

If `X-Stream-Type` is not provided, emails default to the `shared` stream and may be auto-classified based on behavior.


### List SMTP credentials

 - [GET /api/v1/smtp-credentials](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials/get.md): Retrieve all SMTP credentials for your account.

Each credential has its own username and password. You can create multiple credentials
for different teams, integrations, or sending domains. Restrict a credential to a
specific verified sending domain so emails sent through it can only use that domain.

The is_master credential is the primary credential and cannot be deleted.

### Create SMTP credential

 - [POST /api/v1/smtp-credentials](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials/post.md): Create a new named SMTP credential with a generated username and password.

The plain-text password is returned only once in the response. Store it securely.
It cannot be retrieved again — use the rotate endpoint to generate a new one.

Optionally restrict the credential to a specific verified sending domain. If set,
emails sent using this credential must use that domain in the From header or they
will be rejected by the SMTP server.

Hostname binding: Set smtp_hostname_id to bind this credential to a specific
custom SMTP hostname. When bound, the credential can only be used to authenticate
via that hostname. A master credential (is_master: true) can authenticate via
any hostname. See Custom SMTP Hostnames.

### Update SMTP credential

 - [PUT /api/v1/smtp-credentials/{credential_id}](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials~1%7Bcredential_id%7D/put.md): Update the name, sending domain restriction, hostname binding, or rate limits for a credential.

### Delete SMTP credential

 - [DELETE /api/v1/smtp-credentials/{credential_id}](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials~1%7Bcredential_id%7D/delete.md): Permanently delete an SMTP credential. The credential stops working immediately.

The is_master credential cannot be deleted.

### Rotate credential password

 - [POST /api/v1/smtp-credentials/{credential_id}/rotate](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials~1%7Bcredential_id%7D~1rotate/post.md): Generate a new password for a specific SMTP credential. The old password is
immediately invalidated. The new plain-text password is returned once only.

### Enable or disable a credential

 - [PATCH /api/v1/smtp-credentials/{credential_id}/status](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials~1%7Bcredential_id%7D~1status/patch.md): Enable or disable a specific SMTP credential without deleting it.

### List custom SMTP hostnames

 - [GET /api/v1/smtp-credentials/hostnames](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials~1hostnames/get.md): List all white-label SMTP hostnames configured for your account.

A custom hostname (e.g. smtp.yourdomain.com) lets your customers or integrations
connect to MailerLogic's SMTP infrastructure using your own branded domain.
Add a CNAME DNS record pointing to smtp.mailerlogic.net, then call the verify
endpoint. SSL is issued automatically after DNS verification.

Security enforcement: Credentials are validated against the hostname they connect
through. Only credentials whose smtp_hostname_id matches the connected hostname
(or master credentials) are accepted. Generate a dedicated credential for each
custom hostname via POST /api/v1/smtp-credentials with smtp_hostname_id set.

From address enforcement: If a hostname is associated with a sending_domain_id,
the From address in all emails must use that sending domain — not the hostname itself.
If no sending domain is associated (Any / not restricted), any verified domain in the
account may be used in From.

### Add custom SMTP hostname

 - [POST /api/v1/smtp-credentials/hostnames](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials~1hostnames/post.md): Register a new white-label SMTP hostname.

After registering, add a DNS CNAME record:

smtp.yourdomain.com  CNAME  smtp.mailerlogic.net

Then call POST /hostnames/{id}/verify to confirm DNS and trigger automatic SSL
certificate issuance.

You may optionally associate the hostname with a specific sending domain for
organizational purposes.

### Remove custom SMTP hostname

 - [DELETE /api/v1/smtp-credentials/hostnames/{hostname_id}](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials~1hostnames~1%7Bhostname_id%7D/delete.md)

### Verify DNS for custom SMTP hostname

 - [POST /api/v1/smtp-credentials/hostnames/{hostname_id}/verify](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials~1hostnames~1%7Bhostname_id%7D~1verify/post.md): Checks that the CNAME record for your custom hostname points to
smtp.mailerlogic.net. If verified, marks the hostname as active and triggers
automatic SSL certificate issuance via Let's Encrypt.

You must set the CNAME before calling this endpoint. DNS propagation can
take up to 24 hours, though it usually completes within minutes.

### Rotate master SMTP password (legacy)

 - [POST /api/v1/smtp-credentials/rotate](https://developers.mailerlogic.com/customer-api.openapi/smtp/paths/~1api~1v1~1smtp-credentials~1rotate/post.md): Legacy endpoint — rotates the master credential password. Prefer
POST /api/v1/smtp-credentials/{credential_id}/rotate for named credentials.

## Sending Domains

Add and verify domains for sending authenticated emails.
Configure SPF, DKIM, and DMARC records to improve deliverability.


### List all domains

 - [GET /api/v1/customer/domains](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains/get.md): Retrieve all domains registered to your account with their verification status.
Use this to check which domains are ready for sending emails.

### Add domain

 - [POST /api/v1/customer/domains](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains/post.md): Register a new domain for sending emails. This will generate DKIM keys and DNS records.
After adding, use the DNS endpoint to get records that need to be configured.

### Get required DNS records

 - [GET /api/v1/customer/domains/{id}/dns](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains~1%7Bid%7D~1dns/get.md): Get the DNS records you need to configure for this domain.
Add these TXT records to your DNS provider to verify ownership and enable email authentication (SPF, DKIM, DMARC).

### Verify domain

 - [POST /api/v1/customer/domains/{id}/verify](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains~1%7Bid%7D~1verify/post.md): Verify DNS records for the domain. This checks SPF, DKIM, DMARC, and domain verification records.

### Update domain tracking settings

 - [PATCH /api/v1/customer/domains/{id}](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains~1%7Bid%7D/patch.md): Configure per-domain tracking settings. Override global customer defaults for this specific domain.

Tracking Hierarchy (highest to lowest priority):
1. Per-email override (in send request)
2. Per-domain settings (this endpoint)
3. Customer global defaults

Settings:
- tracking_enabled - Master toggle for all tracking (NULL = use customer default)
- open_tracking_enabled - Track email opens (NULL = use customer default)
- click_tracking_enabled - Track link clicks (NULL = use customer default)
- unsubscribe_header_enabled - Include List-Unsubscribe header (NULL = use customer default)

NULL Values: Set to null to inherit from customer global settings. Set to true or false to override.

Sandbox restriction: During the initial account review period (first 14 days for
accounts without the verified tag), click_tracking_enabled cannot be set to false.
The value will be accepted but compliance link rewriting remains active regardless.
Use GET /api/v1/customer/domains/:id/tracking to check is_in_sandbox before
rendering the setting in a UI.

Use Cases:
- Disable tracking for transactional domains
- Enable tracking only for marketing domains
- Client-specific requirements
- Environment-based (test vs production)

### Delete domain

 - [DELETE /api/v1/customer/domains/{id}](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains~1%7Bid%7D/delete.md): Remove a domain from the account. This cannot be undone.

### Get domain tracking settings

 - [GET /api/v1/customer/domains/{id}/tracking](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains~1%7Bid%7D~1tracking/get.md): Retrieve the current tracking settings for a specific domain, including per-domain
overrides, resolved account defaults, and sandbox status.

Tracking value meanings:
- true — Explicitly enabled for this domain
- false — Explicitly disabled for this domain
- null — Inherits from account-level default (see account_defaults)

Sandbox state: When is_in_sandbox is true, the account is under initial
review (< 14 days old, no verified tag). Click tracking is forced active for
compliance purposes regardless of the click_tracking_enabled setting. The
sandbox_message field explains this to end users.

### Update domain tracking settings (dedicated endpoint)

 - [PATCH /api/v1/customer/domains/{id}/tracking](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains~1%7Bid%7D~1tracking/patch.md): Update per-domain tracking overrides. Set any field to null to inherit from account defaults.

Sandbox restriction: During the initial review period (is_in_sandbox: true),
click_tracking_enabled: false is silently ignored -- compliance link rewriting
remains active. Check is_in_sandbox from the GET endpoint before rendering the
toggle in a UI.

Tracking hierarchy (highest to lowest priority):
1. Per-email track_opens / track_clicks overrides
2. Per-domain settings (this endpoint)
3. Customer account global defaults

### Check domain test readiness

 - [GET /api/v1/customer/domains/test-readiness/{domain_id}](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains~1test-readiness~1%7Bdomain_id%7D/get.md): Check if a domain is ready for sending test emails and get recommendations for test mode.

Purpose:
This endpoint helps you determine the best approach for testing new domains to avoid spam filters.

Returns:
- Domain age and health score
- Historical sending statistics
- Custom tracking domain status
- Recommended test mode (basic/standard/full)
- Warnings and actionable recommendations
- Readiness checklist

Test Modes:
- Basic: Plain text only, no tracking, no links. Best for new domains  30 days.

Use Case:
Call this endpoint before displaying the test email form to show warnings and auto-configure tracking based on domain health.

### Assign tracking domain to sending domain

 - [PUT /api/v1/customer/domains/{id}/tracking-domain](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains~1%7Bid%7D~1tracking-domain/put.md): Assign a specific tracking domain to a sending domain for branded click and open tracking.

What this does:
- Explicitly assigns a tracking domain to a sending domain
- All emails from this domain will use the assigned tracking domain for links and pixels
- Overrides smart matching behavior
- Requires the tracking domain to be verified

Use Cases:
- Brand consistency: Use different tracking domains for different brands
- Client-specific: Assign dedicated tracking domains per client
- Environment separation: Different tracking for test vs production

Requirements:
- Tracking domain must be verified (is_verified = true)
- Tracking domain must belong to your account
- SSL certificate is automatically provisioned after verification

Smart Matching Fallback:
To clear an assignment and use smart matching (automatic best match), set tracking_domain_id to null.

### Get tracking domain assignment

 - [GET /api/v1/customer/domains/{id}/tracking-domain](https://developers.mailerlogic.com/customer-api.openapi/sending-domains/paths/~1api~1v1~1customer~1domains~1%7Bid%7D~1tracking-domain/get.md): Get the current tracking domain assignment for a sending domain.

Response Details:
- Shows currently assigned tracking domain (if any)
- Includes verification status
- Indicates assignment type (explicit or smart_matching)

Assignment Types:
- explicit: Tracking domain was manually assigned via PUT endpoint
- smart_matching: No explicit assignment; system uses smart matching to find best tracking domain

## Tracking Domains

Manage custom tracking domains for branded click and open tracking.
Tracking domains allow you to use your own domain (e.g., track.yourdomain.com) instead of the default mailerlogic.net domain for tracking links and pixels.

**Setup workflow:**
1. Create tracking domain
2. Add CNAME record to DNS
3. Verify DNS configuration
4. SSL automatically provisions (1-2 minutes)
5. Assign to sending domains


### Create tracking domain

 - [POST /api/v1/customer/tracking-domains](https://developers.mailerlogic.com/customer-api.openapi/tracking-domains/paths/~1api~1v1~1customer~1tracking-domains/post.md): Create a new tracking domain for your account. Tracking domains allow you to brand your click and open tracking links with your own domain instead of the default mailerlogic.net domain.

What are tracking domains?

Tracking domains are custom domains used for:
- Click tracking URLs (when recipients click links in your emails)
- Open tracking pixels (when recipients open your emails)

Benefits:
- Professional appearance (e.g., track.yourbrand.com instead of track.mailerlogic.net)
- Improved deliverability (ISPs recognize your brand)
- Better email client compatibility

Setup Process:
1. Create the tracking domain via this API
2. Add the CNAME record to your DNS (returned in response)
3. Wait 5-30 minutes for DNS propagation
4. Verify the tracking domain (POST /api/v1/customer/tracking-domains/:id/verify)
5. SSL certificate is automatically provisioned after verification
6. Assign tracking domain to your sending domains (PATCH /api/v1/customer/domains/:id)

### List tracking domains

 - [GET /api/v1/customer/tracking-domains](https://developers.mailerlogic.com/customer-api.openapi/tracking-domains/paths/~1api~1v1~1customer~1tracking-domains/get.md): Retrieve all tracking domains for your account.

Returns a list of all tracking domains with their verification and SSL status.

### Get tracking domain

 - [GET /api/v1/customer/tracking-domains/{id}](https://developers.mailerlogic.com/customer-api.openapi/tracking-domains/paths/~1api~1v1~1customer~1tracking-domains~1%7Bid%7D/get.md): Retrieve details for a specific tracking domain including DNS setup instructions.

### Update tracking domain

 - [PATCH /api/v1/customer/tracking-domains/{id}](https://developers.mailerlogic.com/customer-api.openapi/tracking-domains/paths/~1api~1v1~1customer~1tracking-domains~1%7Bid%7D/patch.md): Update the domain name for a tracking domain. This will reset verification and SSL status.

Note: Changing the domain name will require re-verification and SSL re-provisioning.

### Delete tracking domain

 - [DELETE /api/v1/customer/tracking-domains/{id}](https://developers.mailerlogic.com/customer-api.openapi/tracking-domains/paths/~1api~1v1~1customer~1tracking-domains~1%7Bid%7D/delete.md): Delete a tracking domain from your account.

Important: You cannot delete a tracking domain that is currently assigned to any sending domains. Remove it from all sending domains first.

### Verify tracking domain DNS

 - [POST /api/v1/customer/tracking-domains/{id}/verify](https://developers.mailerlogic.com/customer-api.openapi/tracking-domains/paths/~1api~1v1~1customer~1tracking-domains~1%7Bid%7D~1verify/post.md): Verify that the CNAME record has been correctly configured for the tracking domain.

Verification Process:
1. Checks that the CNAME record points to the correct target
2. If verified, automatically triggers SSL certificate generation
3. SSL provisioning takes 1-2 minutes after verification

After Verification:
- SSL certificate is automatically provisioned via Let's Encrypt
- You can check SSL status using GET /api/v1/customer/tracking-domains/:id/ssl
- The tracking domain becomes ready to use once SSL is active

Troubleshooting:
- DNS propagation can take 5-30 minutes
- Use dig CNAME track.yourdomain.com to check DNS status
- Ensure CNAME points exactly to the target provided

### Check SSL certificate status

 - [GET /api/v1/customer/tracking-domains/{id}/ssl](https://developers.mailerlogic.com/customer-api.openapi/tracking-domains/paths/~1api~1v1~1customer~1tracking-domains~1%7Bid%7D~1ssl/get.md): Check the SSL certificate provisioning status for a tracking domain.

SSL Certificate Lifecycle:
1. unavailable: Domain not yet verified
2. provisioning: Certificate being generated (1-2 minutes after verification)
3. active: Certificate issued and working

Certificate Details:
- Issued by Let's Encrypt
- Automatically renewed before expiration
- 90-day validity with auto-renewal at 60 days

### Provision SSL certificate

 - [POST /api/v1/customer/tracking-domains/{id}/ssl](https://developers.mailerlogic.com/customer-api.openapi/tracking-domains/paths/~1api~1v1~1customer~1tracking-domains~1%7Bid%7D~1ssl/post.md): Manually trigger SSL certificate provisioning for a verified tracking domain.

When to use this:
- SSL was not automatically provisioned after verification
- You want to force certificate regeneration
- Previous SSL provisioning failed

Note: SSL is automatically provisioned after verification in most cases, so you typically don't need to call this endpoint.

Process:
- Request returns immediately with 202 Accepted
- Certificate generation happens in background (30-60 seconds)
- Check status with GET /api/v1/customer/tracking-domains/:id/ssl

## Statistics

Access detailed email delivery and engagement metrics.
Query sends, bounces, opens, clicks, and spam complaints with flexible date filters.


### Get usage statistics

 - [GET /api/v1/customer/usage](https://developers.mailerlogic.com/customer-api.openapi/statistics/paths/~1api~1v1~1customer~1usage/get.md): Retrieve current month's email usage and delivery statistics.

Optionally filter by domain_id to get statistics for a specific sending domain.

### Get outbound statistics overview

 - [GET /api/v1/stats/outbound](https://developers.mailerlogic.com/customer-api.openapi/statistics/paths/~1api~1v1~1stats~1outbound/get.md): Overview of all outbound email statistics with optional date filtering.

Domain Filtering - Use the domain_id parameter to get statistics for a specific sending domain only.

Confidence-Based Scanner Detection - Use the filter parameter to exclude bot/scanner engagement and get accurate human-only metrics.

The system now uses a confidence score (0-100) to classify engagement:
- scanner (>= 80): Known email security systems and bots
- suspicious (50-79): Edge cases that may be automated
- human (< 50): Real user engagement

Gmail and Outlook Web clicks are correctly classified as "human" since these clients strip referrer headers for privacy but show other human signals (residential IP, real browser UA, normal timing).

### Get send statistics

 - [GET /api/v1/stats/outbound/sends](https://developers.mailerlogic.com/customer-api.openapi/statistics/paths/~1api~1v1~1stats~1outbound~1sends/get.md): Daily or hourly breakdown of emails sent with optional filtering.

Use domain_id to filter statistics for a specific sending domain.
Use precision to control time granularity (day or hour).

### Get delivery statistics

 - [GET /api/v1/stats/outbound/delivered](https://developers.mailerlogic.com/customer-api.openapi/statistics/paths/~1api~1v1~1stats~1outbound~1delivered/get.md): Daily or hourly breakdown of successfully delivered emails with optional filtering.

Shows emails that were accepted by the recipient's mail server.
Use domain_id to filter statistics for a specific sending domain.
Use precision to control time granularity (day or hour).

### Get bounce statistics

 - [GET /api/v1/stats/outbound/bounces](https://developers.mailerlogic.com/customer-api.openapi/statistics/paths/~1api~1v1~1stats~1outbound~1bounces/get.md): Daily or hourly breakdown of bounced emails with hard/soft bounce classification.

Use domain_id to filter statistics for a specific sending domain.
Use precision to control time granularity (day or hour).

### Get spam complaint statistics

 - [GET /api/v1/stats/outbound/spam](https://developers.mailerlogic.com/customer-api.openapi/statistics/paths/~1api~1v1~1stats~1outbound~1spam/get.md): Daily or hourly breakdown of spam complaints.

Use domain_id to filter statistics for a specific sending domain.
Use precision to control time granularity (day or hour).

### Get open statistics

 - [GET /api/v1/stats/outbound/opens](https://developers.mailerlogic.com/customer-api.openapi/statistics/paths/~1api~1v1~1stats~1outbound~1opens/get.md): Daily or hourly breakdown of email opens (total and unique).

Domain Filtering - Use domain_id to filter statistics for a specific sending domain.

Confidence-Based Scanner Detection - Use filter=human_only to exclude Gmail/Apple Mail privacy protection opens and security scanner bots for accurate engagement metrics.

Opens are classified using confidence scoring:
- human (= 80): Known security scanners, bots, automated systems

Use precision to control time granularity (day or hour).

### Get platform statistics

 - [GET /api/v1/stats/outbound/opens/platforms](https://developers.mailerlogic.com/customer-api.openapi/statistics/paths/~1api~1v1~1stats~1outbound~1opens~1platforms/get.md): Breakdown of email opens by email client platform (Gmail, Outlook, Apple Mail, etc.).

Use domain_id to filter statistics for a specific sending domain.

### Get click statistics

 - [GET /api/v1/stats/outbound/clicks](https://developers.mailerlogic.com/customer-api.openapi/statistics/paths/~1api~1v1~1stats~1outbound~1clicks/get.md): Daily or hourly breakdown of link clicks (total and unique).

Domain Filtering - Use domain_id to filter statistics for a specific sending domain.

Confidence-Based Scanner Detection - Use filter=human_only to exclude security scanner clicks for accurate click-through rates.

Clicks are classified with high accuracy:
- human (= 80): Proofpoint, Barracuda, Mimecast, curl, automated tools

Gmail and Outlook Web users clicking links are correctly identified as "human" even though these clients strip the Referer header.

Use precision to control time granularity (day or hour).

## Content Scoring

Analyze email content for spam patterns before sending.
Get actionable feedback to improve deliverability scores.


### Analyze email content

 - [POST /api/v1/content-score](https://developers.mailerlogic.com/customer-api.openapi/content-scoring/paths/~1api~1v1~1content-score/post.md): Test your email content for spam triggers before sending.
Get a deliverability score (0-100, higher is better) with specific issues and suggestions for improvement.

Use this to:
- Check emails before sending campaigns
- Improve inbox placement rates
- Identify problematic content patterns

Rate Limit: Subject to monthly quota (default: 1000 checks/month)

## Email Validation

Enterprise email validation API to reduce bounce rates and protect sender reputation.
Real-time validation with syntax checking, domain verification, comprehensive disposable email detection, and MX record validation.
Built-in intelligence to identify role accounts and suggest corrections for common typos.


### Validate email address

 - [POST /api/v1/address/validate](https://developers.mailerlogic.com/customer-api.openapi/email-validation/paths/~1api~1v1~1address~1validate/post.md): Validate a single email address for deliverability before sending.

Comprehensive validation checks:
- Syntax validation (RFC 5322 compliant)
- Domain existence verification (DNS lookup)
- MX record validation
- Advanced disposable email detection with continuously updated database
- Role account detection (support@, admin@, etc.)
- SMTP mailbox probe — connects to the receiving mail server and issues an RCPT TO command to confirm the individual mailbox exists (without sending a message)
- Catch-all domain detection — identifies domains that accept all addresses regardless of whether the specific mailbox exists

Business benefits:
- Reduce bounce rates by 60-80%
- Protect your sender reputation score
- Block temporary and disposable email addresses
- Detect non-existent mailboxes even when the domain looks valid
- Identify catch-all domains that can inflate your list with unknown addresses
- Identify role accounts to improve engagement
- Real-time validation with instant results

Enterprise reliability with 99.9% uptime SLA and global infrastructure.

Rate Limit: Consumes from your monthly validation quota (check /api/v1/address/validate/quota)

### Validate multiple emails

 - [POST /api/v1/address/validate/batch](https://developers.mailerlogic.com/customer-api.openapi/email-validation/paths/~1api~1v1~1address~1validate~1batch/post.md): Validate up to 100 email addresses in a single request.
Each email is validated independently with full results returned, including the full intelligence layer.

Batch processing:
- Maximum 100 emails per request
- Each email validated independently
- Consumes 1 validation credit per email
- Returns individual results for each email
- All results include confidence_score, confidence_label, mx_provider, and email_pattern

Use this for:
- List cleaning before campaigns
- Bulk validation of imported contacts
- Pre-send validation of subscriber lists
- Prioritising sends by confidence level (send to very_high first)

Rate Limit: Consumes from your monthly validation quota (check /api/v1/address/validate/quota)

### Get validation quota

 - [GET /api/v1/address/validate/quota](https://developers.mailerlogic.com/customer-api.openapi/email-validation/paths/~1api~1v1~1address~1validate~1quota/get.md): Check your email validation quota usage and limits.

Quota information:
- Monthly validation limit
- Current usage
- Remaining validations
- Reset date

Use this to:
- Monitor validation usage
- Plan batch validation operations
- Track quota consumption

## Risk Assessment

Pre-send risk assessment API for Professional and Enterprise plans.
Preview risk scores before sending emails to reduce bounce rates, improve deliverability, and maintain sender reputation.
Get detailed risk analysis with actionable recommendations and enforcement policy insights.


### Preview risk score before sending (advisory)

 - [POST /api/v1/risk/preview](https://developers.mailerlogic.com/customer-api.openapi/risk-assessment/paths/~1api~1v1~1risk~1preview/post.md): Pre-send guidance to help you decide whether to send an email.

Returns a risk assessment with a would_block boolean that indicates whether the platform will block this email if you attempt to send it.

Important Contract:
- This is advisory - you make the decision
- If would_block = true, calling /api/v1/send will also block for the same reason
- If would_block = false but risk is medium/high, you can still choose to send
- Platform may throttle/warn on high risk sends depending on your plan

Risk Score Ranges:
- 0-29: Safe (send)
- 30-49: Low risk (warn)
- 50-69: Medium risk (soft block - customer can override)
- 70-100: High/Critical risk (hard block)

Hard Blocks (would_block = true):
- Known spamtraps (spamtrap_detected)
- Previous spam complaints (previous_complaint)
- High-confidence disposable domains > 0.85 (disposable_high_confidence)
- Sender verification failure if enabled (sender_not_verified)
- Risk score >= 70 (risk_score_critical)

Stable Reason Codes (for programmatic handling):
- disposable_high_confidence - Disposable domain with 90%+ confidence
- disposable_medium_confidence - Disposable domain with 50-89% confidence
- sender_not_verified - DKIM/SPF not verified
- spamtrap_detected - Known spamtrap address
- previous_complaint - Recipient marked previous email as spam
- previous_hard_bounce - Hard bounce on previous send
- content_risk_high - High spam content score
- velocity_first_send_bulk - First send attempt is bulk email
- volume_spike - Unusual sending volume increase

Quota:
- Available on Professional and Enterprise plans
- Check /api/v1/risk/stats for usage and remaining quota

### Get risk API usage and analytics

 - [GET /api/v1/risk/stats](https://developers.mailerlogic.com/customer-api.openapi/risk-assessment/paths/~1api~1v1~1risk~1stats/get.md): Retrieve usage statistics, trends, and risk analytics for the Risk Score API.

Information provided:
- Current quota (used/limit/remaining/reset_at)
- Top risk factors detected in your previews
- Average risk score across all previews
- Breakdown of risk categories (recipient/content/sender/behavior)
- Block rate statistics

Use this to:
- Monitor API quota consumption
- Understand common risk patterns in your sends
- Identify areas for improvement (e.g., "30% of risk from unverified senders")
- Plan list cleaning or content optimization strategies

## Events

Query email lifecycle events with human engagement detection and device analytics.

## Features
- ✅ Real human engagement detection (`is_human_engagement`)
- ✅ Bot/scanner filtering with confidence scores (`scanner_detection`)
- ✅ Device and browser analytics (`device_info`)
- ✅ Complete event timeline with summary statistics
- ✅ Advanced filtering and pagination

## Data Retention
Event data is retained based on your pricing plan:
- **Free Plan**: 3 days
- **Starter Plan**: 7 days
- **Growth Plan**: 30 days
- **Professional Plan**: 90 days
- **Enterprise Plan**: 365 days

Only events within your plan's retention period are accessible via this API.
Upgrade your plan to access longer retention periods and historical data.


### Query email events

 - [GET /api/v1/events](https://developers.mailerlogic.com/customer-api.openapi/events/paths/~1api~1v1~1events/get.md): Query email events with advanced filtering and human engagement detection.

This endpoint provides:
- Real human engagement detection (is_human_engagement)
- Bot/scanner filtering (scanner_detection)
- Device and browser analytics (device_info)
- Complete event timeline with stats

Data Retention:
Events are retained based on your plan's data retention policy:
- Free: 3 days
- Starter: 7 days
- Growth: 30 days
- Professional: 90 days
- Enterprise: 365 days

Tip: Upgrade to a higher plan for longer retention and access to historical event data.

### Get events for specific email

 - [GET /api/v1/emails/{email_id}/events](https://developers.mailerlogic.com/customer-api.openapi/events/paths/~1api~1v1~1emails~1%7Bemail_id%7D~1events/get.md): Retrieve complete event timeline for a specific email.

This endpoint provides:
- Chronological event timeline
- Event summary statistics (summary object)
- Human engagement detection for each event
- Device and browser analytics

Data Retention:
Events are only available within your plan's retention period:
- Free: 3 days
- Starter: 7 days
- Growth: 30 days
- Professional: 90 days
- Enterprise: 365 days

## Bounces

View detailed bounce event history with SMTP diagnostic codes and error messages.

**What's the Difference?**
- **Bounces**: Complete historical log of every bounce event with diagnostic details
- **Suppressions**: Current list of blocked addresses (includes bounces, complaints, manual blocks)
- **Unsubscribes**: User preference opt-outs

**Bounce Types:**
- **Hard Bounce**: Permanent delivery failure (invalid address, domain doesn't exist)
- **Soft Bounce**: Temporary failure (mailbox full, server down)
- **Complaint**: Recipient marked email as spam
- **Block**: Recipient's server blocked delivery (reputation, content filters)

**Use Cases:**
- View why a specific email bounced (SMTP diagnostic codes)
- Analyze bounce rate trends over time
- Debug delivery issues with detailed error messages
- Audit trail for compliance
- Track bounce patterns for a recipient

**SMTP Diagnostic Codes:**
- `550 5.1.1` - User unknown / Mailbox doesn't exist
- `552 5.2.2` - Mailbox full
- `553 5.3.0` - Domain doesn't exist
- `554 5.7.1` - Blocked by recipient server

**Automatic Actions:**
- Hard bounces are automatically added to suppressions
- Soft bounces are tracked; repeated soft bounces become suppressions
- All bounce events are logged for analytics

Unlike suppressions (which show only currently blocked addresses), the bounces endpoint
provides complete diagnostic information for every bounce that occurred.


### List bounce events

 - [GET /api/customer/bounces](https://developers.mailerlogic.com/customer-api.openapi/bounces/paths/~1api~1customer~1bounces/get.md): Get detailed bounce event history with SMTP diagnostic codes and error messages.

Bounces vs Suppressions:
- Bounces endpoint: Shows complete history of ALL bounce events with diagnostic details
- Suppressions endpoint: Shows currently blocked addresses (no diagnostic codes)

Use this to:
- View exact SMTP error codes (550 5.1.1, 452 4.2.2, etc.)
- Analyze bounce rate trends over time
- Debug delivery issues with detailed error messages
- Track bounce patterns for specific recipients
- Generate bounce analytics and reports

Bounce Types:
- hard: Permanent delivery failure (invalid address, domain doesn't exist)
- soft: Temporary failure (mailbox full, server down)
- complaint: Recipient marked email as spam
- block: Recipient's server blocked delivery

Common SMTP Status Codes:
- 550 5.1.1 - User unknown / Mailbox doesn't exist
- 552 5.2.2 - Mailbox full
- 553 5.3.0 - Domain doesn't exist
- 554 5.7.1 - Blocked by recipient server
- 452 4.2.2 - Mailbox full (temporary)

All hard bounces are automatically added to your suppressions list.

## Suppressions

Manage system-level suppressions for bounces and spam complaints.

**Suppression Types:**
- **Hard Bounces**: Permanent delivery failures (automatically added by the system)
- **Soft Bounces**: Temporary delivery failures (automatically added after threshold)
- **Complaints**: Spam complaints and feedback loop reports

**Suppression Scope:**
- **Global**: Applies to ALL your domains (when no `domain_id` specified)
- **Domain-specific**: Applies to a specific domain only

**Key Features:**
- Automatic bounce and complaint handling
- Whitelist management to override suppressions
- List all suppressions with filtering
- Manual suppression management

Automated list hygiene to protect your sender reputation and ensure compliance.


### List all suppressions

 - [GET /api/customer/suppressions](https://developers.mailerlogic.com/customer-api.openapi/suppressions/paths/~1api~1customer~1suppressions/get.md): Retrieve all system-managed suppressions (hard bounces, soft bounces, and spam complaints) with filtering capabilities.

Use this to:
- Monitor bounce and complaint trends
- Export comprehensive suppression lists
- Filter by type, domain, or date range
- Track suppression sources and reasons
- Manage whitelist overrides

Suppression Types:
- bounce: Hard and soft bounces (added automatically by the system)
- complaint: Spam complaints and feedback loop reports (added automatically)

Each suppression includes a scope field indicating whether it's global (all domains) or domain-specific.

Note: For user opt-outs and unsubscribes, see the /api/v1/customer/unsubscribes endpoints.

### Add suppression

 - [POST /api/customer/suppressions](https://developers.mailerlogic.com/customer-api.openapi/suppressions/paths/~1api~1customer~1suppressions/post.md): Manually add an email to your suppression list for bounces or spam complaints.

Suppression Scope:
- Global: Omit domain_id to suppress across ALL your domains
- Domain-specific: Include domain_id to suppress for a specific domain only

Common Use Cases:
- Manual bounce additions for known bad addresses
- Adding complaint addresses from external feedback loops
- Proactive list cleaning based on email validation results
- Importing suppressions from other platforms

Note: For managing user opt-outs, use the /api/v1/customer/unsubscribes endpoints instead.

### Remove suppression

 - [DELETE /api/customer/suppressions/{suppressionId}](https://developers.mailerlogic.com/customer-api.openapi/suppressions/paths/~1api~1customer~1suppressions~1%7Bsuppressionid%7D/delete.md): Remove an email from your suppression list by suppression ID.

Important: Only remove suppressions if:
- The recipient has explicitly requested re-subscription
- You have verified the email address is valid
- For bounces: You have confirmed the email is now deliverable
- For complaints: You have received explicit consent to resume sending

## Unsubscribes

Manage user consent and opt-out preferences.

**Adding Unsubscribe Links to Emails:**

Include the `{{unsubscribe}}` placeholder in your email HTML or text:

```html
<p><a href="{{unsubscribe}}">Unsubscribe</a></p>
```

MailerLogic automatically:
- Replaces `{{unsubscribe}}` with a unique, secure URL per recipient
- Adds RFC 8058 List-Unsubscribe headers for Gmail/Outlook one-click
- Tracks unsubscribes per domain
- Enforces unsubscribe preferences on future sends

**User-Initiated Opt-Outs:**
- Unsubscribe link clicks in emails (via `{{unsubscribe}}`)
- One-click unsubscribe in email clients (Gmail, Outlook)
- API-based unsubscribe requests
- Domain-specific or global unsubscribe preferences

**Unsubscribe Scope:**
- **Global**: User opts out from ALL your domains
- **Domain-specific**: User opts out from a specific domain only

**Key Features:**
- Add emails to unsubscribe list
- Remove (re-subscribe) emails
- List all unsubscribed emails with filtering
- Automatic enforcement during email sending

Ensures compliance with CAN-SPAM, GDPR, and other anti-spam regulations.


### List unsubscribes

 - [GET /api/customer/unsubscribes](https://developers.mailerlogic.com/customer-api.openapi/unsubscribes/paths/~1api~1customer~1unsubscribes/get.md): Retrieve your unsubscribe list with filtering and search capabilities.

Use this to:
- Monitor user opt-out trends
- Export unsubscribe lists for compliance
- Audit unsubscribe sources (API, link clicks, manual)
- Filter by domain or view all unsubscribes
- Track consent management across your domains

Complete unsubscribe lifecycle management with comprehensive analytics and compliance reporting.

Each unsubscribe includes a scope field indicating whether it's global (all domains) or domain-specific.

Note: For system-managed suppressions (bounces, complaints), see the /api/v1/customer/suppressions endpoints.

### Add to unsubscribe list

 - [POST /api/customer/unsubscribes](https://developers.mailerlogic.com/customer-api.openapi/unsubscribes/paths/~1api~1customer~1unsubscribes/post.md): Add an email address to your unsubscribe list for user consent management.

Unsubscribe Scope:
- Global: Omit domain_id to unsubscribe from ALL your domains
- Domain-specific: Include domain_id to unsubscribe from a specific domain only

Use cases:
- Processing manual unsubscribe requests (phone, email, support tickets)
- Honoring opt-out preferences from other channels
- Importing unsubscribe lists from other platforms
- Domain-specific opt-outs for users who want targeted unsubscribes
- Proactive consent management

Note: Unsubscribe links in emails are handled automatically. Use this endpoint for opt-outs from other channels.

### Re-subscribe email

 - [DELETE /api/customer/unsubscribes/{email}](https://developers.mailerlogic.com/customer-api.openapi/unsubscribes/paths/~1api~1customer~1unsubscribes~1%7Bemail%7D/delete.md): Remove an email from your unsubscribe list, allowing them to receive emails again.

Re-subscribe Scope:
- Global: Omit domain_id query param to remove from global unsubscribe list
- Domain-specific: Include domain_id query param to remove domain-specific unsubscribe

Important: Only do this when:
- The recipient has explicitly requested to be re-subscribed
- You have documented proof of their consent
- You comply with applicable consent regulations (GDPR, CAN-SPAM, etc.)

Use cases:
- Processing re-subscription requests from users
- Honoring preference center updates
- Correcting accidental unsubscribes

## Health Score

Monitor your account's email health and engagement quality metrics.
Get a 0-100 score with reputation grade (A+ to F) and actionable insights.


### Get health score

 - [GET /api/customer/health-score](https://developers.mailerlogic.com/customer-api.openapi/health-score/paths/~1api~1customer~1health-score/get.md): Retrieve your account's email health score and engagement quality metrics.

Health Score (0-100) indicates your overall sending reputation based on:
- Delivery rate
- Engagement (opens/clicks)
- Bounce rate
- Complaint rate

Reputation Grades:
- A+ (95-100): Outstanding
- A (90-94): Excellent
- B+ (85-89): Good
- B (80-84): Above average
- C+ (75-79): Fair
- C (70-74): Below average
- D (60-69): Poor
- F (0-59): Critical

### Get health score history

 - [GET /api/customer/health-score/history](https://developers.mailerlogic.com/customer-api.openapi/health-score/paths/~1api~1customer~1health-score~1history/get.md): Retrieve historical health score data over time.
Use this to track trends and improvements in your sending reputation.

### Refresh health score

 - [POST /api/customer/health-score/refresh](https://developers.mailerlogic.com/customer-api.openapi/health-score/paths/~1api~1customer~1health-score~1refresh/post.md): Recalculate your health score with the latest data.
Health scores are automatically updated daily, but you can manually refresh when needed.

## Tracking

Public endpoints for open and click tracking.
These are called automatically by email clients - no authentication required.


### Track email open

 - [GET /track/o/{token}](https://developers.mailerlogic.com/customer-api.openapi/tracking/paths/~1track~1o~1%7Btoken%7D/get.md): Open tracking pixel endpoint. Returns a 1x1 transparent GIF.

How it works:
- When you enable track_opens: true in your email send request, MailerLogic automatically injects a tracking pixel into the HTML body
- The pixel contains a unique encrypted token specific to that email
- When the recipient opens the email, their email client loads the pixel, triggering this endpoint
- The open event is recorded and available via the Events API

Public endpoint - no authentication required. The token provides the necessary context.

### Track link click

 - [GET /track/c/{token}](https://developers.mailerlogic.com/customer-api.openapi/tracking/paths/~1track~1c~1%7Btoken%7D/get.md): Click tracking redirect endpoint. Logs the click and redirects to the original URL.

How it works:
- When you enable track_clicks: true in your email send request, MailerLogic automatically rewrites all links in your HTML
- Each link is replaced with a tracking URL containing a unique encrypted token
- When the recipient clicks a link, they are redirected through this endpoint
- The click event is recorded and the user is immediately redirected to the original destination

Public endpoint - no authentication required. The token provides the necessary context.

### Unsubscribe (manual)

 - [GET /track/u/{token}](https://developers.mailerlogic.com/customer-api.openapi/tracking/paths/~1track~1u~1%7Btoken%7D/get.md): Manual unsubscribe endpoint. Shows a confirmation page.

How it works:
- When you include an unsubscribe link in your emails, MailerLogic can automatically generate an encrypted token
- The recipient clicks the unsubscribe link in their email
- They are taken to a confirmation page where they can confirm their unsubscription

Public endpoint - no authentication required. The token provides the necessary context.

### One-click unsubscribe (RFC 8058)

 - [POST /track/u/{token}](https://developers.mailerlogic.com/customer-api.openapi/tracking/paths/~1track~1u~1%7Btoken%7D/post.md): One-click unsubscribe endpoint per RFC 8058.
Email clients can call this to instantly unsubscribe users.

How it works:
- MailerLogic automatically adds the List-Unsubscribe and List-Unsubscribe-Post headers to your emails
- Major email clients (Gmail, Yahoo, etc.) display an "Unsubscribe" button
- When clicked, the email client POSTs to this endpoint
- The user is instantly unsubscribed without visiting a webpage

Public endpoint - no authentication required. The token provides the necessary context.

## Outbound Webhooks

MailerLogic sends real-time webhook notifications to your configured endpoint for all email events.

**Webhook Scopes:**

**Customer-Level Webhooks** (domain_ids = null or [])
- Receives events from ALL domains
- Simplest setup for single-backend applications

**Single Domain Webhooks** (domain_ids = [uuid])
- Receives events from ONE specific domain
- Useful for isolated domains

**Domain Group Webhooks** (domain_ids = [uuid1, uuid2, ...])
- Receives events from MULTIPLE specific domains
- Perfect for grouping related domains when webhook endpoint limits apply
- Example: Plan has 20 domains, 5 webhook limit → group marketing domains, support domains, etc.

**Mixed Approach**
- You can combine all three types
- Domain-specific/group webhooks fire first, then customer-level
- Maximize efficiency with limited webhook endpoints

**Create customer-level webhook (all domains):**
```bash
curl -X POST https://api.mailerlogic.net/api/v1/customer/webhooks \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/mailerlogic",
    "events": ["email.delivered", "email.opened", "email.clicked", "email.bounced", "email.complained"],
    "name": "Production Webhook",
    "domain_ids": null,
    "is_active": true
  }'
```

**Create domain group webhook (multiple domains):**
```bash
curl -X POST https://api.mailerlogic.net/api/v1/customer/webhooks \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://marketing.example.com/webhook",
    "events": ["email.opened", "email.clicked"],
    "name": "Marketing Domains Group",
    "domain_ids": [
      "550e8400-e29b-41d4-a716-446655440001",
      "550e8400-e29b-41d4-a716-446655440002",
      "550e8400-e29b-41d4-a716-446655440003"
    ],
    "is_active": true
  }'
```

**Create single domain webhook:**
```bash
curl -X POST https://api.mailerlogic.net/api/v1/customer/webhooks \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://support.example.com/webhook",
    "events": ["email.delivered", "email.bounced"],
    "name": "Support Domain Only",
    "domain_ids": ["550e8400-e29b-41d4-a716-446655440000"],
    "is_active": true
  }'
```

**All webhook events include:**
- `event` - Event type (e.g., "email.delivered", "email.opened")
- `timestamp` - ISO 8601 timestamp
- `email_id` - UUID of the email (except unsubscribe events)
- `tag` - Optional tag for filtering/grouping (if provided when sending)
- `metadata` - Optional custom metadata object (if provided when sending)

**Events sent to your endpoint:**

### email.delivered
Sent when email is successfully delivered to recipient's mail server.
```json
{
  "event": "email.delivered",
  "timestamp": "2025-12-27T12:34:56.789Z",
  "email_id": "550e8400-e29b-41d4-a716-446655440000",
  "to": "user@example.com",
  "from": "sender@yourdomain.com",
  "subject": "Welcome",
  "deliveredAt": "2025-12-27T12:34:56.789Z",
  "tag": "campaign-welcome",
  "metadata": {
    "campaign_id": "welcome-2025",
    "customer_segment": "new-users"
  }
}
```
**Note:** `tag` and `metadata` fields are included if provided when sending the email.

### email.opened
Sent when recipient opens email (requires open tracking enabled).
```json
{
  "event": "email.opened",
  "timestamp": "2025-12-27T12:35:23.456Z",
  "email_id": "550e8400-e29b-41d4-a716-446655440000",
  "ip_address": "203.0.113.45",
  "user_agent": "Mozilla/5.0...",
  "is_scanner": false,
  "scanner_confidence": 0,
  "browser": "Chrome",
  "os": "Windows",
  "device_type": "Desktop",
  "tag": "campaign-welcome",
  "metadata": {
    "campaign_id": "welcome-2025",
    "customer_segment": "new-users"
  }
}
```
**Notes:**
- `is_scanner` indicates if the open was detected as an automated email scanner rather than human interaction.
- `tag` and `metadata` fields are included if provided when sending the email.

### email.clicked
Sent when recipient clicks a tracked link.
```json
{
  "event": "email.clicked",
  "timestamp": "2025-12-27T12:36:15.123Z",
  "email_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://example.com/product",
  "ip_address": "203.0.113.45",
  "is_scanner": false,
  "browser": "Safari",
  "os": "iOS",
  "device_type": "Mobile",
  "tag": "campaign-welcome",
  "metadata": {
    "campaign_id": "welcome-2025",
    "customer_segment": "new-users"
  }
}
```
**Note:** `tag` and `metadata` fields are included if provided when sending the email.

### email.bounced
Sent when email bounces (hard or soft).
```json
{
  "event": "email.bounced",
  "timestamp": "2025-12-27T12:34:58.234Z",
  "email_id": "550e8400-e29b-41d4-a716-446655440000",
  "recipient": "invalid@example.com",
  "bounce_type": "hard",
  "reason": "User unknown",
  "diagnostic_code": "550 5.1.1",
  "tag": "campaign-welcome",
  "metadata": {
    "campaign_id": "welcome-2025",
    "customer_segment": "new-users"
  }
}
```
**Notes:**
- Hard bounces are automatically added to suppression list.
- `tag` and `metadata` fields are included if provided when sending the email.

### email.complained
Sent when recipient marks email as spam.
```json
{
  "event": "email.complained",
  "timestamp": "2025-12-27T12:37:42.567Z",
  "email_id": "550e8400-e29b-41d4-a716-446655440000",
  "recipient": "user@example.com",
  "complaint_type": "abuse",
  "tag": "campaign-welcome",
  "metadata": {
    "campaign_id": "welcome-2025",
    "customer_segment": "new-users"
  }
}
```
**Notes:**
- Complaints are automatically added to suppression list.
- `tag` and `metadata` fields are included if provided when sending the email.

### email.unsubscribed
Sent when recipient unsubscribes.
```json
{
  "event": "email.unsubscribed",
  "timestamp": "2025-12-27T12:38:20.890Z",
  "email": "user@example.com",
  "reason": "User clicked unsubscribe link",
  "method": "link"
}
```
Methods: `link` (clicked link) or `one-click` (RFC 8058).

### email.failed
Sent when email fails to send.
```json
{
  "event": "email.failed",
  "timestamp": "2025-12-27T12:34:57.345Z",
  "email_id": "550e8400-e29b-41d4-a716-446655440000",
  "recipient": "blocked@example.com",
  "reason": "Blocked by content filter",
  "error": "Content violated filtering rules",
  "tag": "campaign-welcome",
  "metadata": {
    "campaign_id": "welcome-2025",
    "customer_segment": "new-users"
  }
}
```
**Note:** `tag` and `metadata` fields are included if provided when sending the email.

**Webhook Best Practices:**

1. **Respond quickly** - Return 200 OK within 5 seconds
2. **Process asynchronously** - Queue webhook for processing, respond immediately
3. **Handle retries** - Webhooks retry 5 times with exponential backoff if your endpoint fails
4. **Validate payloads** - Check the `event` field and validate structure
5. **Use HTTPS** - Always use HTTPS endpoints for security

**Testing Webhooks:**

Use ngrok or webhook.site to test locally:
```bash
ngrok http 3000
# Create webhook with ngrok URL
curl -X POST https://api.mailerlogic.net/api/v1/customer/webhooks \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"url": "https://abc123.ngrok.io/webhooks", "events": ["delivered"]}'

# Send a test webhook
curl -X POST https://api.mailerlogic.net/api/v1/customer/webhooks/{WEBHOOK_ID}/test \
  -H "X-API-Key: YOUR_API_KEY"
```

**Webhook Delivery:**
- Delivery timeout: 30 seconds
- Retry attempts: 5 (with exponential backoff)
- Retry schedule: 1s, 5s, 30s, 2m, 10m

See the complete integration guide at https://docs.mailerlogic.com/webhooks


### List webhook endpoints

 - [GET /api/v1/customer/webhooks](https://developers.mailerlogic.com/customer-api.openapi/outbound-webhooks/paths/~1api~1v1~1customer~1webhooks/get.md): Retrieve all configured webhook endpoints for your account.

Tier Limits:
- Starter: 1 webhook endpoint
- Professional: 3 webhook endpoints
- Business: 10 webhook endpoints
- Custom: Configurable limit

### Create webhook endpoint

 - [POST /api/v1/customer/webhooks](https://developers.mailerlogic.com/customer-api.openapi/outbound-webhooks/paths/~1api~1v1~1customer~1webhooks/post.md): Create a new webhook endpoint to receive real-time email event notifications.

Webhook Scopes:
- Customer-Level (domain_ids = null/empty): Receives events from ALL domains
- Single Domain (domain_ids = [uuid]): Receives events from ONE domain
- Domain Group (domain_ids = [uuid1, uuid2, ...]): Receives events from MULTIPLE domains

Use Case - Plan Limits:
If your plan has 20 domains but only 5 webhook endpoints, group domains:
- Webhook 1: [marketing-domain, campaigns-domain, newsletters-domain] → marketing app
- Webhook 2: [support-domain, tickets-domain] → support app
- Webhook 3: [] (all remaining domains) → main backend

Event Types:
- email.sent - Email accepted for delivery
- email.delivered - Successfully delivered to recipient
- email.opened - Recipient opened the email
- email.clicked - Recipient clicked a link
- email.bounced - Email bounced
- email.complained - Spam complaint received
- email.unsubscribed - Recipient unsubscribed
- email.failed - Delivery failed

Examples:

Customer-level webhook (all domains):
json
{
  "url": "https://api.example.com/webhook",
  "events": ["email.delivered", "email.bounced"],
  "domain_ids": null
}


Domain group webhook (multiple domains):
json
{
  "url": "https://marketing.example.com/webhook",
  "events": ["email.opened", "email.clicked"],
  "domain_ids": [
    "550e8400-e29b-41d4-a716-446655440001",
    "550e8400-e29b-41d4-a716-446655440002",
    "550e8400-e29b-41d4-a716-446655440003"
  ]
}


Single domain webhook (backward compatible):
json
{
  "url": "https://support.example.com/webhook",
  "events": ["email.delivered"],
  "domain_ids": ["550e8400-e29b-41d4-a716-446655440000"]
}

### Update webhook endpoint

 - [PUT /api/v1/customer/webhooks/{webhookId}](https://developers.mailerlogic.com/customer-api.openapi/outbound-webhooks/paths/~1api~1v1~1customer~1webhooks~1%7Bwebhookid%7D/put.md): Update an existing webhook endpoint configuration.

You can change webhook scope by updating domain_ids:
- Set to null or []: Change to customer-level (all domains)
- Set to [uuid]: Change to single domain
- Set to [uuid1, uuid2, ...]: Change to domain group (multiple domains)

### Delete webhook endpoint

 - [DELETE /api/v1/customer/webhooks/{webhookId}](https://developers.mailerlogic.com/customer-api.openapi/outbound-webhooks/paths/~1api~1v1~1customer~1webhooks~1%7Bwebhookid%7D/delete.md): Remove a webhook endpoint from your account.

### Test webhook endpoint

 - [POST /api/v1/customer/webhooks/{webhookId}/test](https://developers.mailerlogic.com/customer-api.openapi/outbound-webhooks/paths/~1api~1v1~1customer~1webhooks~1%7Bwebhookid%7D~1test/post.md): Send a test event to verify webhook delivery.

Test Event Format:
json
{
  "event": "test",
  "timestamp": "2026-01-18T12:34:56Z",
  "customer_id": "uuid",
  "message": "Test webhook from MailerLogic"
}


The webhook will include an X-Webhook-Signature header for verification.

### Regenerate webhook secret

 - [POST /api/v1/customer/webhooks/{webhookId}/regenerate-secret](https://developers.mailerlogic.com/customer-api.openapi/outbound-webhooks/paths/~1api~1v1~1customer~1webhooks~1%7Bwebhookid%7D~1regenerate-secret/post.md): Generate a new HMAC-SHA256 secret for webhook signature verification.
The old secret will be immediately invalidated.

## Contacts

Complete contact management system for organizing your subscribers.

**Features:**
- Create, update, and delete contacts
- Search and filter contacts by status, source, tags
- Track engagement metrics (opens, clicks, bounces)
- Custom fields for flexible metadata
- Bulk import from CSV
- Source tracking (API, import, form, manual)

**Common Use Cases:**
- Build email lists programmatically
- Import existing subscriber lists
- Track contact lifecycle and engagement
- Segment contacts for targeted campaigns


### List contacts

 - [GET /api/v1/contacts](https://developers.mailerlogic.com/customer-api.openapi/contacts/paths/~1api~1v1~1contacts/get.md): Retrieve a paginated list of contacts for your account with filtering and search capabilities.

Features:
- Paginated results (up to 1000 per page)
- Filter by status (active, unsubscribed, bounced, complained)
- Search by email or name
- Filter by tag
- Sort by multiple fields
- Returns tags array for each contact

### Create a contact

 - [POST /api/v1/contacts](https://developers.mailerlogic.com/customer-api.openapi/contacts/paths/~1api~1v1~1contacts/post.md): Create a new contact in your account. You can include tags, custom properties, and all contact fields.

Fields:
- Email (required) - unique per customer
- Name fields - first_name/last_name or combined name
- Contact info - phone, city, country
- Custom properties - unlimited flexible fields
- Tags - categorize your contacts

Note: Email must be unique. Returns 409 if email already exists.

### Bulk import contacts

 - [POST /api/v1/contacts/import](https://developers.mailerlogic.com/customer-api.openapi/contacts/paths/~1api~1v1~1contacts~1import/post.md): Import multiple contacts at once. Supports up to 10,000 contacts per request.

Features:
- Bulk import up to 10,000 contacts per request
- Choose conflict resolution strategy (skip or update)
- Support for all contact fields including custom properties
- Tags are automatically parsed and created
- Returns detailed results (created, updated, skipped, errors)
- Email validation included
- Transaction-based for data integrity

Use Cases:
- CSV import (after client-side parsing)
- Migration from other platforms
- Batch contact creation
- Syncing contacts from external systems

Best Practices:
- Always validate emails before sending
- Use batches of 1,000 for optimal performance
- Set on_conflict: "update" to overwrite existing contacts
- Set on_conflict: "skip" to preserve existing data (default)

### Get a contact

 - [GET /api/v1/contacts/{id}](https://developers.mailerlogic.com/customer-api.openapi/contacts/paths/~1api~1v1~1contacts~1%7Bid%7D/get.md): Get detailed information about a specific contact including tags, segments, and engagement metrics.

Returns all contact data plus the intelligent engagement score for easy segmentation and targeting.

### Update a contact

 - [PUT /api/v1/contacts/{id}](https://developers.mailerlogic.com/customer-api.openapi/contacts/paths/~1api~1v1~1contacts~1%7Bid%7D/put.md): Update contact information including email address.

Email updates:
- Validates email format
- Checks for duplicates within your account
- Returns 409 if email already exists

Note: To update tags, use the dedicated tag endpoints.

### Delete a contact

 - [DELETE /api/v1/contacts/{id}](https://developers.mailerlogic.com/customer-api.openapi/contacts/paths/~1api~1v1~1contacts~1%7Bid%7D/delete.md): Permanently delete a contact from your account.

### Get email history for a contact

 - [GET /api/v1/contacts/{id}/emails](https://developers.mailerlogic.com/customer-api.openapi/contacts/paths/~1api~1v1~1contacts~1%7Bid%7D~1emails/get.md): Retrieve all emails sent to a specific contact with engagement metrics.

Response includes:
- Email subject, status, timestamps
- Open/click counts
- Bounce and complaint information
- Event timeline (for recent emails)

Use cases:
- Display contact activity timeline
- Show email engagement history
- Track email deliverability per contact
- Debug delivery issues

## Segments

Dynamic and static audience segmentation for targeted campaigns.

**Features:**
- Dynamic segments with auto-updating filters
- Static segments with manual membership
- Filter by engagement, status, source, tags
- Preview segment size before saving
- Refresh dynamic segments on-demand

**Filter Options:**
- Status (active, unsubscribed, bounced)
- Source (api, import, form, manual)
- Engagement metrics (opens, clicks, sent count)
- Tags (AND/OR logic)
- Custom field values

**Example Segments:**
- Highly engaged subscribers (>10 opens)
- Recent form signups (source=form, created <30 days)
- At-risk contacts (sent >5, opened 0)
- VIP customers (tags contain "premium")


### List segments

 - [GET /api/v1/contacts/segments](https://developers.mailerlogic.com/customer-api.openapi/segments/paths/~1api~1v1~1contacts~1segments/get.md): Retrieve all segments (both static and dynamic) for your account.

Response includes:
- Segment name, description, type (static/dynamic)
- Filter conditions for dynamic segments
- Contact count (actual membership count)
- Created/updated timestamps

### Create a segment

 - [POST /api/v1/contacts/segments](https://developers.mailerlogic.com/customer-api.openapi/segments/paths/~1api~1v1~1contacts~1segments/post.md): Create a new segment (static or dynamic).

Dynamic Segments:
- Auto-update based on filter conditions
- Contacts added/removed automatically as they match/unmatch filters
- Refresh on-demand or via cron

Static Segments:
- Manual membership control
- Contacts must be explicitly added/removed
- Useful for one-time campaigns or curated lists

Available Filters:

System Fields:
- status - Contact subscription status
  - Operators: equals, not_equals
  - Values: subscribed, unsubscribed, bounced, complained

- source - How contact was added
  - Operators: equals, not_equals, contains, not_contains, starts_with, ends_with, is_empty, has_value
  - Values: api, import, form, manual, or any custom source

Contact Info Fields:
- first_name, last_name, phone, city, country
  - Operators: equals, not_equals, contains, not_contains, starts_with, not_starts_with, ends_with, not_ends_with, is_empty, has_value
  - Values: Any text string

Tag Filters:
- tags - Contact has any of these tags
  - Operators: in, contains, starts_with
  - Values: Array of tag names ["tag1", "tag2"]

- tags_has_all - Contact has ALL of these tags
  - Operator: has_all
  - Values: Array of tag names ["tag1", "tag2"]

- tags_not - Contact does NOT have any of these tags
  - Operator: not_in
  - Values: Array of tag names ["tag1", "tag2"]

Campaign Engagement:
- campaign_opened - Campaign open tracking
  - Operators: has_opened, has_not_opened, at_least, exactly, more_than, less_than, at_most, never
  - Value: Campaign ID (UUID) or count number
  - Additional filters: campaign_ids (array), time_period_days, exclude_scanner (boolean)

- campaign_clicked - Campaign click tracking
  - Operators: has_clicked, has_not_clicked, at_least, exactly, more_than, less_than, at_most, never
  - Value: Campaign ID (UUID) or count number
  - Additional filters: campaign_ids (array), time_period_days, link_url, exclude_scanner (boolean)

- campaign_sent - Campaign delivery tracking
  - Operators: has_received, has_not_received, was_sent, was_not_sent
  - Value: Campaign ID (UUID)
  - Additional filters: campaign_ids (array), time_period_days

Custom Properties:
- custom_properties. - Filter by any custom property
  - Text operators: equals, not_equals, contains, not_contains, starts_with, not_starts_with, ends_with, not_ends_with, is_empty, has_value, exists, not_exists
  - Numeric operators: >, >=, =",
      "value": 100
    }
  ],
  "match_type": "all"
}
`

Match Types:
- all (AND) - Contact must match ALL filters
- any` (OR) - Contact must match ANY filter

### Get segment details

 - [GET /api/v1/contacts/segments/{id}](https://developers.mailerlogic.com/customer-api.openapi/segments/paths/~1api~1v1~1contacts~1segments~1%7Bid%7D/get.md): Get detailed information about a specific segment.

Optional: Include contacts list with include_contacts=true query parameter.

### Update segment

 - [PUT /api/v1/contacts/segments/{id}](https://developers.mailerlogic.com/customer-api.openapi/segments/paths/~1api~1v1~1contacts~1segments~1%7Bid%7D/put.md): Update segment name, description, or filter conditions.

Note: Updating filter_conditions will NOT automatically refresh membership.
Call POST /api/v1/contacts/segments/{id}/refresh to re-evaluate filters.

### Delete segment

 - [DELETE /api/v1/contacts/segments/{id}](https://developers.mailerlogic.com/customer-api.openapi/segments/paths/~1api~1v1~1contacts~1segments~1%7Bid%7D/delete.md): Delete a segment and all its memberships.

Warning: This action cannot be undone. Contacts themselves are NOT deleted, only their segment membership.

### Refresh dynamic segment

 - [POST /api/v1/contacts/segments/{id}/refresh](https://developers.mailerlogic.com/customer-api.openapi/segments/paths/~1api~1v1~1contacts~1segments~1%7Bid%7D~1refresh/post.md): Re-evaluate filter conditions and update segment membership.

Use cases:
- After updating filter conditions
- To sync segment with current contact data
- Before sending campaign to ensure up-to-date list

Note: Only works for dynamic segments. Static segments return error.

Performance: Refresh may take several seconds for large contact databases.

### Preview segment filters

 - [POST /api/v1/contacts/segments/preview](https://developers.mailerlogic.com/customer-api.openapi/segments/paths/~1api~1v1~1contacts~1segments~1preview/post.md): Preview how many contacts match given filter conditions WITHOUT creating a segment.

Use cases:
- Test filters before creating segment
- Estimate audience size for campaigns
- Validate filter logic

Returns: Contact count only (no actual contact data for performance)

### Add contacts to segment

 - [POST /api/v1/contacts/segments/{id}/contacts](https://developers.mailerlogic.com/customer-api.openapi/segments/paths/~1api~1v1~1contacts~1segments~1%7Bid%7D~1contacts/post.md): Manually add contacts to a segment.

Static segments: Adds contacts to membership
Dynamic segments: NOT recommended - contacts will be removed on next refresh if they don't match filters

### Remove contacts from segment

 - [DELETE /api/v1/contacts/segments/{id}/contacts](https://developers.mailerlogic.com/customer-api.openapi/segments/paths/~1api~1v1~1contacts~1segments~1%7Bid%7D~1contacts/delete.md): Manually remove contacts from a segment.

Static segments: Removes contacts from membership
Dynamic segments: NOT recommended - contacts may be re-added on next refresh if they match filters

## Tags

Flexible tagging system for categorizing and organizing contacts.

**Features:**
- Add/remove tags from contacts
- List all tags with usage counts
- Bulk tag operations
- Filter contacts by tags
- Use in segment filters

**Best Practices:**
- Use lowercase, hyphenated names (e.g., "early-adopter")
- Create tags for lifecycle stages ("trial", "paid", "churned")
- Tag by acquisition source ("webinar-2024", "partner-referral")
- Tag by interests or preferences ("product-updates", "newsletters")


### List all tags

 - [GET /api/v1/contacts/tags](https://developers.mailerlogic.com/customer-api.openapi/tags/paths/~1api~1v1~1contacts~1tags/get.md): Get all unique tags used in your contacts with usage statistics.

### Rename a tag

 - [PATCH /api/v1/contacts/tags/{tagName}](https://developers.mailerlogic.com/customer-api.openapi/tags/paths/~1api~1v1~1contacts~1tags~1%7Btagname%7D/patch.md): Rename a tag across all contacts. This updates the tag name everywhere it's used.

Common use cases:
- Fix typos: "newsleter" → "newsletter"
- Change case: "Newsletter" → "newsletter"
- Standardize naming: "vip_customer" → "vip"

Important:
- Returns 404 if the tag doesn't exist
- Returns 409 if the new name already exists (use merge instead)
- Atomic operation (all or nothing)
- Affects all contacts with this tag

### Merge multiple tags

 - [POST /api/v1/contacts/tags/merge](https://developers.mailerlogic.com/customer-api.openapi/tags/paths/~1api~1v1~1contacts~1tags~1merge/post.md): Merge multiple tags into a single target tag. This is essential for cleaning up duplicate tags.

Common use cases:
- Combine case variations: "Newsletter", "newsletter", "NEWSLETTER" → "newsletter"
- Consolidate similar tags: "vip", "VIP Customer", "vip-member" → "VIP"
- Fix duplicates after import: "customer-2024", "customer-2025" → "customer"

How it works:
1. For each contact with any source tag:
   - Adds target tag (if not already present)
   - Removes all source tags
2. Atomic operation (all or nothing)
3. Returns count of affected contacts

Example:
If contact has tags ["Newsletter", "newsletter"], merging both into "newsletter" results in just ["newsletter"].

Note: You can include the target tag in source_tags array - it will handle this correctly.

### Add tag(s) to contact

 - [POST /api/v1/contacts/{id}/tags](https://developers.mailerlogic.com/customer-api.openapi/tags/paths/~1api~1v1~1contacts~1%7Bid%7D~1tags/post.md): Add one or more tags to a contact. Supports both single tag and multiple tags.

### Remove tag from contact

 - [DELETE /api/v1/contacts/{id}/tags/{tagName}](https://developers.mailerlogic.com/customer-api.openapi/tags/paths/~1api~1v1~1contacts~1%7Bid%7D~1tags~1%7Btagname%7D/delete.md): Remove a specific tag from a contact.

## Contact Properties

Centralized property definition system for managing contact fields (HubSpot-style).

**Two Approaches Available:**

**1. Centralized Definitions (Recommended for CRM)**
- Define properties with types (text, number, date, select, boolean)
- Organize in groups (Contact Info, Company Info, Custom Fields)
- Set validation rules and default values
- Create dropdown options for select fields
- Manage through UI (create, edit, delete, reorder)

**2. Schema-less (Flexible)**
- Add any property on-the-fly to contacts
- No central definition needed
- Maximum flexibility for integrations
- System discovers what's in use

**Both approaches can coexist!**

**Property Types:**
- text, textarea, number, date, datetime
- boolean, select, multi_select
- url, email, phone, json

**Features:**
- Property groups for organization
- Required/optional fields
- Visibility controls
- Help text and placeholders
- Type-based validation
- Usage statistics

**Common Use Cases:**
- CRM contact fields (company, job_title, industry)
- Lead scoring (lead_score, engagement_level)
- E-commerce data (lifetime_value, last_purchase)
- Custom tracking fields (utm_campaign, referral_code)


### List all property groups

 - [GET /api/v1/contacts/property-groups](https://developers.mailerlogic.com/customer-api.openapi/contact-properties/paths/~1api~1v1~1contacts~1property-groups/get.md): Get all property groups with their property counts.

### Create property group

 - [POST /api/v1/contacts/property-groups](https://developers.mailerlogic.com/customer-api.openapi/contact-properties/paths/~1api~1v1~1contacts~1property-groups/post.md): Create a new property group for organizing contact properties.

### List all property definitions

 - [GET /api/v1/contacts/property-definitions](https://developers.mailerlogic.com/customer-api.openapi/contact-properties/paths/~1api~1v1~1contacts~1property-definitions/get.md): Get all property definitions with types, validation rules, and metadata.

Property Types Available:
- text, textarea, number, date, datetime
- boolean, select, multi_select
- url, email, phone, json

### Create property definition

 - [POST /api/v1/contacts/property-definitions](https://developers.mailerlogic.com/customer-api.openapi/contact-properties/paths/~1api~1v1~1contacts~1property-definitions/post.md): Create a new typed property definition with validation and metadata.

### Discover property keys (schema-less)

 - [GET /api/v1/contacts/custom-properties/keys](https://developers.mailerlogic.com/customer-api.openapi/contact-properties/paths/~1api~1v1~1contacts~1custom-properties~1keys/get.md): Get all custom property keys used across your contacts with usage statistics.

### Get contact properties

 - [GET /api/v1/contacts/{id}/custom-properties](https://developers.mailerlogic.com/customer-api.openapi/contact-properties/paths/~1api~1v1~1contacts~1%7Bid%7D~1custom-properties/get.md): Get all custom properties for a specific contact.

### Update properties (merge)

 - [PUT /api/v1/contacts/{id}/custom-properties](https://developers.mailerlogic.com/customer-api.openapi/contact-properties/paths/~1api~1v1~1contacts~1%7Bid%7D~1custom-properties/put.md): Add or update custom properties while keeping existing ones.

### Search contacts by property

 - [POST /api/v1/contacts/search-by-property](https://developers.mailerlogic.com/customer-api.openapi/contact-properties/paths/~1api~1v1~1contacts~1search-by-property/post.md): Find contacts based on custom property values.

Operators: =, exists, contains

