Merge a contact into another
POST/v1/contacts/{id}/merge
Requires an API key with the contacts:write scope. About keys and scopes
Works with integration and partner keys, not agent keys.
A repeat after success returns 404 or 409: treat that as done. About idempotency
Merges this contact, a duplicate, into the one keep names, for one person recorded twice. The kept contact keeps its values and gains any the duplicate had that it lacks: identifiers, name, timezone, country, locale, and attributes and dates by key. An email address or phone it gains brings that channel's consent with it; its own consent otherwise stands. The duplicate's messages, events, conversions, devices and consent changes move to the kept contact; its lists and suppressions are added, and its topic choices fill in topics the kept contact has not chosen. Then the duplicate is deleted, ending its journey enrollments. It cannot be undone. While a message to either is being handed to the provider, which takes seconds, it returns 409 CONTACT_SEND_IN_PROGRESS; retry shortly. A message waiting to be retried moves to the kept contact and still sends; the duplicate's copy of a campaign both received is skipped (contact_deleted) instead; a push that already reached one of the duplicate's devices is marked sent, and one a push service refused is marked failed, as it would have ended anyway. A keep that names no contact is a 404, and merging a contact into itself a 400 at keep.
Path parameters
idstringrequiredKirora's id for the contact, your own with
idType=externalId, or its email address withidType=email, URL-encoded (@as%40).1–255 characters
Query parameters
idTypestringoptionalWhat
{id}is: Kirora's id for the contact (id, the default), your own (externalId, as set with identify) or its email address (email, matched trimmed and without case).one of
id,externalId,email· default"id"
Header parameters
Kirora-WorkspacestringoptionalPartner keys only: the child workspace to act in, by the external id the partner gave it. Without it, a partner key acts in its own workspace. Any other key that sends it is refused with 403, and an unknown workspace is 404.
pattern
^[A-Za-z0-9._:-]{1,128}$Idempotency-KeystringoptionalMakes a retry safe: a repeat with the same key and body within 24 hours gets the first response again, with
Idempotency-Replay: true. The same key with another request is 409IDEMPOTENCY_KEY_REUSED; while the first is still running, 409IDEMPOTENCY_KEY_IN_USE; after anunsafefirst request failed or never returned, 409IDEMPOTENCY_KEY_OUTCOME_UNKNOWN. Use a new key, such as a UUID, for each new request.8–255 characters
Request body
keepobjectrequiredThe contact to keep, named one way; the contact in the path merges into it and is deleted.
Any of 3 shapes
- By contact id
1 child attribute
contactIdstringrequiredKirora's id for the contact.
uuid
- By external id
1 child attribute
externalIdstringrequiredYour own id for the contact, as set with identify.
1–255 characters
- By email
1 child attribute
emailstringrequiredThe contact's email address, matched trimmed and without case.
Returns
Returns 200 OK with a ContactDetail in data. It can also return 409 Conflict, 413 Payload Too Large or 415 Unsupported Media Type; see the statuses below. Otherwise returns an error; Errors lists every code and which to retry.
200 OKThe kept contact, after the merge.409 ConflictThe request conflicts with current state — a duplicate unique value, or a resource whose status does not allow this operation.413 Payload Too LargeThe body is larger than this operation accepts (PAYLOAD_TOO_LARGE).415 Unsupported Media TypeThe body is not JSON, or not the upload the operation takes (UNSUPPORTED_MEDIA_TYPE).
idstringrequireduuid
externalIdstring | nullrequiredYour own id for the contact, if set.
emailstring | nullrequiredemail
firstNamestring | nullrequiredlastNamestring | nullrequiredphonestring | nullrequiredPhone number in E.164 format.
timezonestring | nullrequiredIANA timezone, e.g.
Europe/London.countrystring | nullrequiredISO 3166-1 alpha-2 code: as written, or inferred from the phone, else the timezone.
localestring | nullrequiredBCP 47 tag (
fr,fr-CA): the language the contact reads (its first subtag), and how merge tags format numbers, dates and money for them.rfmobject | nullrequiredThe contact's RFM (recency, frequency and monetary value) group among the workspace's customers, from its purchase events (the workspace's
purchaseEvent: an order, a paid invoice, a booking, a donation), each score from 1 to 5 (a fifth of the customers each; 5 is the most recent, most frequent or highest spend), and their purchase totals. Spend counts only purchases in the workspace's main currency; when the purchase carries no amount,monetaryfollows frequency. Recomputed daily, so a purchase today shows tomorrow;nullfor someone who has never purchased.7 child attributes
groupstringrequiredone of
champions,loyal,cant_lose_them,potential_loyalists,new_customers,need_attention,about_to_sleep,at_risk,hibernating,lostrecencyintegerrequiredmin 1 · max 5
frequencyintegerrequiredmin 1 · max 5
monetaryintegerrequiredmin 1 · max 5
purchaseCountintegerrequiredTheir purchase events (the workspace's
purchaseEvent), in any currency.min > 0
totalSpentobject | nullrequiredWhat their purchases' amounts (
purchaseValueProperty) add up to, in the workspace's main currency (currencyonGET /v1/reports/rfm); purchases in other currencies and refunds are left out.nullwhen the purchase carries no amount.2 child attributes
currencystring | nullrequiredThe currency, an ISO 4217 code; null when none was named.
valuenumberrequiredThe amount in that currency.
lastPurchasedAtstringrequiredWhen their latest purchase happened.
date-time
datesmap<string, string>requiredNamed calendar dates, e.g.
birthday, asYYYY-MM-DDor--MM-DD.attributesmap<string, object>requiredCustom attributes, keyed by attribute name.
consentContactConsentrequiredConsent on each channel.
2 child attributes
emailbooleanrequiredWhether the contact has consented to email.
pushbooleanrequiredWhether the contact has consented to push.
createdAtstringrequireddate-time
updatedAtstringrequireddate-time
emailSuppressionobjectrequired2 child attributes
suppressedbooleanrequiredWhether email to this contact is blocked.
reasonstring | nullrequiredWhy email to this contact is suppressed:
bounced,complained,complained_transactional,unsubscribed,manual,imported, orother_workspace(a bounce or complaint in another workspace with the same owner or partner).
listIdsstring[]requiredIds of the lists the contact is in.
Headers on 200 OK
Idempotency-Replaystringoptionaltruewhen this is the stored response to an earlier request with the same key.one of
true