Merge a contact into anotherMenu

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

idstringrequired

Kirora's id for the contact, your own with idType=externalId, or its email address with idType=email, URL-encoded (@ as %40).

1–255 characters

Query parameters

idTypestringoptional

What {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-Workspacestringoptional

Partner 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-Keystringoptional

Makes 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 409 IDEMPOTENCY_KEY_REUSED; while the first is still running, 409 IDEMPOTENCY_KEY_IN_USE; after an unsafe first request failed or never returned, 409 IDEMPOTENCY_KEY_OUTCOME_UNKNOWN. Use a new key, such as a UUID, for each new request.

8–255 characters

Request body

keepobjectrequired

The 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
contactIdstringrequired

Kirora's id for the contact.

uuid

By external id
1 child attribute
externalIdstringrequired

Your own id for the contact, as set with identify.

1–255 characters

By email
1 child attribute
emailstringrequired

The 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).
idstringrequired

uuid

externalIdstring | nullrequired

Your own id for the contact, if set.

emailstring | nullrequired

email

firstNamestring | nullrequired
lastNamestring | nullrequired
phonestring | nullrequired

Phone number in E.164 format.

timezonestring | nullrequired

IANA timezone, e.g. Europe/London.

countrystring | nullrequired

ISO 3166-1 alpha-2 code: as written, or inferred from the phone, else the timezone.

localestring | nullrequired

BCP 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 | nullrequired

The 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, monetary follows frequency. Recomputed daily, so a purchase today shows tomorrow; null for someone who has never purchased.

7 child attributes
groupstringrequired

one of champions, loyal, cant_lose_them, potential_loyalists, new_customers, need_attention, about_to_sleep, at_risk, hibernating, lost

recencyintegerrequired

min 1 · max 5

frequencyintegerrequired

min 1 · max 5

monetaryintegerrequired

min 1 · max 5

purchaseCountintegerrequired

Their purchase events (the workspace's purchaseEvent), in any currency.

min > 0

totalSpentobject | nullrequired

What their purchases' amounts (purchaseValueProperty) add up to, in the workspace's main currency (currency on GET /v1/reports/rfm); purchases in other currencies and refunds are left out. null when the purchase carries no amount.

2 child attributes
currencystring | nullrequired

The currency, an ISO 4217 code; null when none was named.

valuenumberrequired

The amount in that currency.

lastPurchasedAtstringrequired

When their latest purchase happened.

date-time

datesmap<string, string>required

Named calendar dates, e.g. birthday, as YYYY-MM-DD or --MM-DD.

attributesmap<string, object>required

Custom attributes, keyed by attribute name.

consentContactConsentrequired

Consent on each channel.

2 child attributes
emailbooleanrequired

Whether the contact has consented to email.

pushbooleanrequired

Whether the contact has consented to push.

createdAtstringrequired

date-time

updatedAtstringrequired

date-time

emailSuppressionobjectrequired
2 child attributes
suppressedbooleanrequired

Whether email to this contact is blocked.

reasonstring | nullrequired

Why email to this contact is suppressed: bounced, complained, complained_transactional, unsubscribed, manual, imported, or other_workspace (a bounce or complaint in another workspace with the same owner or partner).

listIdsstring[]required

Ids of the lists the contact is in.

Headers on 200 OK

Idempotency-Replaystringoptional

true when this is the stored response to an earlier request with the same key.

one of true