Skip to content

Contacts

The people you email: create, update in batches, search, read their history, export or erase them.

View as Markdown

List contacts

GET/projects/{project_id}/contacts

Newest first. Filter by one of search (matches email and name), tag or email at a time.

Parameters

NameInTypeNotes
project_idpathstringRequired
searchquerystring | nullOptional
tagquerystring | nullOptional
emailquerystring | nullOptional
cursorquerystring | nullOptional
limitqueryintegerOptional, default 50
Request
curl "https://sendocado.com/api/v1/projects/$PROJECT_ID/contacts?tag=trial&limit=50" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
Response 200
{
  "contacts": [
    {
      "id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
      "project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
      "email": "maya@example.com",
      "first_name": "Maya",
      "last_name": "Patel",
      "timezone": "Europe/London",
      "tags": ["trial"],
      "attributes": {
        "plan": "trial",
        "company": "Northwind"
      },
      "is_unsubscribed": false,
      "is_blocked": false,
      "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.

Create a contact

POST/projects/{project_id}/contacts

Fails with 409 contact_exists when the address is already in the project; to create or update in one call, use the batch route. A new contact joins every live campaign whose audience it matches.

Parameters

NameInTypeNotes
project_idpathstringRequired

Body

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

FieldTypeNotes
emailstringRequired
first_namestring | nullRequired
last_namestring | nullRequired
timezonestring | nullRequired
tagsstring[]Required
attributesobject of stringRequired
Request
curl -X POST "https://sendocado.com/api/v1/projects/$PROJECT_ID/contacts" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "maya@example.com",
  "first_name": "Maya",
  "last_name": "Patel",
  "timezone": "Europe/London",
  "tags": ["trial"],
  "attributes": {
    "plan": "trial",
    "company": "Northwind"
  }
}'
Response 201
{
  "id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
  "project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
  "email": "maya@example.com",
  "first_name": "Maya",
  "last_name": "Patel",
  "timezone": "Europe/London",
  "tags": ["trial"],
  "attributes": {
    "plan": "trial",
    "company": "Northwind"
  },
  "is_unsubscribed": false,
  "is_blocked": false,
  "created_at": 1790000000000
}

Errors

StatusTypeExample message
400invalid_dataSend a JSON request body.
401unauthorizedSend a valid API key as "Authorization: Bearer sc_…", or sign in.
402plan_limit_reachedYour plan allows 5,000 contacts. Upgrade the plan to add more.
404project_not_foundProject not found.
409contact_existsmaya@example.com is already a contact in this project.
429rate_limitedToo many requests. Try again in 12 seconds.

Create or update contacts in a batch

PUT/projects/{project_id}/contacts/batch

Up to 1,000 contacts, all or nothing: one bad contact refuses the batch and the error names its index. For an existing contact a null field keeps what is stored, tags are added and attributes are set.

Parameters

NameInTypeNotes
project_idpathstringRequired

Body

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

FieldTypeNotes
contactsobject[]Required
contacts[].emailstringRequired
contacts[].first_namestring | nullRequired
contacts[].last_namestring | nullRequired
contacts[].timezonestring | nullRequired
contacts[].tagsstring[]Required
contacts[].attributesobject of stringRequired
Request
curl -X PUT "https://sendocado.com/api/v1/projects/$PROJECT_ID/contacts/batch" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "contacts": [
    {
      "email": "maya@example.com",
      "first_name": "Maya",
      "last_name": null,
      "timezone": null,
      "tags": ["customer"],
      "attributes": {
        "plan": "pro"
      }
    },
    {
      "email": "leo@example.com",
      "first_name": "Leo",
      "last_name": "Martin",
      "timezone": "Europe/Paris",
      "tags": ["trial"],
      "attributes": {}
    }
  ]
}'

Answers 204 with no body.

Errors

StatusTypeExample message
400invalid_dataSend a JSON request body.
401unauthorizedSend a valid API key as "Authorization: Bearer sc_…", or sign in.
402plan_limit_reachedYour plan allows 5,000 contacts. Upgrade the plan to add more.
404project_not_foundProject not found.
429rate_limitedToo many requests. Try again in 12 seconds.

Get a contact

GET/contacts/{contact_id}

is_unsubscribed and is_blocked are read from the address’s history, so they stay true after a contact is deleted and added again.

Parameters

NameInTypeNotes
contact_idpathstringRequired
Request
curl "https://sendocado.com/api/v1/contacts/$CONTACT_ID" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
Response 200
{
  "id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
  "project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
  "email": "maya@example.com",
  "first_name": "Maya",
  "last_name": "Patel",
  "timezone": "Europe/London",
  "tags": ["trial"],
  "attributes": {
    "plan": "trial",
    "company": "Northwind"
  },
  "is_unsubscribed": false,
  "is_blocked": false,
  "created_at": 1790000000000
}

Errors

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

Update a contact

PUT/contacts/{contact_id}

The email never changes. Tags and attributes become exactly the sets you send. Unsubscribing and blocking have their own routes.

Parameters

NameInTypeNotes
contact_idpathstringRequired

Body

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

FieldTypeNotes
first_namestring | nullRequired
last_namestring | nullRequired
timezonestring | nullRequired
tagsstring[]Required
attributesobject of stringRequired
Request
curl -X PUT "https://sendocado.com/api/v1/contacts/$CONTACT_ID" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "first_name": "Maya",
  "last_name": "Patel",
  "timezone": "Europe/London",
  "tags": ["trial"],
  "attributes": {
    "plan": "trial",
    "company": "Northwind"
  }
}'
Response 200
{
  "id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
  "project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
  "email": "maya@example.com",
  "first_name": "Maya",
  "last_name": "Patel",
  "timezone": "Europe/London",
  "tags": ["trial"],
  "attributes": {
    "plan": "trial",
    "company": "Northwind"
  },
  "is_unsubscribed": false,
  "is_blocked": false,
  "created_at": 1790000000000
}

