Developer docs

Cyphex Email API

Send email from your own software, from your own domain, with one HTTP request. This is everything you need: how to connect, what the limits are, how errors work, and the rules that keep sending healthy for everyone.

Overview

The API sends email through Cyphex. You verify a domain you own, create a sender address on it and an API key, and your software posts a JSON message to one endpoint. Mail is signed for your domain, so recipients see your brand, not ours.

Base URLhttps://api.cyphex.tech
EndpointPOST /v1/emails
FormatJSON in, JSON out, UTF-8
AuthenticationBearer API key (cm_live_...)
Server side onlyNever put a key in a browser page or a mobile app

Quickstart

  1. Get access. Apply for an API plan. We review every application, usually within one business day.
  2. Add your domain in your dashboard and publish the DNS records we show you (see Domains and senders). Wait until it shows as verified.
  3. Create a sender address on that domain, for example orders@yourdomain.com.
  4. Create an API key under Developers. It is shown once: store it as a secret, for example the environment variable CYPHEX_API_KEY.
  5. Send a test to your own address:
curl -sS -X POST https://api.cyphex.tech/v1/emails \
  -H "Authorization: Bearer $CYPHEX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Shop <orders@yourdomain.com>",
    "to": "buyer@example.com",
    "subject": "Order 1042 confirmed",
    "html": "<p>Thanks for your order!</p>",
    "text": "Thanks for your order!"
  }'

A successful call answers 200 with { "id": "<message id>" }. Open the message in the failed-send log later if you ever need to trace it.

Authentication

Send your key in the Authorization header on every request:

Header
Authorization: Bearer cm_live_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
  • Keys start with cm_live_. They are stored only as a hash on our side, so we cannot show a key again. Lost key: create a new one and revoke the old one.
  • One key belongs to one account. It can only send as that account's own sender addresses.
  • Use one key per project and environment (for example shop-prod and shop-staging) so you can revoke one without touching the others.
  • Rotate by creating the new key, deploying it, then revoking the old one. Revoking is immediate.
  • The number of keys depends on your plan: 3 on API Start, 5 on API Growth, 10 on API Only and Enterprise.

Send an email

POST /v1/emails accepts one message per request. Put several people in to, cc or bcc to send the same message to all of them (up to 50 recipients in total).

FieldTypeRequiredNotes
fromstringyesA sender address of your account, with an optional name: Shop <orders@yourdomain.com>
tostringyesOne address, or several in one string separated by commas
ccstringnoVisible copy recipients
bccstringnoHidden recipients: they receive the mail but are never shown in any header
subjectstringyesPlain text
html / textstringone requiredSend both for best delivery: some inboxes prefer plain text
attachmentsarraynoUp to 10 files. Each: filename, mimeType, content (base64), max 10 MB each
A fuller example
{
  "from": "Billing <billing@yourdomain.com>",
  "to": "client@example.com, accounts@example.com",
  "cc": "manager@example.com",
  "bcc": "archive@yourdomain.com",
  "subject": "Invoice 1042",
  "html": "<p>Your invoice is attached.</p>",
  "text": "Your invoice is attached.",
  "attachments": [
    { "filename": "invoice-1042.pdf", "mimeType": "application/pdf", "content": "<base64 of the file>" }
  ]
}

Recipients are merged and de-duplicated across to, cc and bcc. The count of distinct recipients is what counts toward your limits.

ResponseBody
200{ "id": "<message id>" }
4xx / 5xx{ "error": "Human readable message", "code": "stable_code" }

Errors

Every error has a code. Match on the code, never on the message text: messages can be reworded, codes stay.

HTTPCodeMeaningWhat to do
400invalid_jsonThe body is not valid JSON, or not a JSON object.Fix the request. Do not retry unchanged.
400invalid_requestA required field is missing: from, to, subject, and html or text.Fix the request.
400invalid_recipientsNo valid address in to, or more than 50 recipients in to, cc and bcc together.Send fewer recipients per request.
400too_many_attachmentsMore than 10 attachments.Send fewer files, or link to them.
401invalid_api_keyThe Authorization header is missing or is not a Bearer cm_live_ key.Check the header.
401api_key_not_foundThe key does not exist (revoked or mistyped).Create a new key.
401account_deactivatedThe user that owns the key is deactivated.Contact your administrator.
403forbidden_roleOnly administrators and sender addresses can send with the API.Create the key from an allowed account.
403from_not_allowedThe From address is not one of your sender addresses.Use a verified sender of your own domain.
403plan_limitYour plan or account status stops this send (for example a suspended account or a plan cap).Check your plan, or contact us.
413attachment_too_largeAn attachment is over 10 MB.Compress it or send a link.
429rate_limited_minuteMore than 120 requests a minute with this key.Wait for the Retry-After seconds, then retry.
429rate_limited_dayThe key's daily email limit was reached.Wait for Retry-After, or ask for a higher limit.
500send_failedOur mail system could not send it.Retry with backoff. Contact us if it repeats.

