Contact API - Update
Use these endpoints to update existing contacts. You can update one contact by its ID, one contact found by email or another key field, or several contacts in one request.
Endpoints
Section titled “Endpoints”| Method | URL | Description |
|---|---|---|
| PATCH | https://e1.envoke.com/v1/contacts/{ID} |
Update one contact by ID. |
| PATCH | https://e1.envoke.com/v1/contacts |
Update one contact found by key field (object body), or several contacts (list body). |
Authentication is via HTTP Basic Auth using your API ID and API Key. The request body must be JSON.
Query Parameters
Section titled “Query Parameters”| Parameter | Type | Default | Description |
|---|---|---|---|
write_empty_values |
boolean | false |
When 1, true, yes, or on, an empty string ("") clears a field. Otherwise empty values are ignored (see Clearing Values). |
key_field |
string | (see below) | id, email, or remote_id. Used only by PATCH /v1/contacts with an object body. |
Which update is performed
Section titled “Which update is performed”| URL | Body | Update |
|---|---|---|
/v1/contacts/{ID} |
JSON object | Update by ID |
/v1/contacts |
JSON list of objects | Update several contacts |
/v1/contacts |
JSON object | Update one contact found by key field |
A list body sent to /v1/contacts/{ID} is treated as an update of several contacts, and the {ID} in the URL is ignored.
Request Body
Section titled “Request Body”Send only the fields you want to change. Any writable field from the Fields reference can be included, with the same accepted values as on create. Each field is compared with the stored value, and only fields that differ are written; a request that changes nothing still succeeds.
external_id, date_created, and consent_expiry are read-only and silently ignored. id is used to identify the contact, never written.
Note: Custom field values that cannot be stored, nurture campaigns skipped for lack of consent, and consent changes that are preempted or blocked are not reported; the response still reports success.
Update by ID
Section titled “Update by ID”PATCH https://e1.envoke.com/v1/contacts/{ID}Request. A JSON object. Replace {ID} with the Envoke contact ID. key_field is ignored. If the body includes id, it must match {ID} (see ID Mismatch).
Response. A short result, not the full contact. result_data.id is an integer on this endpoint, and result_data.warnings lists any country or language warnings ([] when none):
{ "success": true, "result_text": "The contact was successfully updated.", "result_data": { "id": 1001, "submit_type": "update", "warnings": [] }}When no profile column changed (only custom fields, tags, nurture campaigns, or consent, or nothing at all), result_data also contains "no_affected_rows": true. When an EU country change resets the contact’s consent, result_data also contains inapplicable_consent_updated and consent_fix_message (see example).
Errors.
- Not found: validation envelope with
No contact was found with ID: '999999'. - Body errors (unknown field, invalid value): validation envelope with
result_data.errors. - Field validation (length, email format, duplicate): the field-validation envelope, with an extra
warningskey:{"success":false,"result_data":{"fields":{"fname":"First name must not exceed 50 characters"},"warnings":[]},"result_text":"First name must not exceed 50 characters"}. - ID mismatch:
{"success":false,"result_data":[],"result_text":"Contact 'id': 1001 does not match 'id' in request body (1002)"}.
Update several contacts
Section titled “Update several contacts”PATCH https://e1.envoke.com/v1/contactsRequest. A JSON list of contact objects. Each object is matched on its own:
- If it has an
id, that ID is used directly (it is not looked up first). - Otherwise it is matched by
email.
key_field is ignored for list bodies, so contacts cannot be matched by remote_id this way. Each object is then updated exactly as in Update by ID.
Response. When every contact is updated, HTTP 200. The envelope has two extra top-level keys, successes and failures, listing contact IDs, and result_data holds each contact’s result keyed by ID:
{ "success": true, "successes": ["1006", "1007"], "failures": [], "result_data": { "1006": { "id": 1006, "submit_type": "update", "warnings": [] }, "1007": { "id": 1007, "submit_type": "update", "warnings": [] } }, "result_text": "All contacts were successfully updated"}Partial failure. If any contact fails, the whole response is HTTP 400 with success: false, even though the other contacts were updated. The failed ones are listed in failures:
- A contact that could not be found is keyed
CONTACT_OBJECT_{n}, where{n}is its zero-based position in the list, with the lookup error inerrors. - A contact that was found but failed validation is keyed by its ID, with the same
errorsorfieldsandwarningscontent as Update by ID.
{ "success": false, "successes": ["1006", "1007"], "failures": ["CONTACT_OBJECT_2"], "result_data": { "1006": { "id": 1006, "submit_type": "update", "warnings": [] }, "1007": { "id": 1007, "submit_type": "update", "warnings": [] }, "CONTACT_OBJECT_2": { "errors": ["No contact was found with the 'email': 'missing.member@example.com'"] } }, "result_text": "2 contacts were successfully updated; 1 contacts were not updated"}Errors (per contact, in result_data):
No contact was found with the 'email': '{email}'No contact was found with ID: '{id}'(anidthat does not exist)Multiple contacts were found with the 'email': '{email}'. (IDs: 1006, 1012)(two spaces before the bracket)An 'id' or 'email' (or alternate field specified by key_field query parameter) must be provided in order to update a contact
Update one contact found by key field
Section titled “Update one contact found by key field”PATCH https://e1.envoke.com/v1/contactsRequest. A JSON object. The contact is found by key_field:
key_field |
Lookup |
|---|---|
| (not set) | By id if the body has one (used directly, not looked up first); otherwise by email. |
id |
By id, looked up. |
email |
By email. |
remote_id |
By remote_id. |
Because the key value is used only to find the contact, a body with id and a new email (and no key_field) changes that contact’s email address.
Response. The full, updated contact, in the same shape as a read. Warnings are appended to result_text after . , which follows the success message’s own period:
{ "success": true, "result_text": "The contact was successfully updated.. 'Narnia' is not a valid value for country; field will not be updated", "result_data": { "id": "1002", "email": "tenor.remote@example.com", "remote_id": "HCS-0002", "first_name": "Dan", "country": "" }}(result_data shortened; the response contains every field.)
Errors. Lookup failures use a plain envelope with result_data: [], not the validation envelope:
result_text |
Cause |
|---|---|
No contact was found with the 'email': 'nobody@example.com' |
No contact has that key value. With key_field=id, the message names 'id'. |
Multiple contacts were found with the 'remote_id': 'HCS-0002'. (IDs: 1002, 1010) |
More than one contact has the key value. |
Specified key_field 'remote_id' field was not provided. |
key_field is set but the body does not include that field. |
An 'id' or 'email' (or alternate field specified by key_field query parameter) must be provided in order to update a contact |
No key_field, and the body has neither id nor email. |
Invalid 'key_field' value: 'external_id' |
key_field is not id, email, or remote_id. |
The specified contact ID 1002 does not match record identified by key_field 'email': 'alto.lead@example.com' (ID: 1001) |
See ID Mismatch. |
Once the contact is found, update errors are the same as for Update by ID. When the body has an id and no key_field, a missing ID gives the validation envelope with No contact was found with ID: '{id}'.
Clearing Values
Section titled “Clearing Values”| Value sent | Without write_empty_values |
With write_empty_values=1 |
|---|---|---|
null |
Ignored | Ignored |
"", 0, "0", false, [] |
Ignored | "" clears a text field |
Custom field value "" |
Deletes the custom field value | Deletes the custom field value |
- A custom field is cleared by sending
""as its value insidecustom_fields. This works with or withoutwrite_empty_values. emailcannot be cleared:Email must not be empty.countryandlanguagecannot be cleared; an empty value leaves them unchanged.- Tags, subscriptions, and nurture campaigns are removed with the object form (
{ "Alumni": "Unset" }), not by sending an empty list.
Consent Changes
Section titled “Consent Changes”Consent is written only when consent_status, consent_description, or consent_effective_date differs from the stored value. When one of them changes, all the consent fields in the body are applied together, and the contact’s current status is used if consent_status was not sent. consent_force_downgrade on its own does nothing.
Whether a new status becomes current follows the transition rules in Consent fields. A downgrade (for example Express to an implied type) is recorded in the contact’s history but not made current unless consent_force_downgrade is true. A change away from a spam-reported status, or from Revoked to Not Provided, is blocked.
Note: A preempted or blocked consent change is not reported. The response is the normal success message, and the contact’s consent_status is unchanged.
ID Mismatch
Section titled “ID Mismatch”PATCH /v1/contacts/{ID}: if the body includesidand it differs from{ID}, the request fails with{"success":false,"result_data":[],"result_text":"Contact 'id': 1001 does not match 'id' in request body (1002)"}."1001"and1001count as the same.PATCH /v1/contactswithkey_field=emailorremote_id: if the body includesidand it differs from the contact the key field found, the request fails with{"success":false,"result_data":[],"result_text":"The specified contact ID 1002 does not match record identified by key_field 'email': 'alto.lead@example.com' (ID: 1001)"}.
Validation Errors
Section titled “Validation Errors”{ "success": false, "result_text": "Validation failed, see 'result_data' -> 'errors'", "result_data": { "errors": [ "No contact was found with ID: '999999'" ] }}Common errors:
| Error | Cause |
|---|---|
Invalid request |
No body, an empty body, {}, or []. Plain envelope with result_data: []. |
Invalid JSON |
The body is not valid JSON. Plain envelope with result_data: []. |
No contact was found with ID: '{id}' |
The ID does not match any contact in your account. |
'nickname' is not a valid contact field |
The body has a key that is not a contact field. |
Email must not be empty |
email was sent as "" with write_empty_values=1. Field-validation envelope. |
contact with email = alto.lead@example.com already exists |
The new email belongs to another contact. Field-validation envelope. |
The body validation errors listed for create (consent status, effective date, custom fields, interests, autoresponders) apply to updates too.
Examples
Section titled “Examples”Update by ID
Section titled “Update by ID”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"title": "Alto Section Lead", "phone": "416-555-0199"}' \ "https://e1.envoke.com/v1/contacts/1001"Update by email
Section titled “Update by email”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"email": "alto.lead@example.com", "company": "Harbourfront Choral Society"}' \ "https://e1.envoke.com/v1/contacts"Returns the full contact in result_data.
Update by remote ID
Section titled “Update by remote ID”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"remote_id": "HCS-0002", "first_name": "Dan"}' \ "https://e1.envoke.com/v1/contacts?key_field=remote_id"Clear a value
Section titled “Clear a value”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"address_2": ""}' \ "https://e1.envoke.com/v1/contacts/1001?write_empty_values=1"Without write_empty_values=1 the same request succeeds but leaves address_2 unchanged.
Clear a custom field
Section titled “Clear a custom field”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"custom_fields": {"Season_Ticket_Number": ""}}' \ "https://e1.envoke.com/v1/contacts/1001"Remove a tag
Section titled “Remove a tag”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"interests": {"Alumni": "Unset"}}' \ "https://e1.envoke.com/v1/contacts/1001"Other tags and subscriptions are left as they are.
Stop a nurture campaign
Section titled “Stop a nurture campaign”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"autoresponders": {"Welcome Sequence": "Dequeue"}}' \ "https://e1.envoke.com/v1/contacts/1001"Force a consent downgrade
Section titled “Force a consent downgrade”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"consent_status": "Implied - Transaction", "consent_description": "Ticket purchase only; express consent withdrawn by phone", "consent_force_downgrade": true}' \ "https://e1.envoke.com/v1/contacts/1001"The contact had Express consent. Without consent_force_downgrade the request returns the same success message but consent_status stays Express.
Update several contacts, one of which is missing
Section titled “Update several contacts, one of which is missing”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '[{"email": "bulk.a@example.com", "city": "Hamilton"}, {"email": "bulk.b@example.com", "city": "Hamilton"}, {"email": "missing.member@example.com", "city": "Hamilton"}]' \ "https://e1.envoke.com/v1/contacts"The first two contacts are updated; the response is HTTP 400 (see Partial failure).
Change country to an EU country
Section titled “Change country to an EU country”curl -X PATCH -gs \ -u "$API_ID:$API_KEY" \ -H "Content-Type: application/json" \ -d '{"country": "Germany"}' \ "https://e1.envoke.com/v1/contacts/1004"The contact had Implied - Inquiry consent, which does not apply in the EU region, so it is set to Not Provided:
{ "success": true, "result_text": "The contact was successfully updated. Their consent status was updated because Implied - Inquiry consent does not apply to contacts in the EU.", "result_data": { "id": 1004, "submit_type": "update", "inapplicable_consent_updated": true, "consent_fix_message": " Their consent status was updated because Implied - Inquiry consent does not apply to contacts in the EU.", "warnings": [] }}Note: The curl examples above are formatted for readability. All requests must use properly encoded URLs.
Full reference, OpenAPI description, and Postman collection: developers.envoke.com.

