API Reference Guide

Our HTTP REST API lets you programmatically manage your domains and aliases for email forwarding.

Base URL

The base URL is: https://api.improvmx.com/v4

Versioning

The v4 api was released on Aug 12th, 2026.

The v3 api was released on April 30th, 2020.

The v2 api has been marked as deprecated and was removed on June 1st 2024.

Authentication

Get your API key from the API page of the dashboard, then use HTTP basic auth with username api and your API key as the password. With curl, pass them via -u and it will build the Authorization: Basic header for you:

export API_KEY="your_api_key_here"
curl https://api.improvmx.com/v4/domains \
  -u "api:$API_KEY"

Parameters

Every endpoint lists its parameters with a TYPE of query or body, which tells you where each one goes:

TYPE WHERE IT GOES TYPICAL METHOD
query In the URL, after ? as key=value. GET
body As JSON in the request body (curl's -d flag). POST, PUT

For example, listing domains filters with a query parameter in the URL:

curl -X GET "https://api.improvmx.com/v4/domains?query=pied" \
  -u "api:$API_KEY"

Adding a domain sends a body parameter as JSON:

curl -X POST https://api.improvmx.com/v4/domains \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{ "domain": "piedpiper.com" }'

Error codes

CODE DESCRIPTION
200 Success
400 Bad Request - Incorrect or missing parameter.
401 Authentication required - Missing or invalid credentials.
403 Forbidden - Missing permissions, e.g. requires a premium account.
429 Too Many Requests - You've been rate limited. See Rate limiting.
500 Server error - We ran into a bug. Let us know and we'll fix it.

Errors return a JSON body explaining the failure. Example Bad Request:

{
    "message": "You cannot use your domain in your email.",
    "errors": {
        "email": [
            "You cannot use your domain in your email."
        ]
    }
}

Every error has the same shape: message is always a displayable string, and errors is always present — a map of field to messages on validation failures, and {} otherwise. For validation failures message repeats the first field message, so you can show it without walking the map.

Rate Limits

Free accounts get 30 requests per minute per endpoint; paid plans get 200.

Every response includes rate-limit headers so you can track your budget:

HEADER DESCRIPTION
X-RateLimit-Limit Max requests allowed in the current window.
X-RateLimit-Remaining Requests left in the current window.
X-RateLimit-Reset When the window resets, as a Unix timestamp (seconds).
Retry-After On a 429 only — seconds to wait before retrying.

When you exceed the limit, the API responds 429 Too Many Requests. Back off for Retry-After seconds (or until X-RateLimit-Reset) before trying again.

Account

Get account

GET /account

curl -X GET https://api.improvmx.com/v4/account \
  -u "api:$API_KEY"

Response:

{
    "account": {
        "address": "1 Decentralized Street, 92024 California",
        "billing_email": null,
        "cancels_at": null,
        "company_vat": null,
        "country": "US",
        "created_at": "2017-12-01T13:23:02Z",
        "email": "richard.hendricks@gmail.com",
        "email_log_retention_days": 7,
        "lock_reason": null,
        "locked": null,
        "name": "PiedPiper Inc.",
        "over_quota": false,
        "plan": {
            "name": "Enterprise - PiedPiper",
            "price": 249,
            "billing_cycle": "monthly",
            "domains_limit": 10000,
            "aliases_limit": 10000,
            "rules_limit": 50,
            "daily_receive_limit": 100000,
            "daily_send_limit": 200,
            "monthly_receive_limit": 0,
            "monthly_send_limit": 0
        },
        "privacy_level": 1,
        "renews_at": "2020-04-30T07:50:59Z"
    }
}

Domains

Add domains to ImprovMX that you want to send/receive emails from.

List domains

GET /domains

curl -X GET "https://api.improvmx.com/v4/domains?query=pied" \
  -u "api:$API_KEY"
PARAMETER TYPE DESCRIPTION
query query Filter domains by substring.
forwarding_ready query Only domains whose MX records resolve to ImprovMX (true) or not (false).
send_ready query Only domains ready (true) or not ready (false) to send outbound mail.
whitelabel query Filter by whitelabel: a specific brand (e.g. hooli.com) matches that whitelabel exactly, null matches domains without one. Omit to not filter.
routing_engine query Filter by routing engine: alias or rules matches that engine exactly, null matches domains with routing disabled. Omit to not filter.
order query Sort order: name_asc (default), name_desc, created_asc, or created_desc.
limit query Number of domains. Default 20, max 200.
page query Page number (1-based, default 1).

Response:

{
    "domains": [
        {
            "domain": "google.com",
            "forwarding_ready": true,
            "send_ready": false,
            "banned": false,
            "notification_email": null,
            "notify_when_spam_blocked": false,
            "routing_engine": null,
            "rules_fallback_email": null,
            "strict_mxes": true,
            "whitelabel": null,
            "created_at": "2019-06-04T09:14:57Z",
            "updated_at": "2019-06-04T09:14:57Z"
        },
        {
            "domain": "piedpiper.com",
            "forwarding_ready": false,
            "send_ready": false,
            "banned": false,
            "notification_email": null,
            "notify_when_spam_blocked": false,
            "routing_engine": null,
            "rules_fallback_email": null,
            "strict_mxes": true,
            "whitelabel": null,
            "created_at": "2019-06-04T09:15:33Z",
            "updated_at": "2019-06-04T09:15:33Z"
        }
    ],
    "total": 2,
    "limit": 20,
    "page": 1
}

Use query to filter domains by substring, as shown in the curl example above. Response:

{
    "domains": [
        {
            "domain": "piedpiper.com",
            "forwarding_ready": true,
            "send_ready": false,
            "banned": false,
            "notification_email": null,
            "notify_when_spam_blocked": false,
            "routing_engine": null,
            "rules_fallback_email": null,
            "strict_mxes": true,
            "whitelabel": null,
            "created_at": "2019-06-04T09:15:27Z",
            "updated_at": "2019-06-04T09:15:27Z"
        }
    ],
    "total": 1,
    "limit": 20,
    "page": 1
}

Get domain

GET /domains/:domain

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com \
  -u "api:$API_KEY"

Response:

{
    "domain": {
        "domain": "piedpiper.com",
        "forwarding_ready": false,
        "send_ready": false,
        "banned": false,
        "notification_email": null,
        "notify_when_spam_blocked": false,
        "routing_engine": null,
        "rules_fallback_email": null,
        "strict_mxes": true,
        "whitelabel": null,
        "created_at": "2019-06-04T09:15:33Z",
        "updated_at": "2019-06-04T09:15:33Z"
    }
}

Add domain

POST /domains

curl -X POST https://api.improvmx.com/v4/domains \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "domain": "piedpiper.com"
  }'
