Skip to main content

Create or Update Contact

Create a contact if they don't exist, or update them if they do — matched by email_address, phone_number, or both.


Endpoint

POST https://api.campaignlark.com/v1/contacts/upsert

Request Body

FieldTypeRequiredDescription
email_addressstringrequiredEmail address used to look up the contact. Always written to the contact record — cannot be changed via this endpoint. Optional when the workspace allows contacts without an email address and a phone_number is provided.
phone_numberstringoptionalPhone number used to look up the contact. Always written to the contact record. Normalized to E.164, so any format resolving to the same number matches the same contact. Requires a workspace field with the phone_number merge tag.
fieldsobjectoptionalKey-value map of additional field values keyed by merge_tag. email_address is ignored here if provided — use the top-level email_address field instead. phone_number is likewise ignored when the top-level phone_number is provided.
tagsarray of integersoptionalTag IDs to assign. On full replace, replaces existing tags. On partial update, preserves existing tags if omitted.
statusstringoptionalContact status. One of SUBSCRIBED, UNSUBSCRIBED, UNCONFIRMED, CLEANED, COMPLAINED. Defaults to SUBSCRIBED if omitted on create or full replace. On partial update, preserves the existing status if omitted.
sms_statusstringoptionalSMS subscription status. One of SUBSCRIBED, UNSUBSCRIBED, CLEANED, BLOCKED. If omitted when updating an existing contact, the current effective SMS status is preserved. If omitted when creating a contact, it is left unset and reported as SUBSCRIBED in responses.
partial_updatebooleanoptionalDefaults to false. If true, only the provided fields are merged into existing data — unspecified fields, tags, and status are preserved. If false, all fields are replaced with the provided values.

Sample Request

POST https://api.campaignlark.com/v1/contacts/upsert
Content-Type: application/json

{
"email_address": "tywin@example.com",
"phone_number": "+14155550123",
"fields": {
"first_name": "Tywin",
"last_name": "Lannister"
},
"tags": [1, 2],
"status": "SUBSCRIBED",
"sms_status": "UNSUBSCRIBED",
"partial_update": true
}

Response

Success — 200 OK

{
"data": {
"id": "64f1a2b3c4d5e6f7a8b9c0d1",
"status": "SUBSCRIBED",
"sms_status": "SUBSCRIBED",
"score": 0,
"tags": [
{ "id": 1, "name": "newsletter" },
{ "id": 2, "name": "vip" }
],
"data": {
"email_address": "tywin@example.com",
"phone_number": "+14155550123",
"first_name": "Tywin",
"last_name": "Lannister"
},
"statistics": {
"total_opens": 0,
"total_clicks": 0,
"total_bounces": 0,
"total_delivered": 0
},
"created_at": "2024-02-15T10:30:00Z",
"updated_at": "2024-02-15T10:30:00Z"
}
}

Behaviour

ScenarioAction
Only email_address givenLooks the contact up by email address.
Only phone_number givenLooks the contact up by phone number. Allowed when the workspace permits contacts without an email address.
Both givenLooks the contact up by either identity. They must resolve to the same contact, or to no contact at all.
Contact not foundCreates a new contact. Status defaults to SUBSCRIBED if not provided.
Contact found, partial_update: falseReplaces all field values with those provided.
Contact found, partial_update: trueMerges provided fields into existing data. Unspecified fields, tags, and status are preserved.

Automation Behaviour

  • Create path: fires CONTACT_SUBSCRIBED_PENDING if status is UNCONFIRMED. No other automation fires for other statuses.
  • Update path: fires TAG_ADDED / TAG_REMOVED if tags change and FIELD_UPDATED if tracked fields change.

Errors

StatusMessageCause
400Email address is required for upsert operation.email_address is missing and the workspace does not allow contacts without an email address.
400A valid email address or phone number is required for upsert operation.Both email_address and phone_number are missing in a workspace that allows contacts without an email address.
400The email address and phone number belong to different contacts in your workspace.email_address and phone_number each match a different existing contact.
400The SMS status you provided is not valid. Valid SMS statuses are: SUBSCRIBED, UNSUBSCRIBED, CLEANED, or BLOCKED.Invalid sms_status value.
400Phone field not found in workspace configuration.A phone_number was provided but the workspace has no field with the phone_number merge tag.
400phone number is invalidThe provided phone_number could not be parsed, or it has no country code and the phone_number field has no default region.
400We were unable to find a field with the merge_tag <tag>A key in fields doesn't match any workspace merge tag.
400The status you provided is not valid.Invalid status value.
400Field '<label>' is required.A workspace-required field was omitted on a full replace or create.