Errors
The API uses standard HTTP status codes and a consistent JSON error envelope.
Envelope
{
"error": {
"code": "validation_error",
"message": "Request failed validation.",
"details": { "issues": [{ "path": ["recipient", "email"], "message": "Invalid email address" }] }
}
}
code— a stable machine-readable string. Switch on this in your integration.message— human-readable explanation. Safe to log; do not switch on this.details— optional structured data (e.g. Zod issues, quota info).
Status / code table
| HTTP | code | Meaning |
|---|---|---|
| 401 | unauthorized | Missing Authorization header. |
| 401 | invalid_api_key | Key not found, malformed, or revoked. |
| 402 | quota_exceeded | Monthly certificate quota exhausted. details includes remaining, limit, resetAt. |
| 403 | insufficient_scope | Key lacks the scope this endpoint requires. |
| 404 | not_found | Resource does not exist or is not yours. |
| 409 | conflict | Resource state conflicts (reserved for future use). |
| 422 | validation_error | Request body/query failed schema validation. details.issues lists the fields. |
| 429 | rate_limited | Too many requests. See rate limits. |
| 500 | internal_error | Something went wrong on our side. Safe to retry with backoff. |
Best practices
- Log
code, notmessage. Messages may change; codes are contractual. - Retry only idempotent failures.
500and429are retry-safe;402/404/422are not. - Surface
detailsto your users. For validation errors, thedetails.issuesarray maps directly to form fields.