Skip to main content
email·digit
For developers

One POST to send.
Authentication handled.

Define the email once — write it, or generate the whole sequence from a description. Then your app fires a trigger and we deliver it, signed, from your domain. Test keys sandbox everything. Managed SPF, DKIM and DMARC on every plan, including free.

How it works

Two steps,
once.

01

Create the trigger

Give it a key like password_reset, write the email — or describe the sequence and edit what comes back — and declare the variables it takes. Do this in the dashboard or over the API.

02

Fire it from your app

One authenticated POST. 202 Accepted. That's the whole integration.

POST /api/transactional/send
# Fire the trigger — one authenticated POST
curl -X POST https://api.emaildigit.com/api/transactional/send \
  -H "Authorization: Bearer $ED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "trigger_key": "password_reset",
    "to": "ada@example.com",
    "variables": {
      "first_name": "Ada",
      "reset_url": "https://app.example.com/r/abc123"
    },
    "idempotency_key": "pwreset_8f21c"
  }'

# → 202 Accepted
{
  "trigger_key": "password_reset",
  "status": "enrolled",
  "mode": "live",
  "enrolled_steps": 1,
  "message_ids": ["9f2c1a4e-..."]
}

Why a trigger key instead of raw subject and HTML: the copy lives in one place instead of being compiled into your application. A non-engineer can fix a typo in your receipt email without a deploy, and a one-email reset can become a three-email onboarding sequence without you touching the call site. If you want the email to live in your code, send raw HTML through the same endpoint on a trigger with a single pass-through step.

Sandbox and production

Test keys sandbox everything.

Same endpoint, same payload — the key decides, so your staging environment cannot email a customer no matter what's in its database.

Test
ed_test_…

Records the send, renders the final HTML, delivers nothing. The result is labelled simulated, never delivered — because nothing was delivered.

Live
ed_live_…

Sends for real, from your verified domain. The key prefix tells you which one you're holding.

A test send runs the same pre-send evaluation the live path runs, so you see whether suppression would have stopped it. Test keys also work against draft triggers, so you can wire up an integration before the email is finished.

What you get

The boring infrastructure
you would have built anyway.

Idempotency, signing, retries, a searchable log. None of it email-specific cruft you have to wire up by hand.

Describe the sequence, get the whole thing

Live

“Onboard a trial signup to first value, then to paid.” That sentence produces a complete multi-step sequence with every subject and body written, on your brand, ready to edit. Steps fire on events you emit, not on a schedule you have to maintain.

Idempotency is a field, not a policy

Live

Pass idempotency_key and a replay returns the original result instead of sending again. Retry your queue as aggressively as you like.

Logs you can actually search

Live

Every send is a row: recipient, trigger, mode, status, subject, the variables you passed and the final rendered HTML. Filter by status, open one, read the delivery timeline, copy the payload as JSON, or resend a message that failed.

Webhooks, signed and retried

Live

Every delivery is HMAC-signed and retried on failure, with a delivery history you can inspect and replay.

Scoped tokens

Live

Tokens are per workspace and scoped — a send key can send and nothing else. Keys self-identify with an ed_live_ or ed_test_ prefix, so secret scanners catch an accidental commit.

The inbound half

Live

Replies to your app's email don't vanish into a no-reply mailbox. They arrive classified — what the person wants, how urgent, whether it carries risk — with a draft response you can approve. Anything flagged for review is draft-only and will not send on its own.

Receiving events

Verify the signature,
then dispatch.

Every event is HMAC-SHA256-signed over the timestamp and the raw body. Verify it, drop anything unsigned, dispatch on event type. Two of the most-deployed examples below — the same pattern in every other language.

POST /webhooks/email-digit
// Verify the X-Email-Digit-Signature header on inbound deliveries
import crypto from "crypto";
import express from "express";

const SECRET = process.env.ED_WEBHOOK_SECRET;

function verify(rawBody, header) {
  const [sigPart, tsPart] = header.split(",");
  const sig = sigPart.slice("sha256=".length);
  const ts = tsPart.slice("t=".length);
  // Reject anything older than 5 minutes (replay defense)
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = crypto
    .createHmac("sha256", SECRET)
    .update(ts + ".")
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

// IMPORTANT: use express.raw — JSON parsers re-serialize and break the MAC
app.post("/webhooks/email-digit",
  express.raw({ type: "application/json" }),
  (req, res) => {
    if (!verify(req.body, req.get("X-Email-Digit-Signature"))) {
      return res.status(401).send("invalid signature");
    }
    const event = JSON.parse(req.body.toString("utf8"));
    // dispatch on event.type
    res.status(200).send("ok");
  });
Event types

Subscribe to what happened.

Subscribe to all of them with *, or just the ones you need. Same payload envelope across every type.

email.sentAn outbound email is accepted for delivery.
email.bouncedAn outbound email fails at the sending layer.
reply.receivedA reply lands in the workspace, after classification.
suppression.createdAn address is added to the do-not-send list.
domain.verifiedA sending domain becomes verified.
automation.firedAn automation action ran for a contact.
whatsapp.receivedAn inbound WhatsApp message arrives.
sms.receivedAn inbound SMS arrives.
Managed authentication

Authentication you don't have
to become an expert in.

Publish three DNS records once — two CNAMEs and one TXT. Keys rotate on our side with a grace window, so nothing in flight breaks. DMARC walks from monitoring toward enforcement based on your actual alignment data. A new domain warms up on a graduated daily ceiling that only advances on healthy days.

Microsoft finished enforcing SPF, DKIM and DMARC for Outlook, Hotmail and Live in late 2025, and non-compliant mail is refused, not junked. If you've seen 550 5.7.26 or 550 5.7.15 Access deniedin your logs, that's this.

No per-domain fee for DMARC monitoring. No separate deliverability tier. It's on the free plan.

Honest notes

What isn't here.

The things you'd otherwise find out after you started building.

No client libraries. REST and a bearer token. curl, fetch, requests — whatever you already have.

Sending needs a verified domain. You can build and test before that; live delivery waits for the three records.

Rate limits are generous and unpublished.They exist to stop a runaway, not to shape normal use. We'll publish exact numbers alongside the response headers when those ship — the two arrive together, because a documented limit with no header to read is worse than no limit at all.

No card checkout yet. Free is instant; paid plans start with an email.

We don't compute a delivery score.Some tools show one. Ours would be a made-up number, so there isn't one.

FAQ

Things developers actually ask.

What can trigger a send?

An API event you post, or a contact action inside the platform — segment entry, a tag, a reply, a date field.

Are there SDKs?

No. A REST API and webhooks. Client libraries aren't built, and we'd rather say that than publish an install line for a package that doesn't exist.

How do I stop a send to someone who complained?

You don't have to. Suppression is checked on every send, and complaint-driven suppression blocks every stream, including your app's email.

Can I use my own domain?

Yes — three DNS records, published once, and we handle signing from then on.

Get started

Read the docs.
Then get a test key.

Test keys deliver nothing and sandbox everything, so you can build the whole integration before a single email leaves the building.