Errors

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

Delete a contact

DELETE/contacts/{contact_id}

Its campaigns end. The address stays unsubscribed or blocked; to remove every trace of it, create a contact erasure.

Parameters

NameInTypeNotes
contact_idpathstringRequired
Request
curl -X DELETE "https://sendocado.com/api/v1/contacts/$CONTACT_ID" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"

Answers 204 with no body.

Errors

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

List a contact’s emails and events

GET/contacts/{contact_id}/activity

Every email sent to the contact’s address, newest first, including ones sent before the contact existed. Each lists up to 15 events of each type.

Parameters

NameInTypeNotes
contact_idpathstringRequired
cursorquerystring | nullOptional
limitqueryintegerOptional, default 50
Request
curl "https://sendocado.com/api/v1/contacts/$CONTACT_ID/activity" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
Response 200
{
  "activity": [
    {
      "send": {
        "id": "thjxjqi3ogz5kok16zv0mwufxbv932by",
        "project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
        "contact_id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
        "to": "maya@example.com",
        "subject": "Welcome to Acme, Maya",
        "source": {
          "type": "campaign_step",
          "campaign_id": "h5dnsipzz5fk2z9ri19r0wyojfljooa5",
          "step_id": "j8gxbenyjqwx4hh5344tfjgvq4k7bn7x",
          "enrollment_id": "j3j4wj99ibag7i1mnbqns6puq80idw37"
        },
        "status": "delivered",
        "has_opened": true,
        "has_clicked": true,
        "has_replied": false,
        "accepted_at": 1790000120000,
        "failed_at": null,
        "ext_provider_message_id": "4ef9a1c2-7d3b-4f0e-9a51-2c8e6b1d0f73",
        "created_at": 1790000120000
      },
      "events": [
        {
          "type": "delivered",
          "url": null,
          "detail": null,
          "created_at": 1790000180000
        },
        {
          "type": "opened",
          "url": null,
          "detail": null,
          "created_at": 1790005700000
        },
        {
          "type": "clicked",
          "url": "https://acme.example/setup",
          "detail": null,
          "created_at": 1790005760000
        }
      ]
    }
  ],
  "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.
404contact_not_foundContact not found.
429rate_limitedToo many requests. Try again in 12 seconds.

List a contact’s campaigns

GET/contacts/{contact_id}/enrollments

Every campaign the contact is in or has left, with why they left.

Parameters

NameInTypeNotes
contact_idpathstringRequired
Request
curl "https://sendocado.com/api/v1/contacts/$CONTACT_ID/enrollments" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
Response 200
{
  "enrollments": [
    {
      "id": "j3j4wj99ibag7i1mnbqns6puq80idw37",
      "campaign_id": "h5dnsipzz5fk2z9ri19r0wyojfljooa5",
      "contact": {
        "id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
        "email": "maya@example.com",
        "first_name": "Maya",
        "last_name": "Patel"
      },
      "status": "active",
      "exit_reason": null,
      "next_action": {
        "type": "check_branch",
        "step_id": "j8gxbenyjqwx4hh5344tfjgvq4k7bn7x",
        "due_at": 1790259200000
      },
      "created_at": 1790000060000,
      "exited_at": null
    }
  ],
  "next_cursor": null
}

Errors

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

Export everything about a contact

GET/contacts/{contact_id}/export

A subject-access export: every fact held about the contact and its address, in one JSON document.

Parameters

NameInTypeNotes
contact_idpathstringRequired
Request
curl "https://sendocado.com/api/v1/contacts/$CONTACT_ID/export" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
Response 200
{
  "contact": {
    "id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
    "project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
    "email": "maya@example.com",
    "first_name": "Maya",
    "last_name": "Patel",
    "timezone": "Europe/London",
    "tags": ["trial"],
    "attributes": {
      "plan": "trial",
      "company": "Northwind"
    },
    "is_unsubscribed": false,
    "is_blocked": false,
    "created_at": 1790000000000
  },
  "enrollments": [
    {
      "id": "j3j4wj99ibag7i1mnbqns6puq80idw37",
      "campaign_id": "h5dnsipzz5fk2z9ri19r0wyojfljooa5",
      "exits": [],
      "created_at": 1790000060000
    }
  ],
  "sends": [
    {
      "send": {
        "id": "thjxjqi3ogz5kok16zv0mwufxbv932by",
        "to": "maya@example.com",
        "subject": "Welcome to Acme, Maya",
        "source": {
          "type": "campaign_step",
          "campaign_id": "h5dnsipzz5fk2z9ri19r0wyojfljooa5",
          "step_id": "j8gxbenyjqwx4hh5344tfjgvq4k7bn7x",
          "enrollment_id": "j3j4wj99ibag7i1mnbqns6puq80idw37"
        },
        "status": "delivered",
        "accepted_at": 1790000120000,
        "failed_at": null,
        "created_at": 1790000120000
      },
      "events": [
        {
          "type": "delivered",
          "url": null,
          "detail": null,
          "created_at": 1790000180000
        },
        {
          "type": "opened",
          "url": null,
          "detail": null,
          "created_at": 1790005700000
        },
        {
          "type": "clicked",
          "url": "https://acme.example/setup",
          "detail": null,
          "created_at": 1790005760000
        }
      ]
    }
  ],
  "replies": [
    {
      "id": "kdfy6spsc3lkr2aqxv9upctnwlavyf4r",
      "send_id": "thjxjqi3ogz5kok16zv0mwufxbv932by",
      "from_email": "maya@example.com",
      "from_name": "Maya Patel",
      "subject": "Re: Welcome to Acme, Maya",
      "text": "Thanks! Quick question: can I import from a CSV?",
      "created_at": 1790010800000
    }
  ],
  "unsubscribes": [],
  "resubscribes": [],
  "bounces": [],
  "complaints": [],
  "manual_blocks": [],
  "unblocks": [],
  "consents": [],
  "transactional_emails": [],
  "test_emails": []
}

Errors

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

Erase an address

POST/projects/{project_id}/contact-erasures

Deletes the contact and everything sent to the address, in the background. Its unsubscribes and blocks are kept without the address, so it stays unmailable. Read the erasure until it is completed.

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/contact-erasures" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "maya@example.com"
}'
Response 201
{
  "id": "ez732pgojj7g3f9caioctiq71hget7my",
  "status": "pending",
  "created_at": 1790000000000,
  "completed_at": null
}

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.

