PUT/contacts

PUT /contacts

Upsert a contact by email: create it, or merge the payload into the existing record.

View as Markdown

Request

curl -X PUT 'https://api.sendheron.com/api/v1/contacts' \
  -H 'Authorization: Bearer <YOUR_API_KEY>' \
  -H 'Content-Type: application/json'

Required scopes

The key must carry these:

  • contacts:write

Body parameters

NameTypeRequiredDescription
emailstringYesMatch key for the upsert.
firstNamestringNoFirst name.
lastNamestringNoLast name.
propertiesobjectNoCustom fields, merged into any existing properties.
statussubscribed | unsubscribed | bounced | complainedNoA contact already bounced, unsubscribed or complained cannot be pushed back to subscribed here. Only a person in the dashboard can do that.
sourcemanual | import | api | form | syncNoHow the contact was acquired.
tagIdsuuid[]NoTags to attach by id, merged with the ones already there.
tagNamesstring[]NoTags to attach by name. Names that do not exist yet are created.
removeTagNamesstring[]NoTags to detach by name, for clearing a superseded lifecycle tag. Never creates anything, and is a no-op if the contact does not carry them.

Responses

Returns 200 on success.

400
The payload failed validation, or the request is not valid for the current state. The body's `description` names the field and says what was wrong with it in words, e.g. "domain: domain must be a bare hostname such as acme.com, with no scheme, path, or port". The `error` code is stable and safe to branch on; `description` is for the human reading the log.
401
Missing or invalid API key.
403
Valid key, but it does not carry the required scope. The `error` code is `apiKeys.insufficientScopes` and the `description` names both halves of the problem: "Missing required scope(s): X. This key holds: Y." Neither is a secret, since the required scopes are on this page and the held ones are your own credential, and a bare "Forbidden" costs a debugging pass to work out which of the two it was.
404
No such record in this workspace. An id belonging to a different workspace returns this too, never a 403, because the API will not confirm that a record exists outside the workspace your key was issued in. Read it as "not yours or not there" rather than as "definitely gone".
409
A duplicate, or an idempotency key reused with a different payload.
429
Either rate-limit ceiling was exceeded.

Rate limits

100/min per key, counted against the organization's WRITE ceiling (400/min). Both windows are one minute. There is no hourly or daily quota.