Upsert a record
Use this REST endpoint to insert a new record or update an existing one in a single call. Upsert is useful for integrations that may or may not have a matching record on the Magentrix side — for example, syncing contacts from an external system where you key on email address rather than the Magentrix record ID.
Upsert uses the HTTP PUT method. Matching is done by a single unique field — either the primary key (Id, the default) or any other field on the entity flagged as unique.
curl --request PUT 'https://{domain}/api/3.0/entity/{entity_name}?uniqueField={field_name}'
-H 'Content-Type: application/json'
-H 'Accept: application/json'
-H 'Authorization: Bearer {access_token}'
-d '{record(s) in JSON format}'How the match resolves:
- If the unique field on the payload matches an existing record, that record is updated.
- If it does not match (or is empty), a new record is created.
- If it matches more than one record, the request fails — the unique field must identify at most one record.
Request
entity_name string Required
Use the entity’s API name in the REST resource path to specify the type of record you want to upsert.
Request Query String
uniqueField string Optional
The API name of the field used to match the payload against existing records. The field must be marked as unique on the entity. If omitted, Id is used. Common choices: Id, Email, ExternalId.
Request Body
JSON data string Required
A single record object or an array of records, in JSON or XML. Every record must include a value for the uniqueField (or omit it to force an insert). For optimal performance, keep bulk payloads under 1,000 records.
Attention: The body payload cannot exceed 20 MB in size.
Example — Upsert by Email
curl --request PUT 'https://{domain}/api/3.0/entity/contact?uniqueField=Email'
-H 'Content-Type: application/json'
-H 'Accept: application/json'
-H 'Authorization: Bearer {access_token}'
-d '{
"FirstName": "Sam",
"LastName": "Davison",
"Email": "s.davison@company.com"
}'If a Contact already has the email s.davison@company.com, that record is updated with the supplied name. If no Contact has that email, a new Contact is created.
Successful Response
HTTP 200 OK
{
"id": "00700000000001F0001",
"success": true,
"errors": []
}If the payload contains an array of records, the response is an array in the same order. Each item indicates the resulting record ID and whether the operation succeeded.
Response Headers
ETag — a successful single-record Upsert response includes an ETag header derived from the record's updated ModifiedOn timestamp:
ETag: W/"2026-04-17T20:42:11.107Z"
An ETag is a short server-issued version stamp for the record. Capture it and pass it back as If-Match on a subsequent PATCH, PUT, or DELETE to perform an atomic compare-and-swap. The value is a weak validator (the W/ prefix is part of the value).
Bulk Upsert responses do not include a single ETag header (multiple records cannot share one). Entities that do not declare a ModifiedOn field (for example RecycleBin, EventLog, Person) do not emit an ETag.
Conditional Upsert (single record)
A single-record PUT supports the same precondition headers as PATCH:
- If-Match — the Upsert proceeds only if the existing record's current ETag matches the supplied value, or if no record matches and a new one is being created.
If-Match: * accepts any existing record. - If-Unmodified-Since — the Upsert proceeds only if the existing record's
ModifiedOn is at or before the supplied date.
When a precondition fails, the server returns HTTP 412 Precondition Failed and the record is not updated. For full header semantics and accepted date formats, see Update a Record — Optimistic Concurrency.
Bulk Upsert and Concurrency
Per-record preconditions do not apply to bulk Upsert. Every record in a bulk payload is processed as last-write-wins regardless of request headers. If you need optimistic concurrency on a specific record, send it in its own single-record PUT.
Failed Response
HTTP 400 Bad Request — invalid unique field
{
"errors": [
{
"code": "INVALID_FIELD",
"message": "'Email2' is not a unique field, you can only perform Upsert on unique fields."
}
],
"success": false
}HTTP 400 Bad Request — multiple records match the unique field
{
"errors": [
{
"message": "Upsert failed: multiple records match the unique field value."
}
],
"success": false
}If the payload is an array, the response can include a mix of successfully saved records (with their IDs) and items that failed (with error messages), in the same order as the input.
Status Codes
| HTTP Code | Error Code | Triggered When |
|---|
| 200 OK | — | The Upsert succeeded. |
| 202 Accepted | — | Bulk Upsert: some records succeeded and some failed. The response body indicates which. |
| 400 Bad Request | INVALID_FIELD | The supplied uniqueField is not marked as unique on the entity. |
| 400 Bad Request | INVALID_HEADER | If-Unmodified-Since could not be parsed. |
| 404 Not Found | INVALID_ENTITY | The entity name in the URL does not exist. |
| 400 Bad Request | — | The unique field value matched more than one record. |
| 406 Not Acceptable | — | Validation failed. |
| 412 Precondition Failed | PRECONDITION_FAILED | A single-record PUT supplied If-Match or If-Unmodified-Since and the precondition did not match. The record is not changed. |
| 413 Payload Too Large | PAYLOAD_TOO_LARGE | The request body exceeded the 20 MB limit. |
What Is Next?