PARAMETER TYPE DESCRIPTION
domain body Required. Domain name.
notification_email body Optionally, where to send notifications. Defaults to your account email.
whitelabel body Parent domain shown in DNS settings.

Response:

{
    "domain": {
        "domain": "piedpiper.com",
        "forwarding_ready": false,
        "send_ready": false,
        "banned": false,
        "notification_email": null,
        "notify_when_spam_blocked": false,
        "routing_engine": null,
        "rules_fallback_email": null,
        "strict_mxes": true,
        "whitelabel": null,
        "created_at": "2019-06-04T12:53:26Z",
        "updated_at": "2019-06-04T12:53:26Z"
    }
}

Update domain

PUT /domains/:domain

The domain name cannot be changed.

curl -X PUT https://api.improvmx.com/v4/domains/piedpiper.com \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "notification_email": "richard.hendricks@gmail.com",
      "whitelabel": "hooli.com"
  }'
PARAMETER TYPE DESCRIPTION
notification_email body Optionally, where to send notifications. Defaults to your account email.
whitelabel body Parent domain owner.

Response:

{
    "domain": {
        "domain": "piedpiper.com",
        "forwarding_ready": false,
        "send_ready": false,
        "banned": false,
        "notification_email": "richard.hendricks@gmail.com",
        "notify_when_spam_blocked": false,
        "routing_engine": null,
        "rules_fallback_email": null,
        "strict_mxes": true,
        "whitelabel": "hooli.com",
        "created_at": "2019-06-04T09:15:33Z",
        "updated_at": "2026-05-06T12:00:00Z"
    }
}

Verify domain

POST /domains/:domain/verify

Verifies the domain's MX, SPF, DKIM, and DMARC records are correct. Once verified, we will begin forwarding your emails.

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/verify \
  -u "api:$API_KEY"

Response:

{
    "records": {
        "provider": "cloudflare",
        "advanced": true,
        "dkim1": {
            "expected": "dkimprovmx1.improvmx.com.",
            "valid": true,
            "values": "dkimprovmx1.improvmx.com."
        },
        "dkim2": {
            "expected": "dkimprovmx2.improvmx.com.",
            "valid": true,
            "values": "dkimprovmx2.improvmx.com."
        },
        "dmarc": {
            "expected": "v=DMARC1; p=none;",
            "valid": false,
            "values": null
        },
        "error": null,
        "mx": {
            "expected": [
                "mx1.improvmx.com",
                "mx2.improvmx.com"
            ],
            "valid": true,
            "values": [
                "mx2.improvmx.com",
                "mx1.improvmx.com"
            ]
        },
        "spf": {
            "expected": "v=spf1 include:someservice.org include:spf.improvmx.com ~all",
            "valid": false,
            "values": "v=spf1 include:someservice.org ~all"
        },
        "valid": false
    }
}

The error field contains the reason when MX is not configured correctly.

Delete domain

DELETE /domains/:domain

curl -X DELETE https://api.improvmx.com/v4/domains/piedpiper.com \
  -u "api:$API_KEY"

Returns 204 No Content on success.

Aliases

Aliases are mailbox identities under your domain, i.e. richard@piedpiper.com forwards to richard.hendricks@gmail.com

List aliases

GET /domains/:domain/aliases

curl -X GET "https://api.improvmx.com/v4/domains/piedpiper.com/aliases?query=richard" \
  -u "api:$API_KEY"
PARAMETER TYPE DESCRIPTION
query query Filter alias and destination by substring.
order query Sort order: name_asc (default), name_desc, created_asc, or created_desc.
limit query Number of aliases. Default 20, max 200.
page query Page number (1-based, default 1).

Response:

{
    "aliases": [
        {
            "created_at": "2023-12-19T10:44:32Z",
            "updated_at": "2023-12-19T10:44:32Z",
            "forward": "richard.hendricks@gmail.com",
            "alias": "richard",
            "id": "4"
        },
        {
            "created_at": "2023-12-19T10:44:32Z",
            "updated_at": "2023-12-19T10:44:32Z",
            "forward": "jared.dunn@gmail.com",
            "alias": "jared",
            "id": "5"
        }
    ],
    "limit": 20,
    "page": 1,
    "total": 2
}

Get alias

GET /domains/:domain/aliases/:id

Resolves by id (the string returned at creation or listing).

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com/aliases/11 \
  -u "api:$API_KEY"

Response:

{
    "alias": {
        "created_at": "2023-12-19T10:44:32Z",
        "updated_at": "2023-12-19T10:44:32Z",
        "forward": "richard.hendricks@protonmail.com",
        "alias": "richard",
        "id": "11"
    }
}

Add alias

POST /domains/:domain/aliases

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/aliases \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "alias": "richard",
      "forward": "richard.hendricks@gmail.com"
  }'
PARAMETER TYPE DESCRIPTION
alias body Required. Local part of the address (e.g. contact, info).
forward body Required. Comma-separated destination emails and/or webhooks.

Response:

{
    "alias": {
        "forward": "richard.hendricks@gmail.com",
        "alias": "richard",
        "id": "11",
        "created_at": "2026-05-05T11:32:00Z",
        "updated_at": "2026-05-05T11:32:00Z"
    }
}

Add aliases

POST /domains/:domain/aliases/batch

Batch-create aliases. Returns successful and failed entries separately, plus counts. 200 when every entry succeeded, 207 Multi-Status when any failed. Each failed entry is exactly index (its 0-based position in the array you sent), message and errors — the submitted item isn't echoed back.