Get an erasure

GET/contact-erasures/{contact_erasure_id}

status becomes completed once every record is gone.

Parameters

NameInTypeNotes
contact_erasure_idpathstringRequired
Request
curl "https://sendocado.com/api/v1/contact-erasures/$CONTACT_ERASURE_ID" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
Response 200
{
  "id": "ez732pgojj7g3f9caioctiq71hget7my",
  "status": "completed",
  "created_at": 1790000000000,
  "completed_at": 1790000120000
}

Errors

StatusTypeExample message
401unauthorizedSend a valid API key as "Authorization: Bearer sc_…", or sign in.
404contact_erasure_not_foundContact erasure not found.
429rate_limitedToo many requests. Try again in 12 seconds.

List tags in use

GET/projects/{project_id}/contact-tags

Every distinct tag on the project’s contacts, for building audiences. is_complete is false when there are more than one read lists.

Parameters

NameInTypeNotes
project_idpathstringRequired
Request
curl "https://sendocado.com/api/v1/projects/$PROJECT_ID/contact-tags" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
Response 200
{
  "tags": ["customer", "trial", "webinar"],
  "is_complete": true
}

Errors

StatusTypeExample message
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 attribute keys in use

GET/projects/{project_id}/contact-attribute-keys

Every distinct attribute key on the project’s contacts. is_complete is false when there are more than one read lists.

Parameters

NameInTypeNotes
project_idpathstringRequired
Request
curl "https://sendocado.com/api/v1/projects/$PROJECT_ID/contact-attribute-keys" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
Response 200
{
  "keys": ["company", "plan"],
  "is_complete": true
}

Errors

StatusTypeExample message
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.