Skip to content

Error Handling

The TopMail API uses standard HTTP status codes and returns consistent error response bodies. This guide covers error formats, common error codes, and retry strategies.

Error Response Format

All error responses follow a consistent JSON format with an error object containing a machine-readable code and a human-readable message.

{
"error": {
"code": "validation_error",
"message": "Subject is required",
"path": "subject"
}
}

HTTP Status Codes

CodeMeaningDescription
200OKRequest succeeded
201CreatedResource was created successfully
202AcceptedRequest accepted for async processing (e.g., batch sends)
400Bad RequestInvalid request body or parameters
401UnauthorizedMissing or invalid API key
403ForbiddenValid API key but insufficient permissions or limit reached
404Not FoundResource does not exist or does not belong to your workspace
409ConflictDuplicate resource or idempotency conflict
429Too Many RequestsRate limit exceeded. Check the Retry-After header.
500Server ErrorAn unexpected error occurred on the server

Common Error Codes

The code field in the error response provides a machine-readable identifier you can use for programmatic error handling.

CodeHTTP StatusDescription
validation_error400Request body failed validation. Check the message and path fields for details.
unauthorized401API key is missing, invalid, or revoked.
missing_from_email400No from_email provided and no default configured in workspace settings.
domain_invalid403Sending domain is not verified or DKIM is not enabled.
template_not_found404The specified template_id does not exist in your workspace.
contact_not_found404No contact found with the given email or contact_id.
not_found404The requested resource does not exist.
workspace_not_found404The workspace associated with the API key was not found.
duplicate409A resource with the same identifier already exists.
limit_reached403Email sending limit for your plan has been reached.
rate_limited429Too many requests. Retry after the duration in the Retry-After header.
invalid_schedule400send_at must be in the future and within 72 hours.
schedule_failed500Failed to enqueue the scheduled email for delivery.
no_content400No email content provided (html, text, or template_id required).
internal_error500An unexpected server error occurred. Safe to retry with backoff.

Retry Strategy

Not all errors should be retried. Use the following guidelines to determine when and how to retry failed requests.

Safe to Retry

  • 429 Too Many Requests -- Wait for the duration specified in the Retry-After header, then retry.
  • 500 Server Error -- Retry with exponential backoff (e.g., 1s, 2s, 4s, 8s). Use an Idempotency-Key header to prevent duplicate sends.
  • Network errors / timeouts -- Retry with backoff. Always include an idempotency key for send endpoints.

Do Not Retry

  • 400 Bad Request -- Fix the request body or parameters before retrying.
  • 401 Unauthorized -- Check your API key is correct and has not been revoked.
  • 403 Forbidden -- The API key lacks permission, the domain is invalid, or you have reached your plan limit.
  • 404 Not Found -- The resource does not exist. Verify the ID or create the resource first.
  • 409 Conflict -- A duplicate resource exists. This is typically not an error condition.

Exponential Backoff Example

# Retry with exponential backoff using a loop
MAX_RETRIES=3
ATTEMPT=0
while [ $ATTEMPT -le $MAX_RETRIES ]; do
RESPONSE=$(curl -s -w "\n%{http_code}" \
https://api.topmail.so/api/v1/email/send \
-H "Authorization: Bearer tm_live_abc123" \
-H "Content-Type: application/json" \
-d '{"to":"user@example.com","subject":"Hello","html":"<p>Hi</p>"}')
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
if [ "$HTTP_CODE" -lt 400 ]; then break; fi
if [ "$HTTP_CODE" -lt 500 ] && [ "$HTTP_CODE" -ne 429 ]; then break; fi
ATTEMPT=$((ATTEMPT + 1))
sleep $((2 ** ATTEMPT))
done
Developer Docs - TopMail