Skip to content

Errors

Every error response has the same JSON shape, identical to Resend’s:

{
"statusCode": 422,
"name": "validation_error",
"message": "`from`: Invalid email address"
}

Branch on name, which is stable. message is for humans and may change. In the Node SDK, errors come back as { data: null, error } with the same three fields; network failures use name: "application_error" and statusCode: null.

errors.ts
import { SpacePost } from "@spacepost/node";
const spacepost = new SpacePost();
const { data, error } = await spacepost.emails.send({
from: "Acme <hello@acme.com>",
to: "user@example.com",
subject: "Hello",
html: "<p>Hello</p>",
});
if (error) {
switch (error.name) {
case "rate_limit_exceeded":
// wait about a second, then retry with the same idempotency key
break;
case "daily_quota_exceeded":
case "monthly_quota_exceeded":
// alert someone: you hit a limit
break;
case "validation_error":
case "invalid_from_address":
// a bug in your request: do not retry
throw new Error(`${error.name}: ${error.message}`);
default:
console.error(error.statusCode, error.name, error.message);
}
} else {
console.log(data.id);
}
Status name Meaning and fix
400 invalid_idempotency_key The Idempotency-Key header is not 1 to 256 characters.
401 missing_api_key No Authorization: Bearer sp_live_... header.
401 restricted_api_key The key may not do this: a sending_access key used on a non-sending endpoint, or a domain-restricted key sending from another domain.
403 invalid_api_key The key is unknown, revoked, or not a SpacePost key (for example a Resend re_ key).
403 invalid_from_address The from domain is not a verified domain of your team.
403 sending_paused Your team is paused, usually after high bounce or complaint rates, or (when you pass tenant_id or send from a tenant-owned domain) that tenant is paused. See Automatic pausing.
403 validation_error A request that is valid but not allowed: using test.spacepost.dev to mail recipients other than your team or test addresses, or exceeding your plan’s domain limit.
403 invalid_access Dashboard session without access to the requested team, or POST /tenants/{ref}/unpause on a tenant that was paused for its bounce or complaint rate by a team that is not trusted. Contact support.
404 not_found The resource does not exist (or belongs to another team), or the endpoint does not exist.
405 method_not_allowed The HTTP method is not supported on this path.
409 concurrent_idempotent_requests The same idempotency key is still being processed. Retry shortly.
409 invalid_idempotent_request The idempotency key was already used with a different request body.
422 validation_error A field is missing or invalid. The message names it. Also: “Only scheduled emails can be canceled”, “Domain already registered”, invalid JSON, a tenant_id that conflicts with the domain’s tenant, a duplicate tenant external_id, deleting a tenant that still has domains.
422 invalid_parameter A query or path parameter is invalid.
429 rate_limit_exceeded Over your requests-per-second limit. Wait for retry-after seconds.
429 daily_quota_exceeded The daily sending limit was reached (new-account sandbox, your trust-level cap, or a tenant’s daily_limit).
429 monthly_quota_exceeded The Free plan’s monthly limit was reached. Upgrade or wait.
451 security_error The email was blocked by content filtering (executable attachment, phishing or spam indicators). Change the content; do not retry as is.
500 application_error Unexpected error from the API. Retry with backoff.
500 internal_server_error “An unexpected error occurred, please try again later”. Retry with backoff; contact support if persistent.
Retry? Errors
Yes, after the retry-after seconds rate_limit_exceeded
Yes, with exponential backoff and the same Idempotency-Key 500s, network errors, concurrent_idempotent_requests
No, fix the request 400, 401, 403, 404, 422
No, wait for the limit to reset or upgrade daily_quota_exceeded, monthly_quota_exceeded
No, ask support (or unpause a tenant you paused yourself) sending_paused, security_error

Errors above are returned when you make a request. Problems that happen after an email is accepted (bounces, rejections) arrive as webhook events and in the email’s last_event.

Over SMTP, the same conditions are returned as SMTP reply codes: quota errors 452, rate limiting 421, invalid sender 553, other rejections 550, temporary faults 451.