Base URL
https://app.dmu.email/api/v1
Authentication
Bearer dmk_… API key
Rate limit
120 requests a minute per key

Errors

Every failure has the same shape: an HTTP status, and a code that says what went wrong. Switch on the code.

The shape

Response

{
  "error": {
    "code": "bad_cursor",
    "message": "Pass the `nextCursor` from the previous page unchanged."
  }
}

The message is written for a person reading a log, and its wording may change. The code won’t. Each endpoint’s page lists the codes it can give.

Statuses

What each status means

400bad_json, bad_limit…
The request was wrong: a body that isn’t JSON, a limit out of range, an unknown view, a bad cursor.
401invalid_key
No key, or a key that’s unknown, revoked or expired.
403missing_scope…
The key lacks the permission, its owner isn’t allowed to do this, or the plan has no API (plan_no_api).
404not_found
There’s no such thing, or it exists and the key can’t see it.
409draft_locked…
It clashes with how things are: someone is editing the draft, the mail has already gone, the name is taken.
423organisation_deleting
The organisation is waiting to be deleted.
429rate_limited
Too many requests. See Rate limits.

Not found, on purpose

A 404 also covers “it exists, but this key can’t see it”. Answering 403 there would confirm the id is real, which is exactly what makes guessing ids worth trying.

Retrying

  • Sending a draft twice sends it once. The second call returns the same result with alreadySent: true.

  • Deleting something that’s already gone succeeds, so a retry after a lost response doesn’t read as a failure.

  • Creating a draft twice makes two drafts. Neither is sent until you send it.

  • After a 429, wait for the Retry-After seconds before trying again.