Transactional and test emails
One email to one address: receipts and resets from your app, and tests to your own inbox.
Send a transactional email
POST/projects/{project_id}/transactional-emails
One email to one address, queued at once (201). Sending the same idempotency_key again returns the first email with 200 and sends nothing. Unsubscribes do not stop it; a blocked address does (422 recipient_blocked).
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| project_id | path | string | Required |
Body
Send JSON with every field; use null for a value you do not set.
| Field | Type | Notes |
|---|---|---|
| to | string | Required |
| template_id | string | null | Required |
| subject | string | null | Required |
| preview_text | string | null | Required |
| html | string | null | Required |
| markdown | string | null | Required |
| variables | object of string | Required |
| reply_to | string | null | Required |
| idempotency_key | string | null | Required |
curl -X POST "https://sendocado.com/api/v1/projects/$PROJECT_ID/transactional-emails" \
-H "Authorization: Bearer $SENDOCADO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "maya@example.com",
"template_id": "29be2u66mr26846p7q9m2i0hz2uep1en",
"subject": null,
"preview_text": null,
"html": null,
"markdown": null,
"variables": {
"order_number": "A-1042",
"total": "$49.00"
},
"reply_to": "billing@acme.example",
"idempotency_key": "order-A-1042-receipt"
}'{
"id": "qfoeqh3av90ric7phkqdlmtt7ns26lrw",
"project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
"send_id": "v7s6ehogfqrclri1qzj865ufrdl1erbf",
"to": "maya@example.com",
"subject": "Your Acme receipt for A-1042",
"preview_text": null,
"html": "<p>Thanks for your order, {{ first_name | there }}.</p>\n<p>Order {{ variables.order_number }}: {{ variables.total }}</p>\n",
"text": "Thanks for your order, {{ first_name | there }}.\n\nOrder {{ variables.order_number }}: {{ variables.total }}",
"merge_tags": ["first_name", "variables.order_number", "variables.total"],
"variables": {
"order_number": "A-1042",
"total": "$49.00"
},
"reply_to": "billing@acme.example",
"source_template_id": "29be2u66mr26846p7q9m2i0hz2uep1en",
"idempotency_key": "order-A-1042-receipt",
"status": "queued",
"created_at": 1790432000000
}Errors
| Status | Type | Example message |
|---|---|---|
| 400 | invalid_data | Send a JSON request body. |
| 401 | unauthorized | Send a valid API key as "Authorization: Bearer sc_…", or sign in. |
| 402 | plan_limit_reached | Your plan allows 5,000 contacts. Upgrade the plan to add more. |
| 404 | project_not_found | Project not found. |
| 422 | recipient_blocked | maya@example.com is blocked in this project: it bounced. |
| 422 | sender_not_ready | Verify the domain of your from address before you send email. |
| 422 | invalid_reference | No template with that id in this project. |
| 429 | rate_limited | Too many requests. Try again in 12 seconds. |
List transactional emails
GET/projects/{project_id}/transactional-emails
Newest first, without each email’s body. Kept for 30 days.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| project_id | path | string | Required |
| cursor | query | string | null | Optional |
| limit | query | integer | Optional, default 50 |
curl "https://sendocado.com/api/v1/projects/$PROJECT_ID/transactional-emails" \
-H "Authorization: Bearer $SENDOCADO_API_KEY"{
"transactional_emails": [
{
"id": "qfoeqh3av90ric7phkqdlmtt7ns26lrw",
"project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
"send_id": "v7s6ehogfqrclri1qzj865ufrdl1erbf",
"to": "maya@example.com",
"subject": "Your Acme receipt for A-1042",
"preview_text": null,
"variables": {
"order_number": "A-1042",
"total": "$49.00"
},
"reply_to": "billing@acme.example",
"source_template_id": "29be2u66mr26846p7q9m2i0hz2uep1en",
"idempotency_key": "order-A-1042-receipt",
"status": "delivered",
"created_at": 1790432000000
}
],
"next_cursor": null
}Errors
| Status | Type | Example message |
|---|---|---|
| 400 | invalid_data | limit: Too big: expected number to be <=200 |
| 401 | unauthorized | Send a valid API key as "Authorization: Bearer sc_…", or sign in. |
| 404 | project_not_found | Project not found. |
| 429 | rate_limited | Too many requests. Try again in 12 seconds. |
Get a transactional email
GET/transactional-emails/{transactional_email_id}
status follows the email: queued, sent, then what the provider reported. Get the send for its events and failures.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| transactional_email_id | path | string | Required |
curl "https://sendocado.com/api/v1/transactional-emails/$TRANSACTIONAL_EMAIL_ID" \
-H "Authorization: Bearer $SENDOCADO_API_KEY"{
"id": "qfoeqh3av90ric7phkqdlmtt7ns26lrw",
"project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
"send_id": "v7s6ehogfqrclri1qzj865ufrdl1erbf",
"to": "maya@example.com",
"subject": "Your Acme receipt for A-1042",
"preview_text": null,
"html": "<p>Thanks for your order, {{ first_name | there }}.</p>\n<p>Order {{ variables.order_number }}: {{ variables.total }}</p>\n",
"text": "Thanks for your order, {{ first_name | there }}.\n\nOrder {{ variables.order_number }}: {{ variables.total }}",
"merge_tags": ["first_name", "variables.order_number", "variables.total"],
"variables": {
"order_number": "A-1042",
"total": "$49.00"
},
"reply_to": "billing@acme.example",
"source_template_id": "29be2u66mr26846p7q9m2i0hz2uep1en",
"idempotency_key": "order-A-1042-receipt",
"status": "delivered",
"created_at": 1790432000000
}Errors
| Status | Type | Example message |
|---|---|---|
| 401 | unauthorized | Send a valid API key as "Authorization: Bearer sc_…", or sign in. |
| 404 | transactional_email_not_found | Transactional email not found. |
| 429 | rate_limited | Too many requests. Try again in 12 seconds. |
Send a test email
POST/projects/{project_id}/test-emails
A preview in a real inbox before anyone else gets the email. Merge tags take contact_id’s values when it is set. Test emails are never tracked and have a tighter rate limit.
Limited to 30 requests every 60 minutes, on top of the API limit.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| project_id | path | string | Required |
Body
Send JSON with every field; use null for a value you do not set.
| Field | Type | Notes |
|---|---|---|
| to | string | Required |
| template_id | string | null | Required |
| subject | string | null | Required |
| preview_text | string | null | Required |
| html | string | null | Required |
| markdown | string | null | Required |
| contact_id | string | null | Required |
curl -X POST "https://sendocado.com/api/v1/projects/$PROJECT_ID/test-emails" \
-H "Authorization: Bearer $SENDOCADO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "founder@acme.example",
"template_id": null,
"subject": "Welcome to Acme, {{ first_name | there }}",
"preview_text": null,
"html": "<p>Hi {{ first_name | there }},</p>\n<p>Thanks for trying Acme. Start with the <a href=\"https://acme.example/setup\">two-minute setup</a>.</p>\n",
"markdown": null,
"contact_id": "j8ht9lgmxg9edn581u33xtplpft75v2s"
}'{
"id": "bqcab69m64p2g158z6tnovmizwdiaeq1",
"project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
"send_id": "v7s6ehogfqrclri1qzj865ufrdl1erbf",
"to": "founder@acme.example",
"subject": "Welcome to Acme, Maya",
"status": "queued",
"created_at": 1790000000000
}Errors
| Status | Type | Example message |
|---|---|---|
| 400 | invalid_data | Send a JSON request body. |
| 401 | unauthorized | Send a valid API key as "Authorization: Bearer sc_…", or sign in. |
| 402 | plan_limit_reached | Your plan allows 5,000 contacts. Upgrade the plan to add more. |
| 404 | project_not_found | Project not found. |
| 422 | recipient_blocked | maya@example.com is blocked in this project: it bounced. |
| 422 | sender_not_ready | Verify the domain of your from address before you send email. |
| 422 | invalid_reference | No template with that id in this project. |
| 429 | rate_limited | Too many requests. Try again in 12 seconds. |
Get a test email
GET/test-emails/{test_email_id}
status follows the email, like a transactional email’s.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| test_email_id | path | string | Required |
curl "https://sendocado.com/api/v1/test-emails/$TEST_EMAIL_ID" \
-H "Authorization: Bearer $SENDOCADO_API_KEY"{
"id": "bqcab69m64p2g158z6tnovmizwdiaeq1",
"project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
"send_id": "v7s6ehogfqrclri1qzj865ufrdl1erbf",
"to": "founder@acme.example",
"subject": "Welcome to Acme, Maya",
"status": "delivered",
"created_at": 1790000000000
}Errors
| Status | Type | Example message |
|---|---|---|
| 401 | unauthorized | Send a valid API key as "Authorization: Bearer sc_…", or sign in. |
| 404 | test_email_not_found | Test email not found. |
| 429 | rate_limited | Too many requests. Try again in 12 seconds. |