DocumentationCreate or update contact

Create or update contact

PUT /contacts — upsert by email or externalId.

Upsert a single contact. If externalId is set, MailingCore matches on that field; otherwise it matches on email.

Required scope: contacts:write.

PUT https://api.mailingcore.com/contacts
Authorization: Bearer mc_live_xxxx
X-Tenant-Id: clxxxxxxxx
Content-Type: application/json

Request body

{
  "email": "[email protected]",
  "externalId": "crm-user-12345",
  "locale": "en",
  "optIn": true,
  "consentVersion": "privacy-v2",
  "source": "signup",
  "attributes": {
    "firstName": "Alex",
    "plan": "pro"
  },
  "projectId": "clxproject..."
}

Fields

FieldRequiredDescription
emailYesContact email
externalIdNoYour id for idempotent sync (max 128)
localeNoPreferred language for campaigns
optInNoMarketing consent
attributesNoCustom JSON metadata
consentVersionNoConsent text version (max 64)
sourceNoOrigin label (max 64)
projectIdNoScope to an SMTP project

Example

curl -X PUT "https://api.mailingcore.com/contacts" \
  -H "Authorization: Bearer mc_live_xxxx" \
  -H "X-Tenant-Id: clxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "externalId": "crm-user-12345",
    "locale": "en",
    "optIn": true,
    "attributes": { "firstName": "Alex" }
  }'

Typical response: 200 with the contact object (created or updated).

Partial updates

To patch an existing contact by internal id, use PATCH /contacts/{id} with only the fields you want to change.

Common errors

CodeCause
400Invalid email or payload
403Missing contacts:write scope
409externalId conflict with another contact

Next steps