Core

Contacts API

6 endpoints under https://api.mailneo.co/api/v2. Every request carries your key in the X-API-Key header. The scopes used here: contacts:delete, contacts:read, contacts:write. Each endpoint below states the one it requires. Start with the guide →

Contacts
listContacts

List contacts

Cursor-paginated. Pass updated_since with the synced_through value from your previous run to fetch only what changed; you will occasionally re-see a row, so upsert by id. Deletes are not visible to updated_since.

https://api.mailneo.co/api/v2
GET/contactscontacts:read

Example request

curl "https://api.mailneo.co/api/v2/contacts?limit=25&order=desc&sort=updated_at" \
  -H "X-API-Key: $MAILNEO_API_KEY"
Authorization
Required scope
contacts:read. A key without it is refused before the endpoint runs.
Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Query parameters9
NameTypeRequiredNotes
limitintegerNodefault 25 · 1–100
cursorstringNomax 256 chars
order"asc" | "desc"Nodefault "desc"
updated_sincestring · date-timeNoISO 8601
sort"updated_at" | "created_at" | "last_activity_at"Nodefault "updated_at"
status"ACTIVE" | "CONVERTED" | "LOST" | "UNQUALIFIED" | "ARCHIVED"No
emailstringNomax 320 chars
sourcestringNomax 200 chars
tagsstringNomax 1000 chars
Response · 200

Success

data[]Each element of the array.

FieldTypeAlways presentNotes
object"contact"Yes
idstringYes
emailstringYes
first_namestring · nullableYes
last_namestring · nullableYes
companystring · nullableYes
phonestring · nullableYes
websitestring · nullableYes
linkedinstring · nullableYes
twitterstring · nullableYes
facebookstring · nullableYes
statusstringYes
tagsstring[]Yes
sourcestring · nullableYes
custom_fieldsobjectYesopen keys
emails_opened_countnumberYes
links_clicked_countnumberYes
total_interactionsnumberYes
has_repliedbooleanYes
last_contacted_atstring · nullableYes
last_activity_atstring · nullableYes
created_atstringYes
updated_atstringYes

meta

FieldTypeAlways presentNotes
request_idstringYes
has_morebooleanYes
next_cursorstring · nullableYes
synced_throughstringNo
Contactswrite
createContact

Create a contact

Creates one contact. The email is normalised (trimmed and lower-cased) and must be unique within the team — a duplicate is a 409 resource_already_exists, not a silent upsert. Use POST /contacts/bulk when you want upsert semantics.

https://api.mailneo.co/api/v2
POST/contactscontacts:write

Example request

curl -X POST "https://api.mailneo.co/api/v2/contacts" \
  -H "X-API-Key: $MAILNEO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "<string>"
  }'
Authorization
Required scope
contacts:write. A key without it is refused before the endpoint runs.
Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Idempotency
Idempotency-Key is optional.
Query parameters1
NameTypeRequiredNotes
dry_runbooleanNoReport what this call WOULD do and commit nothing. Returns data: null and a meta.impact block. Requires the resource's :read scope in addition to the scope this endpoint declares. Must be exactly true or false.
Header parameters1
NameTypeRequiredNotes
Idempotency-KeystringNoA caller-chosen unique string, at most 255 characters. Retrying with the same key replays the first response instead of repeating the work; the replay carries Idempotent-Replayed: true. Reusing a key with a different body is a 409 idempotency_key_reused. Keys are remembered for 24 hours. · max 255 chars
Request body

Body

FieldTypeAlways presentNotes
emailstringYesmax 320 chars · pattern-constrained
first_namestring · nullableNomax 200 chars
last_namestring · nullableNomax 200 chars
companystring · nullableNomax 200 chars
phonestring · nullableNomax 50 chars
websitestring · nullableNomax 500 chars
linkedinstring · nullableNomax 500 chars
twitterstring · nullableNomax 500 chars
facebookstring · nullableNomax 500 chars
sourcestring · nullableNomax 200 chars
status"ACTIVE" | "CONVERTED" | "LOST" | "UNQUALIFIED" | "ARCHIVED"No
tagsstring[]No
custom_fieldsobjectNoopen keys
Response · 200

Success

data

FieldTypeAlways presentNotes
dataobject | object · nullableYes

meta

FieldTypeAlways presentNotes
request_idstringYes
dry_runbooleanYes
impactobjectNo
impact.object"impact"Yes
impact.would_createintegerYes
impact.would_updateintegerYes
impact.would_deleteintegerYes
impact.affected_countintegerYes
impact.affected_idsstring[]Yes
impact.quotaobject · nullableYes
impact.quota.kindstringYes
impact.quota.would_consumeintegerYes
impact.quota.limitinteger · nullableYes
impact.quota.currentintegerYes
Response · 201

