comms
email live whatsapp soon

One API. Email and WhatsApp.

One contract for transactional messaging. Email ships today, WhatsApp on the same wire format soon. Multi-provider fallback and retries live in the request, not the docs.

No card. No waitlist. / 15-minute integration.

POST /v1/messages/email
curl https://api.comms.ndcoders.com/v1/messages/email \
  -H "x-api-key: $COMMS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sender":      { "fromAddress": "billing@your-app.com" },
    "destination": { "to": ["alex@startup.io"] },
    "content": {
      "type":    "raw",
      "subject": "Receipt #2891",
      "body":    "Thanks for your payment."
    }
  }'

one request shape. two channels. zero glue code.

what's in the wire

Reliability is a contract,
not a brag.

Six capabilities the API guarantees. None of them are upsells, none of them are hidden behind a flag.

  1. Two channels, one contract.

    Email and WhatsApp share the same envelope, the same response, and the same record shape.

  2. Provider fallback chain.

    Configured per channel. Primary times out, the next provider takes the request, the response says which.

  3. Scheduled sends.

    Pass ISO 8601 in the payload. The engine holds the message until then and dispatches without a worker on your side.

  4. Read your messages back.

    GET a message by ID, or page your sends filtered by channel, status, and time. Scoped to your API key.

  5. Per-attempt timing and errors.

    Every provider try is recorded: duration, status, error category. Debugging is a GET request, not a Slack thread.

  6. 90-day delivery log.

    Searchable by message ID, app, channel, status, and time. Replay a delivery without re-running the producer.

one path, two channels

Your app speaks to one endpoint.
The engine speaks to every provider.

The orchestrator owns rate limiting, retry budgets, circuit-breaker state, and the fallback chain. You ship the message; we ship the delivery.

Request flow from your app to the recipient Your app sends to the Comms API, which routes through the orchestrator to one of two channels, email or WhatsApp, and out to the recipient. your app comms api orchestrator email whatsapp recipient
fig 1. request path. one endpoint, one orchestrator, two channels, one recipient.
GET /v1/messages/5f1d8c2e-9b3a-4c7e-8f1a-2d6b9e0c4a71 200 ok
{
  "messageId":   "5f1d8c2e-9b3a-4c7e-8f1a-2d6b9e0c4a71",
  "channel":     "EMAIL",
  "status":      "DELIVERED",
  "destination": { "to": ["alex@startup.io"] },
  "content":     { "type": "raw", "subject": "Receipt #2891", "body": "Thanks for your payment." },
  "createdAt":   "2026-05-26T15:10:31.991Z",
  "updatedAt":   "2026-05-26T15:10:41.029Z",
  "attempts": [
    {
      "provider":      "ses-primary",
      "status":        "RETRYING",
      "errorCategory": "PROVIDER_OUTAGE",
      "durationMs":    8120,
      "timestamp":     "2026-05-26T15:10:32.404Z"
    },
    {
      "provider":   "ses-fallback",
      "status":     "DELIVERED",
      "durationMs": 412,
      "timestamp":  "2026-05-26T15:10:40.617Z"
    }
  ]
}

show, don't preach

Every retry is in the response.

The same record powers the dashboard, the list endpoint, and the API response. When the primary engine times out, the chain falls through to the fallback, and the message lands. The failed attempt isn't hidden; it's part of the message.

  • attempts[] is ordered. Position is chronology.
  • Six normalized errorCategory values across every engine.
  • Persisted for 90 days. Searchable by anything in the record.

why one api

Most apps send across three channels, billed by three vendors, debugged in three dashboards. Comms is one API, one bill, one log. You stop integrating; we stop you from caring which provider actually sent it.

Switching providers is a config change, not a rewrite. Adding a fourth channel is a config change, not a project. The boring part of comms infrastructure stays boring.

ready when you are

Send your first message in fifteen minutes.

No card. No waitlist. The API key is one click away.