Table of Contents


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 CodeError CodeTriggered When
200 OKThe Upsert succeeded.
202 AcceptedBulk Upsert: some records succeeded and some failed. The response body indicates which.
400 Bad RequestINVALID_FIELDThe supplied uniqueField is not marked as unique on the entity.
400 Bad RequestINVALID_HEADERIf-Unmodified-Since could not be parsed.
404 Not FoundINVALID_ENTITYThe entity name in the URL does not exist.
400 Bad RequestThe unique field value matched more than one record.
406 Not AcceptableValidation failed.
412 Precondition FailedPRECONDITION_FAILEDA single-record PUT supplied If-Match or If-Unmodified-Since and the precondition did not match. The record is not changed.
413 Payload Too LargePAYLOAD_TOO_LARGEThe request body exceeded the 20 MB limit.

What Is Next?

Last updated on 7/28/2026

Attachments