Custom domains

Bring your own domain and receive mail at any address @yourdomain. Custom domains are shared between the API and the webapp dashboard — a domain added here appears in the dashboard immediately, and vice-versa.

Requires: Growth ($49/mo) or Enterprise ($149/mo) plan.

Workflow

  1. POST /v1/custom-domains — add the domain, receive the two DNS records.
  2. Add the MX and TXT records at your registrar.
  3. POST /v1/custom-domains/{domain}/verify — confirm DNS propagation.
  4. POST /v1/inboxes with any user@yourdomain — start receiving mail.

DNS propagation can take up to 48 hours. Most providers update within minutes.

GET /v1/custom-domains

Returns all custom domains on your account with their verification status and the DNS records needed to verify them.

curl
curl "https://api2.freecustom.email/v1/custom-domains" \
  -H "Authorization: Bearer fce_your_api_key"

Responses

200Success

json
{
  "success": true,
  "count": 2,
  "data": [
    {
      "domain": "mail.acme.com",
      "verified": true,
      "mx_record": "mx.freecustom.email",
      "txt_record": "freecustomemail-verification=a1b2c3d4e5f6...",
      "added_at": "2026-01-15T10:00:00.000Z"
    },
    {
      "domain": "staging.acme.com",
      "verified": false,
      "mx_record": "mx.freecustom.email",
      "txt_record": "freecustomemail-verification=9z8y7x6w5v4u...",
      "added_at": "2026-03-10T08:30:00.000Z"
    }
  ]
}

403Plan too low

json
{
  "success": false,
  "error": "plan_required",
  "message": "Custom domains require Growth ($49/mo) or Enterprise ($149/mo) plan.",
  "upgrade_url": "https://freecustom.email/api/pricing"
}

POST /v1/custom-domains

Adds a new domain and returns the two DNS records to configure at your registrar. This call is idempotent — if the domain is already added it returns the existing entry with 200. Maximum 10 custom domains per account.

curl
curl -X POST "https://api2.freecustom.email/v1/custom-domains" \
  -H "Authorization: Bearer fce_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "mail.acme.com" }'

Responses

201Domain added

json
{
  "success": true,
  "message": "Domain added. Configure the DNS records below, then call the verify endpoint.",
  "data": {
    "domain": "mail.acme.com",
    "verified": false,
    "mx_record": "mx.freecustom.email",
    "txt_record": "freecustomemail-verification=a1b2c3d4e5f6...",
    "added_at": "2026-03-11T12:00:00.000Z",
    "dns_records": [
      { "type": "MX",  "hostname": "@", "value": "mx.freecustom.email", "priority": "10", "ttl": "Auto" },
      { "type": "TXT", "hostname": "@", "value": "freecustomemail-verification=a1b2c3d4e5f6...", "ttl": "Auto" }
    ],
    "next_step": "POST /v1/custom-domains/mail.acme.com/verify"
  }
}

400Limit reached

json
{
  "success": false,
  "error": "limit_reached",
  "message": "Maximum of 10 custom domains reached."
}

400Invalid domain

json
{
  "success": false,
  "error": "invalid_domain",
  "message": "Must be a valid domain name (e.g. \"mail.yourdomain.com\")."
}

POST /v1/custom-domains/{domain}/verify

Triggers a live DNS lookup for the domain's MX and TXT records. Call this after adding the records at your registrar. If it fails, the response tells you exactly which record is missing so you know what to fix.

TypeHostValuePriority
MX@mx.freecustom.email10
TXT@freecustomemail-verification=<token>

The <token> is the value returned in txt_record when you added the domain. It is unique per domain + account.

curl
curl -X POST "https://api2.freecustom.email/v1/custom-domains/mail.acme.com/verify" \
  -H "Authorization: Bearer fce_your_api_key"

Responses

200Verified

json
{
  "success": true,
  "verified": true,
  "message": "Domain \"mail.acme.com\" verified successfully. You can now register inboxes at @mail.acme.com.",
  "data": {
    "domain": "mail.acme.com",
    "verified": true,
    "mx_record": "mx.freecustom.email",
    "txt_record": "freecustomemail-verification=a1b2c3d4e5f6...",
    "added_at": "2026-03-11T12:00:00.000Z"
  }
}

422DNS records not found yet

json
{
  "success": false,
  "verified": false,
  "error": "verification_failed",
  "message": "TXT record \"freecustomemail-verification=a1b2c3d4e5f6...\" not found.",
  "hint": "DNS propagation can take up to 48 hours.",
  "dns_records_needed": [
    { "type": "MX",  "hostname": "@", "value": "mx.freecustom.email", "priority": "10" },
    { "type": "TXT", "hostname": "@", "value": "freecustomemail-verification=a1b2c3d4e5f6..." }
  ]
}

404Domain not added yet

json
{
  "success": false,
  "error": "domain_not_found",
  "message": "\"mail.acme.com\" not found. Add it first via POST /v1/custom-domains."
}

DELETE /v1/custom-domains/{domain}

Permanently removes a custom domain from your account. All API inboxes registered at @{domain} are automatically unregistered and listed in inboxes_removed. The domain is also removed from the webapp dashboard.

curl
curl -X DELETE "https://api2.freecustom.email/v1/custom-domains/mail.acme.com" \
  -H "Authorization: Bearer fce_your_api_key"

Responses

200Removed

json
{
  "success": true,
  "message": "\"mail.acme.com\" removed.",
  "inboxes_removed": [
    "support@mail.acme.com",
    "noreply@mail.acme.com"
  ]
}

404Not found

json
{
  "success": false,
  "error": "domain_not_found",
  "message": "Domain \"mail.acme.com\" not found in your account."
}