Documentation

Public docsYou can read this page without an account. Links to paths like /domains or /api-keys go to the dashboard and require signing in. For common questions, see the FAQ; for policies, see Legal.

ZidiMail is a transactional email platform: verify your domain, create API keys, send mail over HTTPS, and receive delivery webhooks. This page describes the customer dashboard and the public HTTP API your applications call.

API origin:https://api.zidimails.com·Versioned prefix:/v1

Overview

The stack has two surfaces you care about: the dashboard (browser UI at your app URL) for domains, keys, billing, and logs; and the REST API at https://api.zidimails.com/v1 for sending and querying from servers.

  • Sending uses an API key (POST /v1/emails) so only backend services hold secrets.
  • Dashboard session uses a JWT stored in the zm_token cookie after login; many read endpoints accept either JWT or API key via the same Authorization: Bearer header.
  • Inbound provider hooks (/inbound/ses, /inbound/mailgun) are internal — not for customer use.

Quick start

  1. Create an account and confirm your email if prompted.
  2. Open Domains, add your sending domain, and add the DNS records shown (SPF, DKIM, DMARC as applicable). Use Verify until the domain is verified.
  3. Open API Keys, create a key, and copy the full secret once — it is shown only at creation time.
  4. Call POST https://api.zidimails.com/v1/emails from your server with Authorization: Bearer <full key>.
  5. Optionally configure Webhooks for delivery events.

Dashboard areas

Emails

Searchable log of sent messages, statuses, and per-email detail.

Domains

Add domains, copy DNS records, run verification, remove domains.

API Keys

Create and revoke keys. Full key secret is shown only once.

Webhooks

Register HTTPS endpoints, choose events, copy signing secret once.

Analytics

Charts and delivery metrics driven by /v1/emails/stats.

Billing

Plan upgrades (PayPal subscription flow) and quota context.

Settings

Organization and account preferences; account deactivation flows.

Operators with admin privileges also see an Admin entry for internal tooling (JWT required, separate from API keys).

Authentication