Created

data

FieldTypeAlways presentNotes
dataobject | object · nullableYes

meta

FieldTypeAlways presentNotes
request_idstringYes
dry_runbooleanYes
impactobjectNo
impact.object"impact"Yes
impact.would_createintegerYes
impact.would_updateintegerYes
impact.would_deleteintegerYes
impact.affected_countintegerYes
impact.affected_idsstring[]Yes
impact.quotaobject · nullableYes
impact.quota.kindstringYes
impact.quota.would_consumeintegerYes
impact.quota.limitinteger · nullableYes
impact.quota.currentintegerYes
Contacts
getContact

Retrieve a contact

https://api.mailneo.co/api/v2
GET/contacts/{contactId}contacts:read

Example request

curl "https://api.mailneo.co/api/v2/contacts/{contactId}" \
  -H "X-API-Key: $MAILNEO_API_KEY"
Authorization
Required scope
contacts:read. A key without it is refused before the endpoint runs.
Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Path parameters1
NameTypeRequiredNotes
contactIdstringYesmax 64 chars
Response · 200

Success

data

FieldTypeAlways presentNotes
object"contact"Yes
idstringYes
emailstringYes
first_namestring · nullableYes
last_namestring · nullableYes
companystring · nullableYes
phonestring · nullableYes
websitestring · nullableYes
linkedinstring · nullableYes
twitterstring · nullableYes
facebookstring · nullableYes
statusstringYes
tagsstring[]Yes
sourcestring · nullableYes
custom_fieldsobjectYesopen keys
emails_opened_countnumberYes
links_clicked_countnumberYes
total_interactionsnumberYes
has_repliedbooleanYes
last_contacted_atstring · nullableYes
last_activity_atstring · nullableYes
created_atstringYes
updated_atstringYes

meta

FieldTypeAlways presentNotes
request_idstringYes
Contactswrite
updateContact

Update a contact

Merge-patch: fields you omit are left alone, and null clears a field. tags and custom_fields are the exceptions worth knowing — tags REPLACES the whole array, while custom_fields merges key by key so a value written by an import is not lost.

https://api.mailneo.co/api/v2
PATCH/contacts/{contactId}contacts:write

Example request

curl -X PATCH "https://api.mailneo.co/api/v2/contacts/{contactId}" \
  -H "X-API-Key: $MAILNEO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "<string>",
    "first_name": "<string>",
    "last_name": "<string>",
    "company": "<string>",
    "phone": "<string>",
    "website": "<string>",
    "linkedin": "<string>",
    "twitter": "<string>",
    "facebook": "<string>",
    "source": "<string>",
    "status": "ACTIVE",
    "tags": [
      "<string>"
    ],
    "custom_fields": {}
  }'
Authorization
Required scope
contacts:write. A key without it is refused before the endpoint runs.
Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Idempotency
Idempotency-Key is optional.
Path parameters1
NameTypeRequiredNotes
contactIdstringYesmax 64 chars
Query parameters1
NameTypeRequiredNotes
dry_runbooleanNoReport what this call WOULD do and commit nothing. Returns data: null and a meta.impact block. Requires the resource's :read scope in addition to the scope this endpoint declares. Must be exactly true or false.
Header parameters1
NameTypeRequiredNotes
Idempotency-KeystringNoA caller-chosen unique string, at most 255 characters. Retrying with the same key replays the first response instead of repeating the work; the replay carries Idempotent-Replayed: true. Reusing a key with a different body is a 409 idempotency_key_reused. Keys are remembered for 24 hours. · max 255 chars
Request body

Body

FieldTypeAlways presentNotes
emailstringNomax 320 chars · pattern-constrained
first_namestring · nullableNomax 200 chars
last_namestring · nullableNomax 200 chars
companystring · nullableNomax 200 chars
phonestring · nullableNomax 50 chars
websitestring · nullableNomax 500 chars
linkedinstring · nullableNomax 500 chars
twitterstring · nullableNomax 500 chars
facebookstring · nullableNomax 500 chars
sourcestring · nullableNomax 200 chars
status"ACTIVE" | "CONVERTED" | "LOST" | "UNQUALIFIED" | "ARCHIVED"No
tagsstring[]No
custom_fieldsobjectNoopen keys
Response · 200

Success

data

FieldTypeAlways presentNotes
dataobject | object · nullableYes

meta

FieldTypeAlways presentNotes
request_idstringYes
dry_runbooleanYes
impactobjectNo
impact.object"impact"Yes
impact.would_createintegerYes
impact.would_updateintegerYes
impact.would_deleteintegerYes
impact.affected_countintegerYes
impact.affected_idsstring[]Yes
impact.quotaobject · nullableYes
impact.quota.kindstringYes
impact.quota.would_consumeintegerYes
impact.quota.limitinteger · nullableYes
impact.quota.currentintegerYes
Contactsdestructive
deleteContact

