Contacts

Create or update a contact by e-mail

Creates or updates one contact by e-mail and returns it whole, as get_contact does. Call it to push a contact from another system, such as a CRM, without looking it up first; for many contacts at once, upsert_contacts.

The contact is found by email, without case, and updated; when the address is free it is created. The address of a deleted contact restores that contact with its old data and applies the request over it. result says which: created and restored answer 201, updated and unchanged (nothing to change, nothing written) answer 200.

A field left out is kept; null clears first_name, last_name, phone, country, timezone and language; fields are keyed by field ids from list_contact_fields, merged by key, and null removes a value. Tags go by name, compared without case: add_tags adds them and creates a tag the site does not have, remove_tags takes them off; tags not named stay. changed names the fields that were written.

Status: subscribed is allowed from unsubscribed, and subscribes again a contact who opted out, as the admin does; leave status out to keep what the contact chose. unsubscribed is allowed from subscribed or from awaiting double opt-in. A bounced contact changes status only with a new e-mail, and a contact awaiting double opt-in is never subscribed here. A status change that is not allowed does not stop the rest: the other fields are written and reason says why.

A new contact is subscribed unless status says unsubscribed, which stores it as never subscribed; it cannot be created bounced. Its source is api, with the API key as id, or the user when the call is made with a user's access token. A contact created here starts "new contact" automations when subscribed and emits contact.created; a restored one does neither. Its e-mail is checked in the background. A found contact keeps the stored case of its e-mail and its source.

post/v1/sites/{site_id}/contacts

Request

  • Base URL
    https://api.getsitecontrol.com
  • Auth
    HTTP bearer

Path parameters

site_idinteger required

Headers

Idempotency-Keystring

Makes a retry of a POST safe: a repeat with the same key, body and GSC-Version returns the stored response with Idempotency-Replayed: true instead of running again. The key protects against repeated execution while the key store works. Saving the change and storing the response under the key are not atomic: if the process or the key store fails between them, the change is kept, the key is released after 15 minutes and a retry runs the request again. After a timeout or a 5xx, read the resource to check the result before retrying. 5xx and 429 responses and responses over 256 KB are not stored, so a repeat runs the request again. A key is kept for 24 hours. The same key with another body or version is 422; a repeat while the first request runs is 409.

Request body

emailstring required

Finds the contact, without case; kept as stored when found, stored in lower case when created

status'subscribed' | 'unsubscribed'

subscribed or unsubscribed; bounced is set only by e-mail delivery. Left out: unchanged, a new contact is subscribed; may not be null

first_namestring nullable

null clears it

last_namestring nullable

null clears it

countrystring nullable

ISO 3166-1 alpha-2 code or an English country name; stored as the code; null clears it

phonestring nullable

In the international format, or national with country in the same request; stored normalized; null clears it

timezonestring nullable

IANA time zone name such as Europe/Berlin; null clears it

languagestring nullable

ISO 639-1 code such as de; stored in lower case; null clears it

fieldsobject

Values by field id from list_contact_fields: a string for text, a whole number for integer, a number, an ISO 8601 string for a datetime (UTC without an offset), YYYY-MM-DD for a date, true or false for a boolean. Fields of the other type are read-only. Merged into the stored values: null removes a value, keys not given stay as they are

add_tagsstring[]

Tag names to add, compared without case; a tag the site does not have is created. Tags the contact has stay

remove_tagsstring[]

Tag names to remove, compared without case; a name with no tag, or a tag the contact does not have, is no change. Never creates a tag

Response

The contact existed: updated, or nothing to change

result'created' | 'updated' | 'restored' | 'unchanged' | 'failed' required

created: a new contact, by upsert_contacts or upsert_contact. updated: something was written, changed names it; in delete_contacts the contact was deleted. restored: the address belonged to a deleted contact, which is back with its old data and the item applied over it. unchanged: nothing to change, nothing written; in delete_contacts the contact was deleted before. failed: nothing of this item was written, see reason.

changedstring[] required

Names of the fields whose stored value changed, from is_deleted, email, status, first_name, last_name, phone, country, timezone, language, fields, tags; empty when none did. A new contact names email, status and every field it was given; a restored one starts with is_deleted

reason'contact_not_found' | 'contact_email_taken' | 'contact_tag_invalid' | 'contact_field_invalid' | 'contact_unreadable' | 'contact_status_transition' | 'contact_value_invalid'

contact_not_found: no contact of the site has this id or e-mail; in update_contacts also a deleted one. contact_email_taken: the e-mail belongs to another contact of the site, live or deleted, or another request took it at the same moment. contact_tag_invalid: a tag name is empty or too long, see detail. contact_field_invalid: an unknown field, a field of the other type or a value of another type, see detail. contact_unreadable: the stored contact cannot be read; it can only be deleted. contact_status_transition: the status change is not allowed, the other fields were written; detail says why. contact_value_invalid: an e-mail, country, phone, time zone or language that cannot be read, detail names it.

detailstring nullable

Changes

No recorded changes to this operation across all 1 revision of this API.