Send an email
const url = 'https://api.spacepost.dev/emails';const options = { method: 'POST', headers: { 'Idempotency-Key': 'welcome-user-4821', Authorization: 'Bearer <token>', 'Content-Type': 'application/json' }, body: '{"from":"Acme <onboarding@acme.com>","to":["delivered@test.spacepost.dev"],"subject":"Welcome to Acme","html":"<p>Thanks for signing up!</p>"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.spacepost.dev/emails \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: welcome-user-4821' \ --data '{ "from": "Acme <onboarding@acme.com>", "to": [ "delivered@test.spacepost.dev" ], "subject": "Welcome to Acme", "html": "<p>Thanks for signing up!</p>" }'Validates and queues one email. Each recipient counts towards your quota. Use scheduled_at to send later (up to 30 days ahead). Pass tenant_id to send on behalf of a tenant (not needed when the from domain belongs to one). Fails with 422 if tenant_id conflicts with the domain’s tenant, 403 sending_paused if the tenant is paused and 429 daily_quota_exceeded if it reached its daily cap.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”A unique key (1 to 256 characters) that makes the request safe to retry for 24 hours.
Example
welcome-user-4821Request Bodyrequired
Section titled “Request Bodyrequired”Either html or text is required. reply_to is also accepted as replyTo and scheduled_at as scheduledAt.
object
An email address, optionally with a display name: Acme <hello@acme.com>.
An email address, optionally with a display name: Acme <hello@acme.com>.
An email address, optionally with a display name: Acme <hello@acme.com>.
An email address, optionally with a display name: Acme <hello@acme.com>.
An email address, optionally with a display name: Acme <hello@acme.com>.
object
Provide exactly one of content or path.
object
Base64-encoded file content.
A public URL fetched at send time.
Content-ID for inline images (cid:).
object
ISO 8601 date-time or natural language such as “in 1 hour” or “in 2 days”. At most 30 days ahead.
Platform mode. Our tenant id or your external_id. Optional when the from domain belongs to a tenant; a conflict with the domain’s tenant is a 422.
Examples
HTML email
{ "from": "Acme <onboarding@acme.com>", "to": [ "delivered@test.spacepost.dev" ], "subject": "Welcome to Acme", "html": "<p>Thanks for signing up!</p>"}Scheduled with tags
{ "from": "Acme <onboarding@acme.com>", "to": "user@example.com", "subject": "Your trial ends soon", "text": "Your trial ends in 3 days.", "scheduled_at": "in 1 hour", "tags": [ { "name": "category", "value": "trial" } ]}Responses
Section titled “Responses”The email was accepted.
object
Example
{ "id": "0198a1c2-7b3e-7a41-9d52-5f6c1e0b8a11"}Headers
Section titled “Headers”Requests allowed per second for your team.
Requests left in the current one-second window.
Seconds until the window resets.
An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key,
invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests;
422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.
object
Machine-readable error name.
missing_api_key(401): no bearer token.invalid_api_key(403): unknown or malformed key.restricted_api_key(401): the key issending_access(or limited to another domain).validation_error(422): invalid request. Also used with 403 for plan limits and test-domain restrictions.not_found(404): the resource does not exist or belongs to another team.method_not_allowed(405)invalid_idempotency_key(400): key length outside 1 to 256.concurrent_idempotent_requests(409): the original request is still running.invalid_idempotent_request(409): the key was used with a different payload.rate_limit_exceeded(429)daily_quota_exceeded(429): the sandbox, daily limit or a tenant’sdaily_limitwas reached.monthly_quota_exceeded(429): the plan’s monthly limit was reached (Free plan).invalid_from_address(403): the sender domain is not verified.invalid_access(422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)invalid_parameter(422)sending_paused(403): sending is paused for the team, or for the tenant named bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key,
invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests;
422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.
object
Machine-readable error name.
missing_api_key(401): no bearer token.invalid_api_key(403): unknown or malformed key.restricted_api_key(401): the key issending_access(or limited to another domain).validation_error(422): invalid request. Also used with 403 for plan limits and test-domain restrictions.not_found(404): the resource does not exist or belongs to another team.method_not_allowed(405)invalid_idempotency_key(400): key length outside 1 to 256.concurrent_idempotent_requests(409): the original request is still running.invalid_idempotent_request(409): the key was used with a different payload.rate_limit_exceeded(429)daily_quota_exceeded(429): the sandbox, daily limit or a tenant’sdaily_limitwas reached.monthly_quota_exceeded(429): the plan’s monthly limit was reached (Free plan).invalid_from_address(403): the sender domain is not verified.invalid_access(422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)invalid_parameter(422)sending_paused(403): sending is paused for the team, or for the tenant named bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key,
invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests;
422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.
object
Machine-readable error name.
missing_api_key(401): no bearer token.invalid_api_key(403): unknown or malformed key.restricted_api_key(401): the key issending_access(or limited to another domain).validation_error(422): invalid request. Also used with 403 for plan limits and test-domain restrictions.not_found(404): the resource does not exist or belongs to another team.method_not_allowed(405)invalid_idempotency_key(400): key length outside 1 to 256.concurrent_idempotent_requests(409): the original request is still running.invalid_idempotent_request(409): the key was used with a different payload.rate_limit_exceeded(429)daily_quota_exceeded(429): the sandbox, daily limit or a tenant’sdaily_limitwas reached.monthly_quota_exceeded(429): the plan’s monthly limit was reached (Free plan).invalid_from_address(403): the sender domain is not verified.invalid_access(422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)invalid_parameter(422)sending_paused(403): sending is paused for the team, or for the tenant named bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key,
invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests;
422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.
object
Machine-readable error name.
missing_api_key(401): no bearer token.invalid_api_key(403): unknown or malformed key.restricted_api_key(401): the key issending_access(or limited to another domain).validation_error(422): invalid request. Also used with 403 for plan limits and test-domain restrictions.not_found(404): the resource does not exist or belongs to another team.method_not_allowed(405)invalid_idempotency_key(400): key length outside 1 to 256.concurrent_idempotent_requests(409): the original request is still running.invalid_idempotent_request(409): the key was used with a different payload.rate_limit_exceeded(429)daily_quota_exceeded(429): the sandbox, daily limit or a tenant’sdaily_limitwas reached.monthly_quota_exceeded(429): the plan’s monthly limit was reached (Free plan).invalid_from_address(403): the sender domain is not verified.invalid_access(422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)invalid_parameter(422)sending_paused(403): sending is paused for the team, or for the tenant named bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key,
invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests;
422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.
object
Machine-readable error name.
missing_api_key(401): no bearer token.invalid_api_key(403): unknown or malformed key.restricted_api_key(401): the key issending_access(or limited to another domain).validation_error(422): invalid request. Also used with 403 for plan limits and test-domain restrictions.not_found(404): the resource does not exist or belongs to another team.method_not_allowed(405)invalid_idempotency_key(400): key length outside 1 to 256.concurrent_idempotent_requests(409): the original request is still running.invalid_idempotent_request(409): the key was used with a different payload.rate_limit_exceeded(429)daily_quota_exceeded(429): the sandbox, daily limit or a tenant’sdaily_limitwas reached.monthly_quota_exceeded(429): the plan’s monthly limit was reached (Free plan).invalid_from_address(403): the sender domain is not verified.invalid_access(422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)invalid_parameter(422)sending_paused(403): sending is paused for the team, or for the tenant named bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}Too many requests (rate_limit_exceeded), or a daily or monthly sending quota was reached (daily_quota_exceeded also means a tenant’s daily_limit).
object
Machine-readable error name.
missing_api_key(401): no bearer token.invalid_api_key(403): unknown or malformed key.restricted_api_key(401): the key issending_access(or limited to another domain).validation_error(422): invalid request. Also used with 403 for plan limits and test-domain restrictions.not_found(404): the resource does not exist or belongs to another team.method_not_allowed(405)invalid_idempotency_key(400): key length outside 1 to 256.concurrent_idempotent_requests(409): the original request is still running.invalid_idempotent_request(409): the key was used with a different payload.rate_limit_exceeded(429)daily_quota_exceeded(429): the sandbox, daily limit or a tenant’sdaily_limitwas reached.monthly_quota_exceeded(429): the plan’s monthly limit was reached (Free plan).invalid_from_address(403): the sender domain is not verified.invalid_access(422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)invalid_parameter(422)sending_paused(403): sending is paused for the team, or for the tenant named bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Example
{ "statusCode": 429, "name": "rate_limit_exceeded", "message": "Too many requests. You can only make 10 requests per second."}Headers
Section titled “Headers”Seconds to wait before retrying.
Requests allowed per second for your team.
Requests left in the current one-second window.
Seconds until the window resets.