Send Authorization: Bearer <token> on every request to /v1/*.

API key (server-to-server)

Keys look like zm_live_<id>_<secret>. Use them for automation and for POST /v1/emails (sending always requires an API key). Store keys in environment variables or a secrets manager — never in frontend code.

curl https://api.zidimails.com/v1/emails \
  -H "Authorization: Bearer zm_live_<keyId>_<secret>"

Session JWT (dashboard)

After login, the UI stores a JWT in the zm_token cookie. The same token can be passed as Bearer for endpoints that use requireAuth (JWT or API key). Endpoints that require requireJwt accept only the dashboard JWT — for example creating API keys and managing PayPal billing.

CORS is restricted to APP_URL on the API. Call the REST API from your backend, or from the dashboard origin as the app already does.

Send an email

POST{origin}/v1/emails

Requires an API key (not JWT alone). The from address must use a domain that is verified for your organization.

Request body

fromrequired
string
Sender email; domain must match a verified domain.
torequired
string | string[]
Recipient(s).
subjectrequired
string
Subject line (max 998 chars per RFC).
html
string
HTML body. At least one of html or text is required.
text
string
Plain-text body.
cc
string | string[]
CC recipients.
bcc
string | string[]
BCC recipients.
reply_to
string
Reply-To address.
headers
Record<string,string>
Custom headers (key-value).
tags
{ name, value }[]
Optional metadata tags (for your own analytics pipelines).

Example

curl -X POST https://api.zidimails.com/v1/emails \
  -H "Authorization: Bearer zm_live_your_full_key" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "hello@yourdomain.com",
    "to": "user@example.com",
    "subject": "Welcome",
    "html": "<p>Thanks for signing up.</p>",
    "text": "Thanks for signing up."
  }'

Response

{
  "id": "<nanoid>",
  "warning": "Optional — some recipients skipped (suppression list)"
}

List & get emails

GET{origin}/v1/emails

List recent messages for the organization. Accepts JWT or API key.

limit
number
1–100, default 50.
page
number
Page index, default 1.
search
string
Filters by recipient substring, subject, or from.
curl "https://api.zidimails.com/v1/emails?limit=20&page=1" \
  -H "Authorization: Bearer <jwt_or_api_key>"

Get one email

GET{origin}/v1/emails/:id

Returns the email row plus related delivery events when present.

curl https://api.zidimails.com/v1/emails/<id> \
  -H "Authorization: Bearer <jwt_or_api_key>"

Analytics & stats

GET{origin}/v1/emails/stats

Aggregates sent volume and rates for the org. Accepts JWT or API key.

days
number
Lookback window, capped at 90, default 30.

Response includes totals, counts by status, daily buckets, and computed delivery / bounce / complaint rates. The dashboard Analytics page consumes this endpoint.

curl "https://api.zidimails.com/v1/emails/stats?days=30" \
  -H "Authorization: Bearer <jwt_or_api_key>"

Domains API

All routes require JWT or API key via Bearer auth.

Add domain

POST{origin}/v1/domains
domainrequired
string
Hostname, e.g. mail.example.com or example.com.

Returns id, domain, and dns_records for SPF/DKIM/DMARC and Mailgun-aligned records.

List domains

GET{origin}/v1/domains

Get domain

GET{origin}/v1/domains/:id

Includes merged DNS guidance and verification flags after checks.

Verify DNS

POST{origin}/v1/domains/:id/verify

Re-runs SPF/DKIM (and related) checks and updates stored verification. Response includes checks and verified when SPF and DKIM pass.

Remove domain

DELETE{origin}/v1/domains/:id

API keys API

Creating and revoking keys requires a JWT (dashboard session), not an API key alone — so compromised automation keys cannot mint new keys.

Create key

POST{origin}/v1/api-keys
namerequired
string
Display label (1–100 chars).

Response includes key once: zm_live_<id>_<secret>. Save it immediately; only the prefix is listed afterward.

List keys

GET{origin}/v1/api-keys

Revoke key

DELETE{origin}/v1/api-keys/:id

Webhooks API

Register HTTPS URLs to receive JSON notifications when delivery events occur. Requires JWT or API key for management routes.

Create webhook

POST{origin}/v1/webhooks
urlrequired
string (URL)
Must be a valid https URL.
eventsrequired
string[]
Non-empty subset of: email.sent, email.delivered, email.bounced, email.complained, email.opened, email.clicked.

Response returns secret once (prefix whsec_) — used to verify ZidiMail-Signature on deliveries.

List webhooks

GET{origin}/v1/webhooks

Secrets are omitted from list responses.

Delete webhook

DELETE{origin}/v1/webhooks/:id

Webhook signatures

Each delivery is a POST with body signed using HMAC-SHA256 and the webhook secret.

  • Header ZidiMail-Signature: sha256=<hex> — HMAC of the raw JSON body.
  • Header ZidiMail-Event — same string as type in the JSON payload.

Payload shape

{
  "type": "email.delivered",
  "created_at": "2026-05-13T12:00:00.000Z",
  "data": {
    "email_id": "...",
    "to": ["user@example.com"],
    "from": "hello@yourdomain.com",
    "subject": "Welcome"
  }
}

Verify by recomputing HMAC-SHA256 of the exact request body bytes with your webhook secret and comparing to the header (constant-time compare recommended).

Sandbox mode & ZidiGuard

Sandbox

Organizations in sandbox mode may only send to the org owner's registered email. Attempts to reach other recipients return 403 with guidance to contact support for production activation.

ZidiGuard (suppressions)

Addresses that hard-bounced or complained are suppressed. If every recipient in a send is suppressed, the API returns 422 and does not consume quota for those recipients. Partial suppression adds a warning in the send response.

Billing & plans

The dashboard Billing flow uses PayPal subscriptions (/billing/subscribe and related routes) with JWT auth. Plan tiers adjust monthly and daily sending limits (see table below).

Exact PayPal plan IDs and webhook verification are server-side; integrate billing only through the dashboard unless you are extending the API intentionally.

HTTP errors

Errors return JSON with at least error and often message and action for remediation.

401

Unauthorized

Missing/invalid Bearer token or malformed API key.

403

Forbidden

Sandbox restriction, or account suspended.

404

Not found

Unknown email or domain id.

409

Conflict

e.g. domain already added.

413

Payload too large

Global body limit 2 MB (appeals endpoint allows more).

422

Unprocessable

Validation, unverified domain, or all recipients suppressed.

429

Rate limited

Burst, daily, monthly, warm-up, or IP limits.

500

Server error

Unexpected failure — retry with backoff or contact support.

Example body

{
  "error": "Domain \"example.com\" is not verified.",
  "message": "Your sending domain must pass SPF/DKIM verification...",
  "action": "Visit your ZidiMail dashboard → Domains → verify your DNS records."
}

Rate limits

Multiple layers apply: per-IP limits on the API (e.g. login/register stricter than global traffic), per-org burst and “slow start” for new accounts, and plan daily/monthly quotas.

LimitFreeProScale
Monthly emails3,00030,00065,000
Daily emails250UnlimitedUnlimited
Burst rate2/secUnlimitedUnlimited
OverageHard stop$1.50 / 1k$1.60 / 1k

Monthly quota resets on the 1st of each month (UTC). When blocked, expect 429 with an explanatory message.

Security notes

  • API keys and webhook secrets are high-privilege — rotate if leaked.
  • The API sets strict security headers (HSTS, frame denial, nosniff, referrer policy).
  • JWTs gate dashboard operations; sending requires API keys so browser extensions cannot steal send capability from cookies alone if keys stay server-side.
  • Verify webhook signatures before trusting events; reject replayed or tampered bodies.