Developers
A small API surface you can trust
Everything speaks JSON over HTTPS at https://api.mail.mirnint.com/v1, documented with OpenAPI 3.1. Accepted means durably stored — delivery truth arrives as events.
Endpoints
The surface area
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/emails | Send an email or a template send — returns 202 once durably stored |
| GET | /v1/emails/{id} | Message metadata, per-recipient states and derived status |
| GET | /v1/emails/{id}/events | Cursor-paginated lifecycle events |
| POST | /v1/emails/{id}/cancel | Cancel a scheduled message before MTA submission |
| POST | /v1/contact-submissions | Restricted contact-form intake with server-side routing |
Authentication is a project-scoped bearer key (mm_live_… / mm_test_…). Test keys can only send to approved recipients.
Webhooks
Events you can verify
Every webhook is HMAC-SHA-256 signed over the webhook ID, timestamp and raw body. Reject stale timestamps, deduplicate by event ID, and you're immune to replay.
- email.accepted
- email.queued
- recipient.submitted_to_mta
- recipient.deferred
- recipient.remote_accepted
- recipient.soft_bounced
- recipient.hard_bounced
- recipient.complained
- recipient.suppressed
- email.completed
// Verify a webhook before trusting it
const canonical = [
req.headers["mirnint-webhook-id"],
req.headers["mirnint-webhook-timestamp"],
rawBody,
].join(".");
const expected = "v1=" + hmacSha256(secret, canonical);
if (!timingSafeEqual(expected,
req.headers["mirnint-webhook-signature"])) {
return res.status(401).end();
}
// Reject stale timestamps, dedupe by event id
handle(JSON.parse(rawBody));
// { "type": "recipient.remote_accepted", ... }Error handling
Failures are part of the contract
Stable error codes, request IDs on every response, and idempotency that makes retries safe. Ambiguity is designed out: an SDK never blindly re-sends after a timeout without the same idempotency key.
SDKs
TypeScript · Java · PHP · Python — generated from the OpenAPI spec with typed errors and sensible timeouts.
Rate-limit headers
Documented headers on every response, with independent limits per key, project and organization.
Content limits
Explicit maximum body and attachment sizes, enforced before queueing — including Base64 expansion.
HTTP/1.1 422 Unprocessable Entity
{
"error": {
"code": "DOMAIN_NOT_VERIFIED",
"message": "The selected sending domain
is not verified.",
"request_id": "req_01J9X4M2",
"details": { "domain_id": "dom_01J9X4" }
}
}