Update a record
Use this REST endpoint to update an entity record or a collection of records. Provide the updated record information in your request data and use the PATCH method of the resource with a specific record ID to update that record. Records in a single file must be of the same object type.
JSON data format:
curl PATCH 'https://{domain}/api/3.0/entity/{entity_name}/{record_id}'
-H 'Content-Type: application/json'
-H 'Accept: application/json'
-H 'Authorization: Bearer {access_token}'
-d '{record(s) in JSON format}'
XML data format:
curl PATCH 'https://{domain}/api/3.0/entity/{entity_name}/{record_id}'
-H 'Content-Type: application/xml'
-H 'Accept: application/xml'
-H 'Authorization: Bearer {access_token}'
-d '{record(s) in XML format}'
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 update.
record_id string Optional
Use this parameter to outline which record should be edited. If you also include the ID field in the payload, the ID values should match. Do not include "record_id" if you wish to edit more than one record.
Request Body
JSONdata string Required
Provide the entity data in JSON or XML format. The payload may represent a single record or an array of records. The entries must have an ID value. For optimal performance, we recommend limiting the number of records to fewer than 400.
Attention: The body payload cannot exceed 20 MB in size.
Example
curl PATCH 'https://{domain}/api/3.0/entity/contact/00100000000001F0001'
-H 'Content-Type: application/json'
-H 'Accept: application/json'
-H 'Authorization: Bearer {access_token}'
-d '{
"Id": "00200000000001F0001",
"BillingStreet": "52 Minthorn blvd",
"BillingCountry": "CA"
}'
Successful Response
HTTP 200 OK
{
"id": "00100000000001F0001",
"success": true,
"errors": [],
}If your request payload contains an array of entities, the response will also be an array. Each item (ID) in the response corresponds to its matching record in the original payload, in the same order.
Failed Response
HTTP 406 Not Acceptable
{
"errors": [
{
"code": "Missing_Field",
"fieldName": "LastName",
"message": "You must enter a value."
}
],
"id": null,
"success": false
}The error message may include a property name, indicating which entity field the error is associated with.
Note: If the payload is an array of entity data, the response can include a collection of successfully saved items (with their IDs) and any items that failed to save (with corresponding error messages).
Response Headers
ETag — a successful single-record PATCH response now 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 (see Optimistic Concurrency below). The value is a weak validator (the W/ prefix is part of the value) and round-trips byte-for-byte — what you get back from PATCH is exactly what the next GET will return.
Some internal entities (for example RecycleBin, EventLog, Person) do not declare a ModifiedOn field. Responses for those entities do not include an ETag header. Treat the absence of an ETag as "ETag-based concurrency is not available on this entity" and either omit If-Match or use If-Match: *.
Optimistic Concurrency (RFC 7232)
By default, REST 3 PATCH follows last-write-wins semantics — concurrent updates to the same record all succeed and the most recent write wins. No client code change is required to benefit from this; concurrent updates that previously failed under load now succeed.
If you need strict optimistic concurrency — that is, you want the update to fail when another writer has changed the record since you read it — opt in by sending one of the conditional request headers below.
| Request Header | Value | Behaviour |
|---|
| If-Match | A weak entity tag from a previous ETag response header (e.g. W/"2026-04-17T20:42:11.107Z"), a comma-separated list of such tags, or *. | The update proceeds only if the record's current ETag exactly matches one of the supplied tags. * accepts any existing record. Use If-Match when you have a recent ETag handy (from a prior GET, PUT, or PATCH response). |
| If-Unmodified-Since | An HTTP-date (RFC 1123 / RFC 850 / asctime) or an ISO 8601 timestamp. | The update proceeds only if the record's ModifiedOn is at or before the supplied date. Use this when you have a wall-clock cutoff rather than a specific ETag. |
When both headers are supplied, If-Match takes precedence (per RFC 7232 §6). When a precondition fails, the server returns HTTP 412 Precondition Failed with error code PRECONDITION_FAILED and the record is not updated. A malformed If-Unmodified-Since returns HTTP 400 Bad Request with error code INVALID_HEADER.
Accepted formats for If-Unmodified-Since
| Format | Example |
|---|
| RFC 1123 (preferred) | Fri, 17 Apr 2026 20:42:11 GMT |
| RFC 850 | Friday, 17-Apr-26 20:42:11 GMT |
| asctime | Fri Apr 17 20:42:11 2026 |
| ISO 8601 (UTC) | 2026-04-17T20:42:11Z or 2026-04-17T20:42:11.107Z |
Examples — Conditional Update
(1) Update with ETag from a previous response — atomic compare-and-swap
PATCH /api/3.0/entity/account/0010000000000010001 HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
If-Match: W/"2026-04-17T20:42:11.107Z"
{ "Name": "Acme Corp" }Returns 200 on success (with a new ETag for the updated record), or 412 if the record was modified since you captured that ETag.
(2) Update with a date cutoff
PATCH /api/3.0/entity/account/0010000000000010001 HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
If-Unmodified-Since: Fri, 17 Apr 2026 20:42:11 GMT
{ "Name": "Acme Corp" }Returns 412 if ModifiedOn is after the supplied date.
(3) Update only if the record still exists (no specific version)
PATCH /api/3.0/entity/account/0010000000000010001 HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
If-Match: *
{ "Name": "Acme Corp" }Returns 412 if the record no longer exists; succeeds otherwise.
Bulk PATCH and Concurrency
Per-record preconditions do not apply to bulk PATCH. Every record in a bulk request is processed as last-write-wins regardless of any request headers sent. If you need optimistic concurrency on a specific record, send a single-record PATCH.
Status Codes
| HTTP Code | Error Code | Triggered When |
|---|
| 200 OK | — | The update succeeded. |
| 202 Accepted | — | Bulk update: some records succeeded and some failed. The response body indicates which. |
| 400 Bad Request | INVALID_HEADER | If-Unmodified-Since could not be parsed as a valid HTTP-date or ISO 8601 timestamp. |
| 404 Not Found | INVALID_ENTITY | The entity name in the URL does not exist. |
| 406 Not Acceptable | — | Model validation failed (missing required field, invalid format, etc.). See Failed Response above. |
| 413 Payload Too Large | PAYLOAD_TOO_LARGE | The request body exceeded the 20 MB limit. |
| 412 Precondition Failed | PRECONDITION_FAILED | If-Match was supplied and did not match the current ETag — or If-Unmodified-Since was supplied and the record was modified after that date. The record is not updated. |
Migration Notes
Prior to this release, REST 3 PATCH enforced an implicitModifiedOn concurrency check on every request, sometimes rejecting concurrent writes with HTTP 406 within a 30 ms window. This implicit check has been removed. REST 3 now matches REST 2's last-write-wins default.
- No precondition header sent (the common case): existing client code is unchanged, and will see fewer errors under load. No migration action needed.
- You relied on the implicit check to detect concurrent updates: you must now opt in by sending
If-Match (with a previously-captured ETag) or If-Unmodified-Since. Failed preconditions are reported as HTTP 412, not 406.
What Is Next?