All CMR API responses (success and error) — use the same JSON envelope. Errors are never surfaced as HTML or plain text.
{
"status": 422,
"message": "Domain is not available for registration",
"data": null
}
The status field in the JSON body always matches the HTTP status code. On success, data contains the response payload. On error, data is null.
HTTP Status Codes#
| Code | Meaning | When you'll see it |
|---|
200 | Success | Request was processed |
400 | Bad Request | Missing required field or invalid parameter |
401 | Unauthorized | Missing or invalid cmr-x-api-key |
403 | Forbidden | Valid key but insufficient permissions |
404 | Not Found | Resource doesn't exist or belongs to another partner |
409 | Conflict | Duplicate resource — e.g. email already registered |
422 | Unprocessable | Request is valid but fails business logic |
429 | Too Many Requests | Rate limit exceeded — check Retry-After header |
500 | Server Error | CMR internal error — safe to retry with backoff |
Common Errors#
| Cause | Status | Message |
|---|
| Missing API key header | 401 | Please provide an api key or generate one from the dashboard |
| Invalid API key | 401 | Invalid api key |
Missing userId | 400 | Please provide a userId |
| User not found | 404 | The requested user does not exist. |
Async Operation Failures#
For async operations, failures don't arrive as HTTP error responses on the initial request — they arrive via webhook after CMR attempts the operation in the background.Always handle both the success webhook and the failure webhook for every async operation you submit. Your UI should reflect the final webhook status, not the initial HTTP 200.
| Operation | Success webhook | Failure webhook |
|---|
| Domain + mailbox order | domain.order.success | domain.order.failed |
| Mailbox-only order | mailbox.order.success | mailbox.order.failed |
| Domain renewal | domain.renewal.success | domain.renewal.failed |
| Subscription renewal | subscription.renewal.success | subscription.renewal.failed |
| Pre-warmup order | prewarmup.order.success | prewarmup.order.failed |
Retry Strategy#
Never retry 4xx responses (except 429). They indicate a problem with your request — retrying won't help and may cause side effects like duplicate resource creation.
| Status | Retry? | Strategy |
|---|
429 | Yes | Wait for Retry-After header value + jitter |
500 | Yes | Exponential backoff — start at 5s, cap at 30s |
503 | Yes | Same as 500 |
4xx | No | Fix the request first |
Next Steps#
Rate Limits
How to handle 429s, batch requests, and stay safely under the 5 req/sec limit.
Pagination
Query parameter errors and out-of-range page/limit handling.
Webhooks Overview
Set up your webhook endpoint to receive async operation results.