Skip to content

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.


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.

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.
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.


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.


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 warnings key: {"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)"}.

PATCH https://e1.envoke.com/v1/contacts

Request. 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 in errors.
  • A contact that was found but failed validation is keyed by its ID, with the same errors or fields and warnings content 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}' (an id that 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

PATCH https://e1.envoke.com/v1/contacts

Request. 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}'.


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 inside custom_fields. This works with or without write_empty_values.
  • email cannot be cleared: Email must not be empty.
  • country and language cannot 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 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.


  • PATCH /v1/contacts/{ID}: if the body includes id and 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" and 1001 count as the same.
  • PATCH /v1/contacts with key_field=email or remote_id: if the body includes id and 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)"}.

{
"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.


Terminal window
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"
Terminal window
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.

Terminal window
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"
Terminal window
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.

Terminal window
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"
Terminal window
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.

Terminal window
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"
Terminal window
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”
Terminal window
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).

Terminal window
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.