NOTE: Batch-create requires a paid plan.

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/aliases/batch \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "aliases": [
          {"alias": "richard", "forward": "richard.hendricks@gmail.com"},
          {"alias": "jared", "forward": "jared.dunn@gmail.com"}
      ]
  }'
PARAMETER TYPE DESCRIPTION
aliases body Required. Up to 500 objects, each with alias and forward.

Response:

{
    "added": [
        {
            "alias": "richard",
            "forward": "richard.hendricks@gmail.com",
            "id": "12345",
            "created_at": "2026-05-05T11:32:00Z",
            "updated_at": "2026-05-05T11:32:00Z"
        },
        {
            "alias": "jared",
            "forward": "jared.dunn@gmail.com",
            "id": "12346",
            "created_at": "2026-05-05T11:32:00Z",
            "updated_at": "2026-05-05T11:32:00Z"
        }
    ],
    "added_count": 2,
    "failed": [],
    "failed_count": 0
}

Update alias

PUT /domains/:domain/aliases/:id

Alias must be the numeric id 11 returned at creation or listing.

curl -X PUT https://api.improvmx.com/v4/domains/piedpiper.com/aliases/11 \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "forward": "richard.hendricks@protonmail.com"
  }'
PARAMETER TYPE DESCRIPTION
forward body Required. Comma-separated destination emails and/or webhooks.

Response:

{
    "alias": {
        "forward": "richard.hendricks@protonmail.com",
        "alias": "richard",
        "id": "11",
        "created_at": "2026-05-05T11:32:00Z",
        "updated_at": "2026-05-05T11:38:00Z"
    }
}

Update aliases

PUT /domains/:domain/aliases/batch

Bulk-update aliases by id. Returns successful and failed entries separately, plus counts. 200 when every entry succeeded, 207 Multi-Status when any failed. Each failed entry is exactly index (its 0-based position in the array you sent), message and errors — the submitted item isn't echoed back.

curl -X PUT https://api.improvmx.com/v4/domains/piedpiper.com/aliases/batch \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "aliases": [
          {"id": "12345", "forward": "richard.hendricks@protonmail.com"},
          {"id": "12346", "forward": "jared.dunn@protonmail.com"},
          {"id": "999999", "forward": "gilfoyle@piedpiper.com"}
      ]
  }'
PARAMETER TYPE DESCRIPTION
aliases body Required. Up to 500 objects, each with a string id and the fields to update (e.g. forward).

Response:

{
    "updated": [
        {
            "alias": "richard",
            "forward": "richard.hendricks@protonmail.com",
            "id": "12345",
            "created_at": "2026-05-05T11:32:00Z",
            "updated_at": "2026-05-05T12:00:00Z"
        },
        {
            "alias": "jared",
            "forward": "jared.dunn@protonmail.com",
            "id": "12346",
            "created_at": "2026-05-05T11:32:00Z",
            "updated_at": "2026-05-05T12:00:00Z"
        }
    ],
    "updated_count": 2,
    "failed": [
        {
            "index": 2,
            "message": "Alias not found.",
            "errors": {}
        }
    ],
    "failed_count": 1
}

Delete alias

DELETE /domains/:domain/aliases/:id

Delete alias by id (the string returned at creation or listing).

curl -X DELETE https://api.improvmx.com/v4/domains/piedpiper.com/aliases/11 \
  -u "api:$API_KEY"

Returns 204 No Content on success.

Delete aliases

DELETE /domains/:domain/aliases/batch

Bulk-delete aliases by id. Returns successful and failed entries separately, plus counts. 200 when every entry succeeded, 207 Multi-Status when any failed. Each failed entry is exactly index (its 0-based position in the array you sent), message and errors — the submitted item isn't echoed back.

curl -X DELETE https://api.improvmx.com/v4/domains/piedpiper.com/aliases/batch \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"ids": ["12345", "12346", "12347"]}'
PARAMETER TYPE DESCRIPTION
ids body Required. Up to 500 alias ids (strings) to delete.

Response:

{
    "deleted": ["12345", "12346"],
    "deleted_count": 2,
    "failed": [
        {
            "index": 2,
            "message": "Alias not found.",
            "errors": {}
        }
    ],
    "failed_count": 1
}

Delete all aliases

DELETE /domains/:domain/aliases?all=true

The ?all=true query parameter is required — it's a guard so a misfired request can't wipe every alias by accident. To delete a specific set of aliases instead, use the batch endpoint.

curl -X DELETE https://api.improvmx.com/v4/domains/piedpiper.com/aliases?all=true \
  -u "api:$API_KEY"

Response:

{
    "deleted": 42
}

Rules

Rules are used to route incoming email to specific destinations based on various criteria.

There are several types of rules described below.

Alias rule config

Schema for adding or updating alias rules.

{
    "alias": "richard",
    "forward": "richard.hendricks@gmail.com"
}
PARAMETER DESCRIPTION
alias Required. Alias this rule matches.
forward Required. Comma-separated forwarding destinations.

Regex rule config

Schema for adding or updating regex rules.

{
    "forward": "jared.dunn@live.com",
    "regex": ".*jared.*",
    "scopes": [
        "sender",
        "recipient",
        "subject",
        "body"
    ]
}
PARAMETER DESCRIPTION
regex Required. Regex pattern to match.
scopes Required. Match scopes: sender, recipient, subject, body.
forward Required. Comma-separated forwarding destinations.

CEL rule config

Schema for adding or updating CEL rules.

{
    "expression": "subject.contains('finance')",
    "forward": "monica@yahoo.com"
}
PARAMETER DESCRIPTION
expression Required. CEL expression to match.
forward Required. Comma-separated forwarding destinations.

List rules

GET /domains/:domain/rules

curl -X GET "https://api.improvmx.com/v4/domains/piedpiper.com/rules?query=richard" \
  -u "api:$API_KEY"
PARAMETER TYPE DESCRIPTION
query query Filter rules by substring.
order query Sort order: rank_asc (default), rank_desc, created_asc, or created_desc.
limit query Number of rules. Default 20, max 200.
page query Page number (1-based, default 1).

Response:

