Skip to content

Unsubscribes and blocks

Who may not be emailed and why: unsubscribes, resubscribes with consent, manual blocks and unblocks.

View as Markdown

Unsubscribe an address

POST/projects/{project_id}/unsubscribes

The address gets no more campaigns or broadcasts. Transactional email still goes out. Works for addresses that are not contacts too.

Parameters

NameInTypeNotes
project_idpathstringRequired

Body

Send JSON with every field; use null for a value you do not set.

FieldTypeNotes
emailstringRequired
Request
curl -X POST "https://sendocado.com/api/v1/projects/$PROJECT_ID/unsubscribes" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "maya@example.com"
}'
Response 201
{
  "id": "qoaa8t3rup47p9pb0tdbm50fqo1xo5cv",
  "email": "maya@example.com",
  "source": "api",
  "created_at": 1790000000000
}

Errors

StatusTypeExample message
400invalid_dataSend a JSON request body.
401unauthorizedSend a valid API key as "Authorization: Bearer sc_…", or sign in.
404project_not_foundProject not found.
429rate_limitedToo many requests. Try again in 12 seconds.

Resubscribe an address

POST/projects/{project_id}/resubscribes

Opts an address back in. It needs proof that the person asked, so every resubscribe records the consent it rests on.

Parameters

NameInTypeNotes
project_idpathstringRequired

Body

Send JSON with every field; use null for a value you do not set.

FieldTypeNotes
emailstringRequired
consentobjectRequired
consent.wordingstring | nullRequired
consent.ip_addressstring | nullRequired
consent.user_agentstring | nullRequired
consent.consented_atintegerRequired
Request
curl -X POST "https://sendocado.com/api/v1/projects/$PROJECT_ID/resubscribes" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "maya@example.com",
  "consent": {
    "wording": "Yes, send me product updates from Acme.",
    "ip_address": "203.0.113.42",
    "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_6)",
    "consented_at": 1789999940000
  }
}'
Response 201
{
  "id": "0xzmas6en5mtmo3oqsg5lo50djzdnbj0",
  "email": "maya@example.com",
  "consent_id": "ddlz2uhfkvml73ctyxv2kgafrfw0h9ny",
  "created_at": 1790000000000
}

Errors

StatusTypeExample message
400invalid_dataSend a JSON request body.
401unauthorizedSend a valid API key as "Authorization: Bearer sc_…", or sign in.
404project_not_foundProject not found.
429rate_limitedToo many requests. Try again in 12 seconds.

Block an address

POST/projects/{project_id}/manual-blocks

The address gets no email at all, transactional included, until you unblock it.

Parameters

NameInTypeNotes
project_idpathstringRequired

Body

Send JSON with every field; use null for a value you do not set.

FieldTypeNotes
emailstringRequired
reasonstring | nullRequired
Request
curl -X POST "https://sendocado.com/api/v1/projects/$PROJECT_ID/manual-blocks" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "spamtrap@example.com",
  "reason": "Known spam trap"
}'
Response 201
{
  "id": "wt1fd4mx82mux4b0pzcyc3edqmevxrvc",
  "email": "spamtrap@example.com",
  "reason": "Known spam trap",
  "created_at": 1790000000000
}

Errors

StatusTypeExample message
400invalid_dataSend a JSON request body.
401unauthorizedSend a valid API key as "Authorization: Bearer sc_…", or sign in.
404project_not_foundProject not found.
429rate_limitedToo many requests. Try again in 12 seconds.

Unblock an address

POST/projects/{project_id}/unblocks

Clears the bounces, spam complaints and manual blocks recorded so far. An address that reported spam needs consent to be unblocked. An unsubscribe is cleared only by a resubscribe.

Parameters

NameInTypeNotes
project_idpathstringRequired

Body

Send JSON with every field; use null for a value you do not set.

FieldTypeNotes
emailstringRequired
reasonstring | nullRequired
consentobject | nullRequired
consent.wordingstring | nullRequired
consent.ip_addressstring | nullRequired
consent.user_agentstring | nullRequired
consent.consented_atintegerRequired
Request
curl -X POST "https://sendocado.com/api/v1/projects/$PROJECT_ID/unblocks" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "maya@example.com",
  "reason": "Mailbox was full, now fixed",
  "consent": null
}'
Response 201
{
  "id": "qurtaebog43yq15i5latjpuu3xf6mzkp",
  "email": "maya@example.com",
  "reason": "Mailbox was full, now fixed",
  "consent_id": null,
  "created_at": 1790000000000
}

Errors

StatusTypeExample message
400invalid_dataSend a JSON request body.
401unauthorizedSend a valid API key as "Authorization: Bearer sc_…", or sign in.
404project_not_foundProject not found.
429rate_limitedToo many requests. Try again in 12 seconds.

List unsubscribed and blocked addresses

GET/projects/{project_id}/blocked-emails

One reason per request, newest first. is_still_blocked is false once a later unblock or resubscribe cleared the row; email is null after an erasure.

Parameters

NameInTypeNotes
project_idpathstringRequired
reasonquery"unsubscribed" | "bounced" | "complained" | "manual"Required
cursorquerystring | nullOptional
limitqueryintegerOptional, default 50
Request
curl "https://sendocado.com/api/v1/projects/$PROJECT_ID/blocked-emails?reason=bounced" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
Response 200
{
  "blocked_emails": [
    {
      "id": "wt1fd4mx82mux4b0pzcyc3edqmevxrvc",
      "email": "old-address@example.com",
      "reason": "bounced",
      "detail": "550 5.1.1 The email account that you tried to reach does not exist.",
      "is_still_blocked": true,
      "contact_id": "eh60kvj50ce9uvw53efr4edt2sywb3wk",
      "created_at": 1790000000000
    }
  ],
  "next_cursor": null
}

Errors

StatusTypeExample message
400invalid_datalimit: Too big: expected number to be <=200
401unauthorizedSend a valid API key as "Authorization: Bearer sc_…", or sign in.
404project_not_foundProject not found.
429rate_limitedToo many requests. Try again in 12 seconds.