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.


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.
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.
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.
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",
"fields": {
"first_name": "Tywin",
"last_name": "Lannister"
},
"tags": [1, 2],
"status": "SUBSCRIBED",
"partial_update": true
}

Response

Success — 200 OK

{
"data": {
"id": "64f1a2b3c4d5e6f7a8b9c0d1",
"status": "SUBSCRIBED",
"tags": [
{ "id": 1, "name": "newsletter" },
{ "id": 2, "name": "vip" }
],
"data": {
"email_address": "tywin@example.com",
"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
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.
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.