{
    "limit": 20,
    "page": 1,
    "rules": [
        {
            "active": true,
            "config": {
                "alias": "richard",
                "forward": "richard.hendricks@gmail.com"
            },
            "created_at": "2025-07-09T01:53:48Z",
            "updated_at": "2025-07-09T01:53:48Z",
            "rank": 1.0,
            "id": "447a95d1-bac1-4d6e-8315-22b10f501efb",
            "type": "alias"
        },
        {
            "active": true,
            "config": {
                "forward": "jared.dunn@live.com",
                "regex": ".*jared.*",
                "scopes": [
                    "sender"
                ]
            },
            "created_at": "2025-07-14T04:30:18Z",
            "updated_at": "2025-07-14T04:30:18Z",
            "rank": 2.0,
            "id": "fcadc999-0d3f-45f8-9c62-056e1b98e47a",
            "type": "regex"
        }
    ],
    "total": 2
}

Add rule

POST /domains/:domain/rules

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/rules \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "type": "regex",
      "config": {
          "regex": ".*important.*",
          "scopes": [
              "subject",
              "body"
          ],
          "forward": "richard.hendricks@gmail.com"
      }
  }'
PARAMETER TYPE DESCRIPTION
type body Required. One of alias, regex, or cel.
config body Required. JSON config for the rule (varies by type).
rank body Rank determining evaluation priority. Defaults to the next largest rank.
active body Whether the rule is active.
id body Rule ID. Auto-generated UUID if omitted.

Response:

{
    "rule": {
        "active": true,
        "config": {
            "alias": "richard",
            "forward": "richard.hendricks@gmail.com"
        },
        "created_at": "2025-07-09T01:53:48Z",
        "updated_at": "2025-07-09T01:53:48Z",
        "rank": 1.0,
        "id": "447a95d1-bac1-4d6e-8315-22b10f501efb",
        "type": "alias"
    }
}

Add rules

POST /domains/:domain/rules/batch

Bulk-create rules. Returns successful and failed entries separately, plus counts. 200 when every entry succeeded, 207 Multi-Status when any failed. Each failed entry is exactly index (its 0-based position in the array you sent), message and errors — the submitted item isn't echoed back.

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/rules/batch \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "rules": [
          {
              "type": "alias",
              "config": {
                  "alias": "richard",
                  "forward": "richard.hendricks@gmail.com"
              }
          },
          {
              "type": "regex",
              "config": {
                  "regex": ".*finance.*",
                  "scopes": ["subject"],
                  "forward": "not-an-email"
              }
          }
      ]
  }'
PARAMETER TYPE DESCRIPTION
rules body Required. Up to 500 rule objects, each with type and config (and optionally rank, active, id).

Response:

{
    "added": [
        {
            "active": true,
            "config": {
                "alias": "richard",
                "forward": "richard.hendricks@gmail.com"
            },
            "created_at": "2026-05-05T11:32:00Z",
            "updated_at": "2026-05-05T11:32:00Z",
            "id": "62f9cf67-9005-41a6-8706-843ca8df8932",
            "rank": 50.0,
            "type": "alias"
        }
    ],
    "added_count": 1,
    "failed": [
        {
            "index": 1,
            "message": "Invalid forward address.",
            "errors": {}
        }
    ],
    "failed_count": 1
}

Get rule

GET /domains/:domain/rules/:rule

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com/rules/447a95d1-bac1-4d6e-8315-22b10f501efb \
  -u "api:$API_KEY"

Response:

{
    "rule": {
        "active": true,
        "config": {
            "alias": "richard",
            "forward": "richard.hendricks@gmail.com"
        },
        "created_at": "2025-07-09T01:53:48Z",
        "updated_at": "2025-07-09T01:53:48Z",
        "rank": 1.0,
        "id": "447a95d1-bac1-4d6e-8315-22b10f501efb",
        "type": "alias"
    }
}

Update rule

PUT /domains/:domain/rules/:rule

curl -X PUT https://api.improvmx.com/v4/domains/piedpiper.com/rules/e8417681-3a4c-4f9b-ab93-1ca2529036c9 \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "config": {
          "regex": ".*critical.*",
          "scopes": [
              "subject",
              "body"
          ],
          "forward": "richard.hendricks@gmail.com"
      }
  }'
PARAMETER TYPE DESCRIPTION
config body Required. JSON config for the rule (varies by type).
rank body Rank determining evaluation priority. Defaults to the next largest rank.
active body Whether the rule is active.

Response:

{
    "rule": {
        "active": true,
        "config": {
            "regex": ".*critical.*",
            "scopes": [
                "subject",
                "body"
            ],
            "forward": "richard.hendricks@gmail.com"
        },
        "created_at": "2025-07-09T01:53:48Z",
        "updated_at": "2026-05-05T11:32:00Z",
        "id": "447a95d1-bac1-4d6e-8315-22b10f501efb",
        "rank": 1.0,
        "type": "alias"
    }
}

Update rules

PUT /domains/:domain/rules/batch

Bulk-update rules by id. Returns successful and failed entries separately, plus counts. 200 when every entry succeeded, 207 Multi-Status when any failed. Each failed entry is exactly index (its 0-based position in the array you sent), message and errors — the submitted item isn't echoed back.

curl -X PUT https://api.improvmx.com/v4/domains/piedpiper.com/rules/batch \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "rules": [
          {
              "id": "62f9cf67-9005-41a6-8706-843ca8df8932",
              "config": {
                  "alias": "gavin.belson@gmail.com"
              }
          },
          {
              "id": "00000000-0000-0000-0000-000000000000",
              "config": {"regex": ".+"}
          }
      ]
  }'
PARAMETER TYPE DESCRIPTION
rules body Required. Up to 500 objects, each with a string id and the fields to update (e.g. config, rank, active).

Response:

{
    "updated": [
        {
            "active": true,
            "config": {
                "alias": "gavin@gmail.com",
                "forward": "gavin.belson@gmail.com"
            },
            "created_at": "2025-07-14T17:29:50Z",
            "updated_at": "2026-05-05T11:32:00Z",
            "id": "62f9cf67-9005-41a6-8706-843ca8df8932",
            "rank": 50.0,
            "type": "alias"
        }
    ],
    "updated_count": 1,
    "failed": [
        {
            "index": 1,
            "message": "Rule not found.",
            "errors": {}
        }
    ],
    "failed_count": 1
}

