Emalc

Search Documentation

Quickly jump to any guide, document, or section...

Errors & Rate Limits

The Emalc Public Email API uses standard HTTP response codes to indicate the success or failure of API requests.


Standard Error Response Format#

All 4xx and 5xx error responses return a standardized JSON body:

json
{
  "error": "ERROR_CODE",
  "message": "Human readable summary of why the request failed.",
  "issues": []
}
  • error (string): Machine-readable uppercase error string.
  • message (string): Detailed explanation of the error.
  • issues (array, optional): Populated when error is VALIDATION_ERROR (400), containing Zod path-level schema validation errors.

HTTP Status & Error Code Matrix#

StatusError CodeDescription & Required Remediation
400VALIDATION_ERRORRequest body failed schema validation. Check issues array for invalid fields or types.
400BAD_REQUESTMalformed JSON body, invalid sender email, or non-UUID path parameter.
401UNAUTHORIZEDAPI key is missing, malformed, or inactive. Verify Authorization: Bearer em_* header.
402INSUFFICIENT_CREDITSNeither subscription quota nor wallet balance has credits available. Top up in dashboard.
403FORBIDDENKey lacks required scope (email:send or email:read).
403DOMAIN_NOT_ALLOWEDSender domain is prohibited by API key's domain_scope setting.
403DOMAIN_NOT_FOUNDSender domain is not registered in your organization.
403DOMAIN_NOT_VERIFIEDSender domain DNS / DKIM verification is incomplete.
404NOT_FOUNDThe requested emailId does not exist or belongs to another organization.
422ALL_RECIPIENTS_SUPPRESSEDAll recipient emails in to are on your organization's suppression list.
429RATE_LIMIT_EXCEEDEDExceeded per-second (2 req/s) or daily (5,000 req/day) limit. Read Retry-After header.
500SEND_FAILEDInternal delivery failure. Credits for failed sends are automatically refunded.

Rate Limits & Capacity#

Rate limits are enforced per organization:

  • Per-Second Limit: 2 HTTP requests / second
  • Daily Request Limit: 5,000 HTTP requests / day (Resets daily at 00:00:00 UTC).
  • Total Daily Delivery Capacity: 5,000 emails / day per organization.

Recipients Batching Note: Sending to up to 10 recipients in a single POST /api/public/email/send call (e.g. to: ["a@acme.com", "b@acme.com", ...]) counts as 1 API request toward your 5,000 daily limit.


Rate Limit Response Headers#

Every API response includes rate limit telemetry headers:

HeaderDescription
X-RateLimit-LimitMaximum allowed requests in current window (2 or 5000).
X-RateLimit-RemainingRemaining requests available in current window.
X-RateLimit-ResetSeconds remaining until the current window resets.
Retry-AfterSent on 429 RATE_LIMIT_EXCEEDED. Seconds to pause before retrying.

Handling 429 Rate Limit Exceeded#

When receiving a 429 response, inspect the Retry-After header and execute an exponential backoff retry pattern:

typescript
if (response.status === 429) {
  const retryAfterSeconds = parseInt(
    response.headers.get('Retry-After') || '1',
    10
  );
  await new Promise((resolve) => setTimeout(resolve, retryAfterSeconds * 1000));
  return retryRequest();
}