Sync a contact batch
v2Send up to 50 contacts in one request. This endpoint always returns 200 for a syntactically valid request — even if every contact in it fails — because a batch's outcomes can't collapse into one status code. Only sending one contact? Use the single-contact endpoint instead, which returns a real per-outcome status.
https://api.scorehq.co/api/v2/contacts/batchSend your secret key in the x-api-key header. Never call this endpoint directly from a browser. Authentication details
Request body
An array of 1–50 contact objects — sending a bare object here returns 400 INVALID_REQUEST.
emailstringrequiredlist_idsstring[]requiredoverwritebooleanfieldsobjectStandard and custom fields
These keys inside fields map directly to built-in contact properties.
first_name · stringlast_name · stringphone · stringcity · stringcountry · stringEvery other key is a custom field and must already exist under Settings → Custom Fields. Unknown names fail that row 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
Omit the key from fields.
Send null.
Send "" (an empty string).
Not allowed; that row returns REQUIRED_FIELD_MISSING.
Custom fields are merged into the stored set, never replaced wholesale. Sending one custom field never removes the others.
One email per request
A normalized email may appear only once per batch. A repeated email fails both of its rows with DUPLICATE_IN_REQUEST — duplicate rows are never merged automatically.
Overwrite behavior
How existence, status, and overwrite determine each contact's own result.
true or falseCreated and added to every list in list_ids. Row status created.
falseNothing changes. Row status failed, code DUPLICATE_EMAIL.
trueSent fields are merged and new list memberships are added. Row status updated or unchanged.
falseNothing changes. Row status failed, code SUPPRESSED_EMAIL.
trueProfile fields update, but no lists or journeys are added. Row status updated or unchanged.
Even with overwrite: true, this endpoint never re-subscribes a bounced, complained, or unsubscribed contact for any row. 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.
Response
Always 200 for a syntactically valid request — read results[] to see what actually happened.
Each entry in results has a status of created, updated, unchanged, or failed, in the same order and count as the contacts you sent. A failed row includes a machine-readable code and a human-readable message; the rest of the batch is unaffected by any one row's failure.
success = created + updated + unchangedDo not treat HTTP 200 alone as "everything succeeded" — check failed and the individual row statuses. The example panel above shows both an all-success and a partial-failure batch.
Errors
Request-level errors stop the whole batch; per-contact errors fail just one row.
Request-level errors
Nothing in the batch is written when one of these occurs.
INVALID_REQUESTA bare object was sent to this endpoint — wrap it in an array, or use the single-contact endpoint for one contact.
BATCH_LIMIT_EXCEEDEDThe request contains more than 50 contacts.
INVALID_API_KEYThe API key is missing, invalid, expired, or revoked.
PAYLOAD_TOO_LARGEThe decoded JSON request body is larger than 1 MB.
RATE_LIMIT_EXCEEDEDThe organization exceeded 300 requests in 60 seconds — shared with the single-contact endpoint.
INTERNAL_ERRORScore 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"
}
}
Per-contact errors
Each of these fails one row inside results[] — the overall response stays 200, and the rest of the batch still processes.
INVALID_EMAILThe email isn't valid after trimming and lowercasing.
DUPLICATE_EMAILThe contact exists and overwrite was not set to true.
SUPPRESSED_EMAILThe contact is suppressed and overwrite was not set to true.
EMPTY_LIST_IDSNo list ID was provided.
TOO_MANY_LIST_IDSMore than 20 list IDs were provided.
INVALID_LISTA list doesn't exist, is archived, or belongs to another organization.
UNKNOWN_FIELDA fields key doesn't match a standard or existing custom field.
FIELD_TYPE_MISMATCHA value doesn't match its field's configured type.
REQUIRED_FIELD_MISSINGA required custom field has no value or was cleared with null.
DUPLICATE_IN_REQUESTThe same normalized email appears more than once in this batch. Duplicate rows are not merged automatically — send each email only once per request.
INVALID_LIST row detail
{
"email": "alex@example.com",
"status": "failed",
"code": "INVALID_LIST",
"message": "One or more lists were not found in this organization",
"invalidListIds": ["000000000000000000000000"]
}