Delete rule

DELETE /domains/:domain/rules/:rule

curl -X DELETE https://api.improvmx.com/v4/domains/piedpiper.com/rules/e8417681-3a4c-4f9b-ab93-1ca2529036c9 \
  -u "api:$API_KEY"

Returns 204 No Content on success.

Delete rules

DELETE /domains/:domain/rules/batch

Bulk-delete rules by id. Returns successful and failed entries separately, plus counts. 200 when every entry succeeded, 207 Multi-Status when any failed. Each failed entry is exactly index (its 0-based position in the array you sent), message and errors — the submitted item isn't echoed back.

curl -X DELETE https://api.improvmx.com/v4/domains/piedpiper.com/rules/batch \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "ids": [
          "62f9cf67-9005-41a6-8706-843ca8df8932",
          "5742c992-4378-4412-945b-be2177072fc4",
          "00000000-0000-0000-0000-000000000000"
      ]
  }'
PARAMETER TYPE DESCRIPTION
ids body Required. Up to 500 rule ids (UUID strings) to delete.

Response:

{
    "deleted": [
        "62f9cf67-9005-41a6-8706-843ca8df8932",
        "5742c992-4378-4412-945b-be2177072fc4"
    ],
    "deleted_count": 2,
    "failed": [
        {
            "index": 2,
            "message": "Rule not found.",
            "errors": {}
        }
    ],
    "failed_count": 1
}

Delete all rules

DELETE /domains/:domain/rules?all=true

The ?all=true query parameter is required — it's a guard so a misfired request can't wipe every rule by accident. To delete a specific set of rules instead, use the batch endpoint.

curl -X DELETE https://api.improvmx.com/v4/domains/piedpiper.com/rules?all=true \
  -u "api:$API_KEY"

Response:

{
    "deleted": 42
}

Email Logs

View your domain logs to see emails sent or received.

List email logs

GET /domains/:domain/logs

Returns email statuses. All filter parameters are optional and combine with AND.

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com/logs \
  -u "api:$API_KEY" -G \
  --data-urlencode "sender=gavin@hooli.com" \
  --data-urlencode "status=DELIVERED,SOFT-BOUNCE"
PARAMETER TYPE DESCRIPTION
sender query Exact match on sender address (case-insensitive).
recipient query Exact match on recipient address (case-insensitive).
forward query Exact match on forwarding destination (case-insensitive).
status query Filter to logs that contain an event with this status. Comma-separated list of QUEUED, DELIVERED, SOFT-BOUNCE, HARD-BOUNCE, BOUNCED, REFUSED.
transport query Filter by message transport. One of mx (forwarded mail), smtp (authenticated SMTP sends), or api (messages sent through the API).
order query created_desc (default, most recent first) or created_asc.
after query ISO 8601 timestamp (e.g. 2024-07-02T12:00:00Z ). Returns entries received after this time.
before query ISO 8601 timestamp. Returns entries received before this time.
limit query Number of entries per page. Default 100, max 200.
cursor query Load logs starting from this log id (e.g. 20201002014128.7ea8ee5b46). Pass next_cursor from the previous response to paginate.

Response:

{
    "logs": [
        {
            "created_at": "2020-01-25T12:19:09Z",
            "events": [
                {
                    "code": 250,
                    "created_at": "2020-01-25T12:19:11Z",
                    "id": "<20200125121911.4a9c2e7b@mail.hooli.com>-0",
                    "local": "mxb.infra.improvmx.com",
                    "message": "Queued",
                    "server": "mail-io1-f54.google.com",
                    "status": "QUEUED"
                },
                {
                    "code": 250,
                    "created_at": "2020-01-25T12:19:12Z",
                    "id": "<20200125121911.4a9c2e7b@mail.hooli.com>-1",
                    "local": "gmail-smtp-in.l.google.com",
                    "message": "Sent.",
                    "server": "mail16.mxc.infra.improvmx.com",
                    "status": "DELIVERED"
                }
            ],
            "forward": {
                "email": "richard.hendricks@gmail.com",
                "name": "Richard Hendricks"
            },
            "hostname": "mail-io1-f54.google.com",
            "id": "20201002014128.5ea8ee59fa894aa7a9141e9665985b46",
            "message_id": "<20200125121911.4a9c2e7b@mail.hooli.com>",
            "recipient": {
                "email": "richard@piedpiper.com",
                "name": "Richard Hendricks"
            },
            "sender": {
                "email": "gavin@hooli.com",
                "name": "Gavin Belsonx"
            },
            "subject": "You are screwed, Piedpiper team!",
            "transport": "smtp"
        },
        {
            "created_at": "2020-01-25T11:30:41Z",
            "events": [
                {
                    "code": 550,
                    "created_at": "2020-01-25T11:30:42Z",
                    "id": "<20200125113041.7f3a1d8c@mail.hooli.com>-0",
                    "local": "mxa.infra.improvmx.com",
                    "message": "5.7.1 Message considered as SPAM (Score of 5.8/5.0 with BAYES_20, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, HTML_MESSAGE, HTML_TAG_BALANCE_BODY, MIME_HEADER_CTYPE_ONLY, NO_RELAYS, URIBL_ABUSE_SURBL, URIBL_DBL_ABUSE_SPAM, URIBL_DBL_SPAM)",
                    "server": "mail-wm1-f67.google.com",
                    "status": "REFUSED"
                }
            ],
            "forward": null,
            "hostname": "mail-wm1-f67.google.com",
            "id": "20201002014128.7ea8ee59fa894aa7a91415a6659c5b46",
            "message_id": "<20200125113041.7f3a1d8c@mail.hooli.com>",
            "recipient": {
                "email": "richard@piedpiper.com",
                "name": null
            },
            "sender": {
                "email": "spam@hooli.com",
                "name": "ThinkTeam"
            },
            "subject": "Enlarge your (pied)piper!",
            "transport": "smtp"
        }
    ],
    "limit": 100,
    "cursor": "20201002014128.5ea8ee59fa894aa7a9141e9665985b46",
    "next_cursor": "20201002014128.7ea8ee59fa894aa7a91415a6659c5b46"
}