Delete a contact

Permanent. The contact row is removed, and the copy of its name and email retained on campaign recipients is anonymised in the same transaction, so campaign counts survive and that copy does not. There is no undo — call with ?dry_run=true first. This is not a complete erasure request: sent messages retain the delivery address in the sending log. Use the account data-erasure flow for a full GDPR deletion.

https://api.mailneo.co/api/v2
DELETE/contacts/{contactId}contacts:delete

Example request

curl -X DELETE "https://api.mailneo.co/api/v2/contacts/{contactId}" \
  -H "X-API-Key: $MAILNEO_API_KEY"
Authorization
Required scope
contacts:delete. A key without it is refused before the endpoint runs.
Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Path parameters1
NameTypeRequiredNotes
contactIdstringYesmax 64 chars
Query parameters1
NameTypeRequiredNotes
dry_runbooleanNoReport what this call WOULD do and commit nothing. Returns data: null and a meta.impact block. Requires the resource's :read scope in addition to the scope this endpoint declares. Must be exactly true or false.
Response · 200

Success

dataMay be null.

FieldTypeAlways presentNotes
object"contact"Yes
idstringYes
deletedtrueYes

meta

FieldTypeAlways presentNotes
request_idstringYes
dry_runbooleanYes
impactobjectNo
impact.object"impact"Yes
impact.would_createintegerYes
impact.would_updateintegerYes
impact.would_deleteintegerYes
impact.affected_countintegerYes
impact.affected_idsstring[]Yes
impact.quotaobject · nullableYes
impact.quota.kindstringYes
impact.quota.would_consumeintegerYes
impact.quota.limitinteger · nullableYes
impact.quota.currentintegerYes
Contactswrite
bulkUpsertContacts

Create or update many contacts

Upserts up to 100 contacts by email, in one transaction: either every row is written or none is. Idempotency-Key is required, because a retried batch that ran the first time must not run twice. Existing contacts are merge-patched exactly as PATCH /contacts/{contactId} would patch them.

https://api.mailneo.co/api/v2
POST/contacts/bulkcontacts:write

Example request

curl -X POST "https://api.mailneo.co/api/v2/contacts/bulk" \
  -H "X-API-Key: $MAILNEO_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      {
        "email": "<string>"
      }
    ]
  }'
Authorization
Required scope
contacts:write. A key without it is refused before the endpoint runs.
Credential
X-API-Key: mk_live_...Authorization: Bearer mk_live_...
Idempotency
Idempotency-Key is required.
Query parameters1
NameTypeRequiredNotes
dry_runbooleanNoReport what this call WOULD do and commit nothing. Returns data: null and a meta.impact block. Requires the resource's :read scope in addition to the scope this endpoint declares. Must be exactly true or false.
Header parameters1
NameTypeRequiredNotes
Idempotency-KeystringYesA caller-chosen unique string, at most 255 characters. Retrying with the same key replays the first response instead of repeating the work; the replay carries Idempotent-Replayed: true. Reusing a key with a different body is a 409 idempotency_key_reused. Keys are remembered for 24 hours. · max 255 chars
Request body

contacts[]Each element of the array.

FieldTypeAlways presentNotes
emailstringYesmax 320 chars · pattern-constrained
first_namestring · nullableNomax 200 chars
last_namestring · nullableNomax 200 chars
companystring · nullableNomax 200 chars
phonestring · nullableNomax 50 chars
websitestring · nullableNomax 500 chars
linkedinstring · nullableNomax 500 chars
twitterstring · nullableNomax 500 chars
facebookstring · nullableNomax 500 chars
sourcestring · nullableNomax 200 chars
status"ACTIVE" | "CONVERTED" | "LOST" | "UNQUALIFIED" | "ARCHIVED"No
tagsstring[]No
custom_fieldsobjectNoopen keys
Response · 200

Success

dataMay be null.

FieldTypeAlways presentNotes
object"bulk_result"Yes
requestedintegerYes
createdintegerYes
updatedintegerYes
resultsobject[]Yes
results[].indexintegerYes
results[].idstringYes
results[].emailstringYes
results[].operation"created" | "updated"Yes

meta

FieldTypeAlways presentNotes
request_idstringYes
dry_runbooleanYes
impactobjectNo
impact.object"impact"Yes
impact.would_createintegerYes
impact.would_updateintegerYes
impact.would_deleteintegerYes
impact.affected_countintegerYes
impact.affected_idsstring[]Yes
impact.quotaobject · nullableYes
impact.quota.kindstringYes
impact.quota.would_consumeintegerYes
impact.quota.limitinteger · nullableYes
impact.quota.currentintegerYes

Next Steps