API reference
Errors
The error object and every error the API returns.
Failed requests return a non-2xx HTTP status and an error object:
{
"statusCode": 422,
"name": "validation_error",
"message": "The `to` field is required."
}| Field | Description |
|---|---|
statusCode | The HTTP status code. |
name | A stable, machine-readable error name. Use it in your code. |
message | A human-readable explanation. It may change: don't parse it. |
Error names
| Status | Name | Description |
|---|---|---|
| 401 | missing_api_key | The Authorization header is missing or not in the form Bearer <key>. |
| 401 | restricted_api_key | A sending_access key called an endpoint that needs full_access. |
| 403 | restricted_api_key | A domain-restricted key tried to send from another domain. |
| 403 | invalid_api_key | The API key does not exist or was deleted. |
| 403 | forbidden | The request is not allowed. The message explains why: the sending domain is not verified, a recipient is not allowed in the sandbox, broadcasts are not available, no member has verified their email, or the organization is suspended. |
| 403 | invalid_download_link | An attachment download link is invalid or expired. |
| 404 | not_found | The resource or endpoint does not exist, or belongs to another organization. |
| 405 | method_not_allowed | The endpoint does not support this HTTP method. |
| 409 | conflict | The resource already exists (a domain, a contact in an audience, a template alias) or is in use. |
| 409 | invalid_idempotency_key | The idempotency key was already used for another email. |
| 409 | concurrent_idempotent_requests | Another request with the same idempotency key is in progress. |
| 413 | payload_too_large | The request body is larger than 50 MB. |
| 422 | validation_error | A parameter is missing or invalid, or the action is not possible in the resource's current state (for example, canceling an email that is no longer scheduled). |
| 422 | dns_provider_error | Auto-configure got an unexpected error from the DNS provider. |
| 429 | rate_limit_exceeded | Too many requests. See Rate limits. |
| 429 | daily_quota_exceeded | The organization reached its daily sending quota. |
| 429 | monthly_quota_exceeded | The organization reached its monthly sending quota. |
| 500 | internal_server_error | Something went wrong on our side. Retry later. |
Handling errors
- 4xx errors mean the request needs to change. Retrying the same request gives the same result, except for
429and409 concurrent_idempotent_requests. - 429
rate_limit_exceeded: wait for theretry-afterheader, then retry. - 5xx errors can be retried with backoff. Use an idempotency key when retrying sends.
The SDKs give you the same fields. In Node.js, the error object is returned as error instead of being thrown. In Python, the SDK raises UsendError:
const { data, error } = await usend.emails.send(email);
if (error) {
if (error.name === 'rate_limit_exceeded') {
// wait, then retry
}
console.error(error.statusCode, error.name, error.message);
}from usend import UsendError
try:
usend.emails.send(email)
except UsendError as err:
if err.name == "rate_limit_exceeded":
pass # wait, then retry
print(err.status_code, err.name, err.message)Network failures use the name application_error and have no status code.