next_cursor is the cursor of the next page, or null when there are no more results. Pass it back as cursor to fetch the next page.

Each entry in logs contains a list of events. Possible statuses:

Status Description
QUEUED Accepted for processing.
REFUSED Refused at the SMTP connection.
DELIVERED Delivered to the destination.
SOFT-BOUNCE Temporarily refused. Retried with backoff.
HARD-BOUNCE Rejected by the destination.
BOUNCED Delivery failed — a bounce not classified as soft or hard.

Count email logs

GET /domains/:domain/logs/count

Returns the total number of logs matching the same filters as the list endpoint above.

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com/logs/count \
  -u "api:$API_KEY" -G \
  --data-urlencode "sender=gavin@hooli.com" \
  --data-urlencode "status=DELIVERED,SOFT-BOUNCE"
PARAMETER TYPE DESCRIPTION
sender query Exact match on sender address (case-insensitive).
recipient query Exact match on recipient address (case-insensitive).
forward query Exact match on forwarding destination (case-insensitive).
status query Filter to logs that contain an event with this status. Comma-separated list of QUEUED, DELIVERED, SOFT-BOUNCE, HARD-BOUNCE, BOUNCED, REFUSED.
transport query Filter by message transport. One of mx (forwarded mail), smtp (authenticated SMTP sends), or api (messages sent through the API).
after query ISO 8601 timestamp (e.g. 2024-07-02T12:00:00Z). Counts entries received after this time.
before query ISO 8601 timestamp. Counts entries received before this time.

Response:

{
    "total": 1337
}

Get email log

GET /domains/:domain/logs/:id

Look up one email by its id — any entry's id from the list above. Returns that entry, including its full events delivery timeline. Responds with 404 if no log with that id exists for the domain.

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com/logs/20250330190000.a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 \
  -u "api:$API_KEY"

Response:

{
    "created_at": "2025-03-30T19:00:00Z",
    "events": [
        {
            "code": 250,
            "created_at": "2025-03-30T19:00:00Z",
            "id": "<174336120000.1560119.13026979903154377804@piedpiper.com>-0",
            "local": "api.improvmx.com",
            "message": "2.0.0 Email queued for delivery.",
            "server": "mail-io1-f54.google.com",
            "status": "QUEUED"
        },
        {
            "code": 250,
            "created_at": "2025-03-30T19:00:12Z",
            "id": "<174336120000.1560119.13026979903154377804@piedpiper.com>-1",
            "local": "gmail-smtp-in.l.google.com",
            "message": "2.0.0 OK",
            "server": "mail16.mxc.infra.improvmx.com",
            "status": "DELIVERED"
        }
    ],
    "forward": null,
    "hostname": "piedpiper.com",
    "id": "20250330190000.a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
    "message_id": "<174336120000.1560119.13026979903154377804@piedpiper.com>",
    "recipient": {
        "email": "gilfoyle@piedpiper.com",
        "name": null
    },
    "sender": {
        "email": "richard@piedpiper.com",
        "name": null
    },
    "subject": "Middle-out compression",
    "transport": "api"
}

Search email logs

GET /domains/:domain/logs/search

Typo-tolerant fuzzy search across subject, sender, recipient, and forward. query is required; the optional filters AND with it. Results are offset-paginated.

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com/logs/search \
  -u "api:$API_KEY" -G \
  --data-urlencode "query=series a" \
  --data-urlencode "status=DELIVERED,SOFT-BOUNCE"
PARAMETER TYPE DESCRIPTION
query query Required. Typo-tolerant keyword. Matches across subject, sender, recipient, and forward.
sender query Case-insensitive substring filter on sender address.
recipient query Case-insensitive substring filter on recipient address.
forward query Case-insensitive substring filter on forwarding destination.
status query Filter to logs that contain an event with this status. Comma-separated list of QUEUED, DELIVERED, SOFT-BOUNCE, HARD-BOUNCE, BOUNCED, REFUSED.
transport query Filter by message transport. One of mx (forwarded mail), smtp (authenticated SMTP sends), or api (messages sent through the API).
order query relevance (default, best match first), created_desc (most recent first), or created_asc.
limit query Number of results. Default 20, max 200.
offset query Skip this many results. Pass next_offset from the previous response to paginate.
after query ISO 8601 timestamp (e.g. 2024-07-02T12:00:00Z ). Returns entries received after this time.
before query ISO 8601 timestamp. Returns entries received before this time.

Response:

{
    "logs": [
        {
            "created_at": "2025-05-12T09:45:18Z",
            "events": [
                {
                    "code": 250,
                    "created_at": "2025-05-12T09:45:20Z",
                    "id": "<20250512094518.7c1a9f3e@mail.raviga.com>-0",
                    "local": "mx1.improvmx.com",
                    "message": "Queued",
                    "server": "mail-yw1-f44.google.com",
                    "status": "QUEUED"
                },
                {
                    "code": 250,
                    "created_at": "2025-05-12T09:45:23Z",
                    "id": "<20250512094518.7c1a9f3e@mail.raviga.com>-1",
                    "local": "gmail-smtp-in.l.google.com",
                    "message": "Sent.",
                    "server": "mail7.mxa.infra.improvmx.com",
                    "status": "DELIVERED"
                }
            ],
            "forward": {
                "email": "richard.hendricks@gmail.com",
                "name": "Richard Hendricks"
            },
            "hostname": "mail-yw1-f44.google.com",
            "id": "20250512094518.0412c5c8a4f74a82b4d02ea83404a6f1",
            "message_id": "<20250512094518.7c1a9f3e@mail.raviga.com>",
            "recipient": {
                "email": "richard@piedpiper.com",
                "name": null
            },
            "sender": {
                "email": "monica@raviga.com",
                "name": "Monica Hall"
            },
            "subject": "Series A term sheet draft",
            "transport": "smtp"
        },
        {
            "created_at": "2025-05-12T06:12:04Z",
            "events": [
                {
                    "code": 250,
                    "created_at": "2025-05-12T06:12:05Z",
                    "id": "<20250512061204.b4e82d6a@mail.raviga.com>-0",
                    "local": "mx2.improvmx.com",
                    "message": "Queued",
                    "server": "mail-pj1-f32.google.com",
                    "status": "QUEUED"
                },
                {
                    "code": 250,
                    "created_at": "2025-05-12T06:12:07Z",
                    "id": "<20250512061204.b4e82d6a@mail.raviga.com>-1",
                    "local": "gmail-smtp-in.l.google.com",
                    "message": "Sent.",
                    "server": "mail12.mxa.infra.improvmx.com",
                    "status": "DELIVERED"
                }
            ],
            "forward": {
                "email": "jared.dunn@gmail.com",
                "name": "Jared Dunn"
            },
            "hostname": "mail-pj1-f32.google.com",
            "id": "20250512061204.9f65bc20deab4f71bcedad1dfc513e9a",
            "message_id": "<20250512061204.b4e82d6a@mail.raviga.com>",
            "recipient": {
                "email": "jared@piedpiper.com",
                "name": null
            },
            "sender": {
                "email": "laurie@raviga.com",
                "name": "Laurie Bream"
            },
            "subject": "Re: Series A funding timeline",
            "transport": "smtp"
        }
    ],
    "limit": 20,
    "offset": 0,
    "total": 2,
    "next_offset": null
}

