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
| Field | Required | Description |
|---|---|---|
email | Yes | Contact email |
externalId | No | Your id for idempotent sync (max 128) |
locale | No | Preferred language for campaigns |
optIn | No | Marketing consent |
attributes | No | Custom JSON metadata |
consentVersion | No | Consent text version (max 64) |
source | No | Origin label (max 64) |
projectId | No | Scope 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
| Code | Cause |
|---|---|
| 400 | Invalid email or payload |
| 403 | Missing contacts:write scope |
| 409 | externalId conflict with another contact |
Next steps
- Bulk import — sync thousands of contacts in one call
- Contacts overview — list, filter, and GDPR erasure