Skip to main content
Contacts API

Create or update contact

v2

Create a new contact, or update one that already exists, in a single call. The HTTP status itself tells you what happened — 201 for created, 200 for updated or unchanged, 409 for a duplicate or suppressed contact — so a plain response.ok check is all you need. To sync multiple contacts in a single API call, use the batch endpoint instead.

POSThttps://api.scorehq.co/api/v2/contacts

Send your secret key in the x-api-key header. Never call this endpoint directly from a browser. Authentication details

Authenticationx-api-key
Rate limit300 / 60 sec (shared)
Contacts per requestExactly 1
Body limit1 MB JSON
01

Request body

A single contact object — sending an array here returns 400 INVALID_REQUEST.

emailstringrequired
Contact email address. Score trims whitespace and converts it to lowercase before matching.
list_idsstring[]required
Between 1 and 20 unique list IDs. Every list must exist, be active, and belong to your organization.
overwriteboolean
Defaults to false. Set it to true to merge fields into an existing contact. See Overwrite behavior.
fieldsobject
Standard contact fields and existing custom fields. Omitted fields are left unchanged.

Standard and custom fields

These keys inside fields map directly to built-in contact properties.

first_name · stringlast_name · stringphone · stringcity · stringcountry · string

Every other key is a custom field and must already exist under Settings → Custom Fields. Unknown names fail with UNKNOWN_FIELD; the API never creates definitions. Custom fields support text, number, date, and boolean. Dates accept 2026-08-31 or a full timestamp such as 2026-08-31T14:30:00Z, with or without milliseconds.

Clearing fields

Leave unchanged

Omit the key from fields.

Clear an optional field

Send null.

Clear a text field

Send "" (an empty string).

Clear a required custom field

Not allowed; returns REQUIRED_FIELD_MISSING.

Custom fields are merged into the stored set, never replaced wholesale. Sending one custom field never removes the others.

02

Overwrite behavior

How existence, status, and overwrite determine the result and the HTTP status you get back.

New contacttrue or false

Created and added to every list in list_ids. Returns 201.

Active contactfalse

Nothing changes. Returns 409 DUPLICATE_EMAIL.

Active contacttrue

Sent fields are merged and new list memberships are added. Returns 200.

Suppressed contactfalse

Nothing changes. Returns 409 SUPPRESSED_EMAIL.

Suppressed contacttrue

Profile fields update, but no lists or journeys are added. Returns 200.

Suppressed contacts stay protected

Even with overwrite: true, this endpoint never re-subscribes a bounced, complained, or unsubscribed contact. It does not add them to a list or enroll them in a journey. Re-enabling email must be done deliberately through suppression management in the dashboard.

Adding an active existing contact to a new list can enroll them in a published journey with a matching list-entry trigger, just as a dashboard or CSV import can.

03

Response

Exactly one outcome, reported as the HTTP status itself.

The response body is the contact's result directly — email, status, and either list_ids_added/fields_changed on success or code/message on failure. There's no wrapper array and no summary counts, since there's only ever one contact to describe.

A caller that only checks response.ok gets the right answer: 201 and 200 mean the write happened, anything 4xx means it didn't.

04

Errors

Request-level errors return before any contact logic runs; everything else is the contact's own outcome.

Request-level errors

Nothing is written when one of these occurs.

400INVALID_REQUEST

An array was sent to this endpoint — send an object with exactly one contact, or use the batch endpoint for multiple.

401INVALID_API_KEY

The API key is missing, invalid, expired, or revoked.

413PAYLOAD_TOO_LARGE

The decoded JSON request body is larger than 1 MB.

429RATE_LIMIT_EXCEEDED

The organization exceeded 300 requests in 60 seconds — shared with the batch endpoint.

500INTERNAL_ERROR

Score could not complete the request.

Request-level error shape
{
"request_id": "req_01J7X8W3E4N8",
"error": {
"code": "INVALID_API_KEY",
"message": "The supplied API key is invalid"
}
}

Contact outcome errors

Each of these is the response — the HTTP status shown below is what you'll actually receive, not a code buried in a body you have to check.

400INVALID_EMAIL

The email isn't valid after trimming and lowercasing.

409DUPLICATE_EMAIL

The contact exists and overwrite was not set to true.

409SUPPRESSED_EMAIL

The contact is suppressed and overwrite was not set to true.

400EMPTY_LIST_IDS

No list ID was provided.

400TOO_MANY_LIST_IDS

More than 20 list IDs were provided.

400INVALID_LIST

A list doesn't exist, is archived, or belongs to another organization.

400UNKNOWN_FIELD

A fields key doesn't match a standard or existing custom field.

400FIELD_TYPE_MISMATCH

A value doesn't match its field's configured type.

400REQUIRED_FIELD_MISSING

A required custom field has no value or was cleared with null.

One code from the full error reference doesn't apply here: DUPLICATE_IN_REQUEST can only occur when the same email appears twice in one request, which requires the batch endpoint.

INVALID_LIST response detail
{
"request_id": "req_...",
"email": "alex@example.com",
"status": "failed",
"code": "INVALID_LIST",
"message": "One or more lists were not found in this organization",
"invalidListIds": ["000000000000000000000000"]
}