next_offset is the offset of the next page, or null when there are no more results. Pass it back as offset to fetch the next page.

SMTP Credentials

Add SMTP credentials to send emails from your domain, e.g. send from richard@piedpiper.com instead of richard@gmail.com.

List credentials

GET /domains/:domain/credentials

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com/credentials \
  -u "api:$API_KEY"
PARAMETER TYPE DESCRIPTION
limit query Number of credentials. Default 20, max 200.
page query Page number (1-based, default 1).

Response:

{
    "credentials": [
        {
            "created_at": "2020-02-13T14:42:50Z",
            "usage": 0,
            "username": "richard"
        },
        {
            "created_at": "2020-02-13T15:17:08Z",
            "usage": 0,
            "username": "monica"
        }
    ],
    "limit": 20,
    "page": 1,
    "total": 2
}

Add credential

POST /domains/:domain/credentials

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/credentials \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "username": "bighead",
      "password": "abc123"
  }'
PARAMETER TYPE DESCRIPTION
username body Required. Alias name (e.g. bighead for bighead@piedpiper.com).
password body Required. SMTP credential password.

Response:

{
    "credential": {
        "created_at": "2020-04-30T08:55:52Z",
        "usage": 0,
        "username": "bighead"
    },
    "requires_new_mx_check": false
}

requires_new_mx_check is true on your first credential. First-time SMTP setup requires two new DKIM CNAMEs and a DMARC TXT entry in your DNS; sending is blocked until they're added.

Update credential

PUT /domains/:domain/credentials/:username

curl -X PUT https://api.improvmx.com/v4/domains/piedpiper.com/credentials/bighead \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "password": "abcd1234"
  }'

Response:

{
    "credential": {
        "created_at": "2020-04-30T08:55:52Z",
        "usage": 0,
        "username": "bighead"
    }
}

Delete credential

DELETE /domains/:domain/credentials/:username

curl -X DELETE https://api.improvmx.com/v4/domains/piedpiper.com/credentials/russ \
  -u "api:$API_KEY"

Returns 204 No Content on success.

Send APIBeta

Send emails from your domain through the same infrastructure as SMTP credentials.

NOTE: Sending is a premium feature, and is for transactional email only. Marketing email is not supported and will get your account blocked.

Send emailBeta

POST /domains/:domain/emails/outbound

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/emails/outbound \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "from": "richard",
      "to": "gilfoyle@example.com",
      "subject": "Hello from the API",
      "text": "This is a plain text email sent via the ImprovMX API.",
      "html": "Hello! This is an HTML email sent via the ImprovMX API."
  }'
PARAMETER TYPE DESCRIPTION
from body Required. Local part of the sender address (e.g. richardrichard@piedpiper.com).
to body Required. Recipient(s). String or array of strings.
subject body Required*. Email subject. *Optional when template provides one. Supports Mustache variables.
text body Plain text body. Required (along with or instead of html) when template is not used.
html body HTML body. Required (along with or instead of text) when template is not used.
template body Name of a saved template. Its subject, html_body, and text_body are rendered with variables. Request-level text / html are ignored; subject overrides the template's.
variables body Mustache variable substitutions. Only used with template.
cc body CC recipient(s). String or array of strings.
bcc body BCC recipient(s). String or array of strings.
reply_to body Reply-To email address.
attachments body Each object needs filename and content (base64). Optional: content_type (inferred from filename) and content_id for inline CID images (e.g. <img src="cid:logo">). Max 25 attachments, 10 MB total. Executable extensions (exe, bat, js, vbs, ps1, scr, etc.) are blocked.

Response:

{
    "id": "20250330190000.a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
    "message_id": "<174336120000.1560119.13026979903154377804@piedpiper.com>"
}

Track delivery by looking up the returned id via Get email log (or find it in your domain's email logs) — it's the log entry's id (one entry per recipient). message_id is the message's RFC 5322 Message-ID, matching the logs message_id field.

Example: multiple recipients with CC and BCC

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/emails/outbound \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "from": "richard",
      "to": [
          "gilfoyle@example.com",
          "dinesh@example.com"
      ],
      "cc": [
          "jared@example.com"
      ],
      "bcc": [
          "bighead@example.com"
      ],
      "reply_to": "support@piedpiper.com",
      "subject": "Team update",
      "text": "Here is the latest update.",
      "html": "

Here is the latest update.

" }'

Example: sending with a template

Render a saved template with variables.

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/emails/outbound \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "from": "richard",
      "to": "gilfoyle@example.com",
      "template": "welcome",
      "variables": {
          "first_name": "Gilfoyle",
          "company": "Pied Piper"
      }
  }'

Example: sending with attachments

Pass each attachment with base64 content. content_type is inferred from the filename if omitted.

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/emails/outbound \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "from": "richard",
      "to": "gilfoyle@example.com",
      "subject": "Q4 Report",
      "text": "Please find the report attached.",
      "attachments": [
          {
              "filename": "report.pdf",
              "content": "JVBERi0xLjQg...",
              "content_type": "application/pdf"
          }
      ]
  }'