A 429 always carries a Retry-After header in seconds. Refused and failed sends are recorded for 30 days (no message content) and shown in your dashboard under “Failed or refused sends”, so you can debug without contacting us.

Limits and plans

LimitValue
Requests per key120 per minute
Emails per key5,000 per day, counted in recipients (to + cc + bcc, de-duplicated)
Recipients per request50
Attachments per request10 files, 10 MB each
Plan daily capAPI Start 1,250 a day, API Growth 5,000 a day, API Only by agreement
API keys per account3 (Start), 5 (Growth), 10 (API Only and Enterprise)
Included volumeAPI Start 25,000 a month, API Growth 100,000 a month

The per-key limits protect everyone's sending reputation. The plan cap is the stricter of the two for small plans. Need more? Ask us: higher limits are agreed together with your price. See plans and pricing.

Domains and senders

You can only send from a domain you have verified, and only as a sender address that exists in your account. Anything else is refused with 403 from_not_allowed.

  1. Add the domain in your dashboard. We show the DNS records to publish.
  2. DKIM: three CNAME records. They sign your mail so it is trusted.
  3. SPF and custom return path: an MX and a TXT record on a subdomain such as mail.yourdomain.com, so inboxes show your domain and not ours.
  4. DMARC: a TXT record on _dmarc.yourdomain.com. Start with p=none, move to quarantine after a clean week.
  5. Press check. When the domain shows verified, create your sender addresses.

DNS changes can take from a few minutes to a few hours to be visible. Use a separate sender per purpose (orders@, security@, news@): it keeps filtering and reputation clean.

Sending rules

These rules are part of our Acceptable-use policy. They exist so that mail from every customer reaches the inbox.

  • Send only to people who agreed to receive your email. No purchased, rented or scraped lists.
  • Marketing or bulk mail must carry a working unsubscribe link, and you must honour it quickly.
  • Keep hard bounces under 2% and spam complaints under 0.05%. Beyond that, sending is paused automatically and you are asked to review your list.
  • Do not send phishing, malware, deceptive or illegal content, or mail that hides who you are.
  • Do not share a key between unrelated businesses or resell access to it.
  • New domains start slowly: raise your volume over a few weeks, not in one day.

We watch bounce and complaint rates automatically. A pause is lifted once the cause is fixed. Repeated or serious breaches can end the agreement.

Best practices

  • Send from a queue, not inside a user's web request. A slow or failed send should never block your page.
  • Retry only what can succeed: 429 and 5xx, with waiting between tries. Never retry a 4xx unchanged.
  • Avoid duplicates. There is no idempotency key yet, so store your own “already sent” flag per business event before retrying.
  • Spread bulk sends over time instead of one burst, and stay under the per-minute limit.
  • Send both HTML and text, keep the subject honest, and use a real reply address.
  • Test with your own inboxes (Gmail and Outlook) and check the headers show spf=pass dkim=pass dmarc=pass for your domain.
  • Watch the failed-send log after your first real traffic and set an alert on repeated 403 or 429.
Retry with waiting (Node.js)
// Retry only 429 and 5xx. Never retry a 4xx: the request itself is wrong.
async function sendWithRetry(mail, tries = 4) {
  for (let i = 0; i < tries; i++) {
    try { return await sendMail(mail); }
    catch (e) {
      if (!e.retryable || i === tries - 1) throw e;
      const wait = e.retryAfter ? e.retryAfter * 1000 : 1000 * 4 ** i;   // 1 s, 4 s, 16 s
      await new Promise((r) => setTimeout(r, wait));
    }
  }
}

Security

  • All traffic is HTTPS. Requests over plain HTTP are refused.
  • Keep keys in environment variables or a secrets manager. Never commit them to Git or ship them in a browser or mobile app.
  • If a key may have leaked, revoke it at once and create a new one. Revoking takes effect immediately.
  • Only administrators and dedicated sender addresses can use the API. Deactivating a user stops their keys.
  • We do not store your message bodies for API sends beyond a short retention period used for the sent log.

Not available yet

We would rather tell you than let you find out. These are planned and not part of the API today:

  • Delivery, bounce and complaint webhooks
  • Inbound email: receiving replies into your software
  • An Idempotency-Key header and a message status lookup
  • A versioned address (/v1) and a dedicated API hostname
  • IP allow-lists for keys

Tell us which one you need first: it decides what we build next.

Changelog

  • November 2026. The API now has its own host, api.cyphex.tech, with the stable path POST /v1/emails. The old address https://mail.cyphex.agency/api/emails/send keeps working; new integrations should use the new one.
  • November 2026. Every error now carries a stable code. bcc recipients are delivered and counted toward limits. Per-key limits of 120 requests a minute and 5,000 emails a day. Invalid JSON answers 400 instead of 500.

Support

Human support in your time zone: email support@cyphex.agency or message us on WhatsApp. Our SLA targets 99.5% availability. When you write, include the time of the request and the code you received, never your key.