Update a contact
Move someone through your funnel, merge attributes, set your own id, or override a trust verdict.
Requires the contacts:write scope.
Body parameters#
| Parameter | Type | Description |
|---|---|---|
stage |
string | Must be one of this project's configured pipeline stages |
attributes |
object | Merged by key, up to 50 keys. A null value deletes that key |
email |
string | The address the contact is mailed at, for a contact identified by something else. null clears it |
external_id |
string | Your own id, unique per project. null clears it |
trust_override |
enum | verified, valid, unknown, risky or fake. null hands the verdict back to the engine |
Every parameter is optional; send only what you are changing. Identity is not among them, for the reason below.
An external_id another contact in this project already holds returns 422 external_id_taken.
Attributes merge, they do not replace#
Sending attributes updates only the keys you send. Everything else stays.
{ "attributes": { "cohort": "beta-2", "source": null } }
That sets cohort and deletes source, leaving every other attribute untouched. Replacing the
whole object would mean every caller has to read-modify-write, which is a race waiting to happen.
Contacts past your plan's size#
A contact hidden past your plan's contact size cannot be edited. The request answers 403 with
code: contact_hidden and param: contact, and nothing is written: stage, attributes,
trust_override and external_id stay as they were. The contact is saved, and editing works again
once the workspace moves up a size. Deleting a hidden contact still works.
Changing the email address#
email is where a contact is mailed, which is separate from who they are. On a contact identified
by a phone number, a username or a wallet you can set it, change it, or clear it with null. It is
canonicalized before it is stored.
Changing or clearing an address the contact already has resets what was known about the old one:
verified_at becomes null and deliverability returns to unknown, because both were facts
about a mailbox the contact no longer uses. status stays as it is. Setting an address on a contact
that had none resets nothing.
On a contact identified by an email, email is ignored. There the address is the identifier.
Identity is not editable#
There is no way to change identifier. Identity is resolved, not edited. A different
identifier is a different person, and quietly rewriting one would corrupt deduplication and the
referral graph.
If you genuinely have two records for one human, that is a merge, and merging is not something this endpoint should do silently.
Telling us somebody converted#
converted is the one stage nothing in LaunchList ever sets for you, and that is deliberate:
whether somebody paid happens inside your product, on your servers, and we would only be guessing.
This endpoint is how you close that loop.
{ "stage": "converted" }
Call it when the thing you actually care about happens: subscription created, plan upgraded,
first order placed. The same applies to any stage you added yourself: stage accepts any key from
your funnel, so a project with an activated stage can report activation the same way.
Next#
- Delete a contact
- Core concepts for what a stage is