Example: inline image with content_id

Embed inline images via cid: references using content_id.

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/emails/outbound \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "richard",
    "to": "gilfoyle@example.com",
    "subject": "Check out our new logo",
    "html": "<p>Here is our logo:</p><img src=\"cid:logo\">",
    "attachments": [
      {
        "filename": "logo.png",
        "content": "iVBORw0KGgo...",
        "content_type": "image/png",
        "content_id": "logo"
      }
    ]
  }'

Error responsesBeta

CODE DESCRIPTION
400 Missing required fields - from, to, or subject is missing.
400 No body content - text or html is required.
400 Invalid email addresses - Invalid address in to, cc, bcc, or reply_to.
400 Invalid variables - variables must be a JSON object.
400 Invalid Mustache template - Malformed Mustache syntax in the template's subject or body.
400 Invalid attachment - Missing filename or content, invalid base64, invalid content_type, or attachments is not an array.
400 Blocked file type - Blocked extension (e.g. exe, bat, js, vbs, ps1, scr).
400 Attachment size limit - Over 10 MB total or more than 25 attachments.
403 Premium required - A premium plan is required to send emails via API.
403 Domain not configured for sending - The domain's DNS settings are not configured for sending. Visit https://app.improvmx.com/domains/:domain/dns to complete setup.
404 Domain not found - Not in your account.
404 Template not found - No template with that name on this domain.
429 Rate limited - Exceeded 10 requests/minute.

Send API TemplatesBeta

Save reusable templates per domain and reference them by name when sending. Subject and body support Mustache variables filled from the request's variables object.

Requires a premium plan. Up to 200 templates per domain.

NOTE: Templates are for transactional email only, not marketing campaigns.

Template objectBeta

{
    "name": "welcome",
    "description": "Welcome email for new signups",
    "subject": "Welcome, {{first_name}}!",
    "html_body": "<p>Hi {{first_name}}, welcome to {{company}}.</p>",
    "text_body": "Hi {{first_name}}, welcome to {{company}}.",
    "created_at": "2025-03-30T19:00:00Z",
    "updated_at": "2025-03-30T19:00:00Z"
}
PARAMETER TYPE DESCRIPTION
name String Required. Unique within the domain. Lowercase letters, numbers, hyphens, underscores; must start with a letter or number. Max 250 chars.
description String Description (max 500 chars).
subject String Default subject (max 250 chars). Supports Mustache.
html_body String HTML body (max 100,000 chars). Supports Mustache.
text_body String Plain text body (max 100,000 chars). Supports Mustache.

List templatesBeta

GET /domains/:domain/templates

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com/templates \
  -u "api:$API_KEY"

Returns summary fields (name, description, subject, created_at, updated_at) only. Fetch a single template to get its bodies.

{
    "templates": [
        {
            "name": "welcome",
            "description": "Welcome email for new signups",
            "subject": "Welcome, {{first_name}}!",
            "created_at": "2025-03-30T19:00:00Z",
            "updated_at": "2025-03-30T19:00:00Z"
        }
    ]
}

Get templateBeta

GET /domains/:domain/templates/:name

curl -X GET https://api.improvmx.com/v4/domains/piedpiper.com/templates/welcome \
  -u "api:$API_KEY"

Response:

{
    "template": {
        "name": "welcome",
        "description": "Welcome email for new signups",
        "subject": "Welcome, {{first_name}}!",
        "html_body": "<p>Hi {{first_name}}, welcome to {{company}}.</p>",
        "text_body": "Hi {{first_name}}, welcome to {{company}}.",
        "created_at": "2025-03-30T19:00:00Z",
        "updated_at": "2025-03-30T19:00:00Z"
    }
}

Create templateBeta

POST /domains/:domain/templates

curl -X POST https://api.improvmx.com/v4/domains/piedpiper.com/templates \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "name": "welcome",
      "description": "Welcome email for new signups",
      "subject": "Welcome, {{first_name}}!",
      "html_body": "

Hi {{first_name}}, welcome to {{company}}.

", "text_body": "Hi {{first_name}}, welcome to {{company}}." }'

Response:

{
    "template": {
        "name": "welcome",
        "description": "Welcome email for new signups",
        "subject": "Welcome, {{first_name}}!",
        "html_body": "<p>Hi {{first_name}}, welcome to {{company}}.</p>",
        "text_body": "Hi {{first_name}}, welcome to {{company}}.",
        "created_at": "2025-03-30T19:00:00Z",
        "updated_at": "2025-03-30T19:00:00Z"
    }
}

Error responses

CODE DESCRIPTION
400 Validation error - Missing name, invalid name format, field too long, or invalid Mustache syntax.
400 Template already exists - name is taken on this domain.
400 Limit reached - 200 templates per domain.
403 Premium required - Templates require a premium plan.
404 Domain not found - Not in your account.

Update templateBeta

PUT /domains/:domain/templates/:name

Only included fields are updated. Pass a new name to rename.

curl -X PUT https://api.improvmx.com/v4/domains/piedpiper.com/templates/welcome \
  -u "api:$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
      "subject": "Welcome to {{company}}, {{first_name}}!"
  }'

Response:

{
    "template": {
        "name": "welcome",
        "description": "Welcome email for new signups",
        "subject": "Welcome to {{company}}, {{first_name}}!",
        "html_body": "<p>Hi {{first_name}}, welcome to {{company}}.</p>",
        "text_body": "Hi {{first_name}}, welcome to {{company}}.",
        "created_at": "2025-03-30T19:00:00Z",
        "updated_at": "2025-03-30T19:05:00Z"
    }
}

Error responses

CODE DESCRIPTION
400 Validation error - Invalid name format, field too long, or invalid Mustache syntax.
400 Template already exists - New name is taken by another template.
404 Domain or template not found - Not in your account.

Delete templateBeta

DELETE /domains/:domain/templates/:name

curl -X DELETE https://api.improvmx.com/v4/domains/piedpiper.com/templates/welcome \
  -u "api:$API_KEY"

Returns 204 No Content on success.