DocumentationError codes

Error codes

HTTP error format and common causes.

Error responses follow a uniform JSON format:

{
  "statusCode": 403,
  "message": "Missing required API key scope: email:send",
  "path": "/emails/send",
  "timestamp": "2026-06-30T12:00:00.000Z"
}

HTTP codes

CodeMeaning
400Validation failed (required field, invalid email)
401Invalid or expired JWT or API key
403Insufficient scope, role, or unauthorized tenant
404Resource not found
409Conflict (duplicate, invalid state)
413Message too large (raw MIME > 10 MB)
422Business rule (e.g. suppressed recipient)
429Global rate limit or monthly quota exceeded

Application error codes

Every error response also carries a machine-readable code alongside the HTTP status. Common codes:

CodeMeaning
VALIDATION_ERRORA field failed validation (400)
HTML_BODY_REQUIREDNo html/htmlBody and no template given (400)
BATCH_LIMIT_EXCEEDEDMore than 100 recipients in one call (400)
HAS_EMAIL_HISTORYCan't delete a template version or project that has send history — logs are append-only (400)
TEMPLATE_NOT_FOUNDUnknown template slug or id (404)
TEMPLATE_NOT_PUBLISHEDThe template has no published version to send
EMAIL_TOO_LARGEThe built message exceeds the 10 MB limit (413)
QUOTA_EXCEEDEDMonthly email quota exceeded (429)

Quota exceeded (429)

When you exceed 110% of the monthly limit:

{
  "statusCode": 429,
  "message": "Monthly email quota exceeded (115%). Upgrade your plan to continue sending.",
  "quota": {
    "limit": 100,
    "used": 115,
    "percentage": 115
  }
}

Rate limit

In production: ~300 requests/minute per IP or JWT user (configurable). Headers:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1719763200

Public auth routes (/auth/login, /auth/register) have a stricter limit: 15 requests / 15 minutes.

SDK

The mailingcore-js package throws MailingCoreError with .status and .detail for client-side handling.