Arlo

HTTP PATCH partial updates

The Arlo API supports partial updates to resources using the HTTP PATCH method. Unlike PUT, which requires you to submit a complete replacement of the entire resource, PATCH allows you to target specific properties and sub-resources for update, addition, or removal — all within a single request.

The PATCH implementation follows the draft RFC 5261 standard. The request body is an XML diff document that describes the changes to apply, using XPath selectors to identify the target nodes within the resource's XML representation.

Topics:

GET before you PATCH

Before constructing a PATCH request, you should always retrieve the current state of the resource with an HTTP GET. The XPath selectors in your diff document must match the actual structure of the resource as it exists on the server — if the structure does not match, the PATCH will fail with a 400 Bad Request error.

This is especially important when working with sub-resources such as addresses, employment details, or custom fields. The correct operation (<replace>, <add>, or <remove>) depends on whether the target element already exists:

  • If a property or sub-resource already exists, use <replace> to update its value, or <remove> to delete it.
  • If a property or sub-resource does not yet exist, use <add> to create it.
  • If you use <replace> on a node that does not exist, or <add> on one that already does, the server will return an error.

Caution: Do not construct a PATCH diff document based on assumptions about the current state of a resource. Another user or process may have modified the resource since you last retrieved it. Always GET the resource immediately before building the diff to ensure your selectors target the correct nodes and your operations are appropriate for the resource's current state.

If your diff targets expanded sub-resources (such as CustomFields or PostalAddress), you must include the corresponding ?expand= parameter in both the initial GET request and the PATCH request. Without expansion, the inline representations needed for XPath targeting will not be present.

The <diff> document format

The request body for a PATCH operation is an XML document with a <diff> root element. Inside this element, you include one or more operations that describe the changes to apply to the resource. Operations are applied in the order they appear in the document.

<diff>
  <replace sel="Contact/Email/text()">newemail@example.org</replace>
  <add sel="Contact">
    <PhoneWork>04 9700 19332</PhoneWork>
  </add>
  <remove sel="Contact/CodeSecondary" />
</diff>

Each operation uses a sel attribute containing an XPath expression that identifies the target node within the resource's XML structure. The selector must match exactly one node; if it matches zero nodes or is malformed, the server returns a 400 Bad Request error.

A single diff document can contain any number of operations of any type. This allows you to perform complex, multi-part updates as a single atomic request.

Operations

Operation Purpose Selector target
<replace> Update the value of an existing property or element The node to replace (use /text() to target the text content of an element)
<add> Append new child elements to an existing parent node The parent node that will receive the new children
<remove> Delete an existing element and its children The node to remove (self-closing element)

Replace

The <replace> operation updates the value of an existing node. The sel attribute identifies the node to replace, and the element content provides the new value.

To replace the text content of a simple property, append /text() to the selector. The new value is provided as the text content of the <replace> element:

<replace sel="Contact/Email/text()">newemail@example.org</replace>

To replace an entire element subtree (for example, swapping a child element of a complex value type), the selector targets the parent and the replacement is provided as a child element:

<replace sel="Organisation/Link[@title='CustomFields']/CustomFields/Field[Name='TaxCode']/Value/String">
  <String>Exempt</String>
</replace>

Add

The <add> operation appends one or more new child elements to an existing parent node. The sel attribute identifies the parent, and the element content provides the new children.

<add sel="Contact">
  <PhoneWork>04 9700 19332</PhoneWork>
</add>

You can add multiple children in a single <add> operation. For example, adding several properties at once:

<add sel="Organisation">
  <LegalName>Clever People Limited</LegalName>
  <Email>info@cleverpeople.com</Email>
  <WebsiteUrl>www.cleverpeople.com</WebsiteUrl>
</add>

When adding complex sub-resources such as a new custom field, the child content may include nested elements and link references:

<add sel="Contact/Link[@title='CustomFields']/CustomFields">
  <Field>
    <Link rel="http://schemas.arlo.co/api/2012/02/auth/related/FieldDescription" type="application/xml" title="FieldDescription" href="https://demo.arlo.co/api/2012-02-01/auth/resources/fielddescriptions/a4b2c1d0-1234-5678-abcd-ef9012345678/"/>
    <Name>PreferredContactMethod</Name>
    <Value>
      <String>Email</String>
    </Value>
  </Field>
</add>

Remove

The <remove> operation deletes an existing element and all of its children. The sel attribute identifies the node to remove. The element is self-closing (no content).

<remove sel="Contact/CodeSecondary" />

You can also use <remove> to delete an inline sub-resource before re-adding it with <add> — this is a common pattern for replacing an entire sub-resource such as a postal address. See Example 3 for a full demonstration.

XPath selectors

The sel attribute on each operation uses standard XPath 1.0 syntax to navigate the resource's XML structure. The following patterns are commonly used:

Pattern Description Example
Entity/Property/text() Target the text content of a simple property Contact/Email/text()
Entity/Property Target the element itself (for removal or subtree replacement) Contact/CodeSecondary
Entity Target the root entity element (for adding new children) Contact
Entity/Link[@title='X'] Target an expanded link by its title attribute Contact/Link[@title='PostalAddress']
Entity/Link[@title='X']/Child Navigate into the expanded content of a link Contact/Link[@title='PostalAddress']/Address
.../Child[Name='Y'] Select a child element by the value of its Name element .../CustomFields/Field[Name='TaxCode']

The selector must resolve to exactly one node. If the selector matches no nodes — for example, because the property does not exist or the XPath is misspelled — the server returns a 400 Bad Request error with a message indicating which path failed to match. See Example 4 for a demonstration.

Examples

The following examples demonstrate common PATCH scenarios. Each example shows the source document (retrieved via HTTP GET), the PATCH diff document, and the resulting updated resource — making the before, patch, and after states clearly visible.

Example 1 — Simple single-property update

Update the email address of an existing contact. This is the simplest form of PATCH — a single <replace> operation targeting the text content of one property.

Before:

GET /api/2012-02-01/auth/resources/contacts/562/

<Contact>
  <ContactID>562</ContactID>
  <FirstName>Barry</FirstName>
  <LastName>Jones</LastName>
  <Email>barry@example.org</Email>
  <CodePrimary>JONESBA01</CodePrimary>
  ...
</Contact>

Patch:

PATCH https://demo.arlo.co/api/2012-02-01/auth/resources/contacts/562/ HTTP/1.1
Accept: application/xml
Content-Type: application/xml

<diff>
  <replace sel="Contact/Email/text()">barry.jones@example.org</replace>
</diff>

After:

<Contact>
  <ContactID>562</ContactID>
  <FirstName>Barry</FirstName>
  <LastName>Jones</LastName>
  <Email>barry.jones@example.org</Email> <!-- Updated -->
  <CodePrimary>JONESBA01</CodePrimary>
  ...
</Contact>

Example 2 — Multiple operations in a single request

Perform three different operations on an organisation in a single PATCH request: replace the CodePrimary value, add new LegalName and Email properties (which do not yet exist), and remove the existing WebsiteUrl. This demonstrates how a single diff document can combine all three operation types.

Before:

GET /api/2012-02-01/auth/resources/organisations/1423/

<Organisation>
  <OrganisationID>1423</OrganisationID>
  <Name>Clever People</Name>
  <CodePrimary>ORG-1423</CodePrimary>
  <WebsiteUrl>www.cleverpeople.com</WebsiteUrl>
  ...
</Organisation>

Patch:

PATCH https://demo.arlo.co/api/2012-02-01/auth/resources/organisations/1423/ HTTP/1.1
Accept: application/xml
Content-Type: application/xml

<diff>
  <replace sel="Organisation/CodePrimary/text()">ORG-3310</replace>
  <add sel="Organisation">
    <LegalName>Clever People Limited</LegalName>
    <Email>info@cleverpeople.com</Email>
  </add>
  <remove sel="Organisation/WebsiteUrl" />
</diff>

After: Note that CodePrimary is updated, LegalName and Email have been added, and WebsiteUrl is gone.

<Organisation>
  <OrganisationID>1423</OrganisationID>
  <Name>Clever People</Name>
  <CodePrimary>ORG-3310</CodePrimary> <!-- Updated -->
  <LegalName>Clever People Limited</LegalName> <!-- Added -->
  <Email>info@cleverpeople.com</Email> <!-- Added -->
  <!-- WebsiteUrl removed -->
  ...
</Organisation>

Example 3 — Updating expanded sub-resources

This example demonstrates the full workflow for updating sub-resources that are represented as expanded links — in this case, updating a custom field value, adding a new custom field, and replacing a postal address on a contact.

Before: The diff selectors need to navigate into expanded link content, so the resource must be retrieved with ?expand=:

GET /api/2012-02-01/auth/resources/contacts/562/?expand=CustomFields,PostalAddress

<Contact>
  <ContactID>562</ContactID>
  <FirstName>Barry</FirstName>
  <LastName>Jones</LastName>
  ...
  <Link rel="..." title="CustomFields" href=".../contacts/562/customfields/">
    <CustomFields>
      <Field>
        <Name>MembershipType</Name>
        <Value><String>Annual</String></Value>
        <Link rel="..." title="FieldDescription" href=".../fielddescriptions/f3a12b45-6c78-9de0-f1a2-b3c4d5e6f7a8/"/>
      </Field>
    </CustomFields>
  </Link>
  <Link rel="..." title="PostalAddress" href=".../contacts/562/postaladdress/">
    <Address>
      <StreetLine1>98 Wallacetown Quay</StreetLine1>
      <City>Metropolis</City>
      <PostCode>9332</PostCode>
      <Country>New Zealand</Country>
    </Address>
  </Link>
  ...
</Contact>

From this response, we can see that the MembershipType field exists (so we <replace> its value), no PreferredContactMethod field exists yet (so we <add> it), and a PostalAddress is present (so we <remove> the existing Address then <add> a new one).

Patch: The PATCH request must include the same ?expand= parameter so the server's representation includes the expanded link content that the selectors reference.

PATCH https://demo.arlo.co/api/2012-02-01/auth/resources/contacts/562/?expand=CustomFields,PostalAddress HTTP/1.1
Accept: application/xml
Content-Type: application/xml

<diff>
  <!-- 1. Update the existing custom field value -->
  <replace sel="Contact/Link[@title='CustomFields']/CustomFields/Field[Name='MembershipType']/Value/String">
    <String>Premium</String>
  </replace>

  <!-- 2. Add a new custom field (requires FieldDescription link with GUID) -->
  <add sel="Contact/Link[@title='CustomFields']/CustomFields">
    <Field>
      <Link rel="http://schemas.arlo.co/api/2012/02/auth/related/FieldDescription" type="application/xml" title="FieldDescription" href="https://demo.arlo.co/api/2012-02-01/auth/resources/fielddescriptions/a4b2c1d0-1234-5678-abcd-ef9012345678/"/>
      <Name>PreferredContactMethod</Name>
      <Value><String>Email</String></Value>
    </Field>
  </add>

  <!-- 3. Replace the PostalAddress: remove existing, then add new -->
  <remove sel="Contact/Link[@title='PostalAddress']/Address" />
  <add sel="Contact/Link[@title='PostalAddress']">
    <Address>
      <StreetLine1>21 Merchant Drive</StreetLine1>
      <SuburbOrRegion>Grafton</SuburbOrRegion>
      <City>Auckland</City>
      <PostCode>1010</PostCode>
      <Country>New Zealand</Country>
    </Address>
  </add>
</diff>

After: MembershipType is updated to Premium, the new PreferredContactMethod field has been added, and the postal address has been replaced.

<Contact>
  <ContactID>562</ContactID>
  <FirstName>Barry</FirstName>
  <LastName>Jones</LastName>
  ...
  <Link rel="..." title="CustomFields" href=".../contacts/562/customfields/">
    <CustomFields>
      <Field>
        <Name>MembershipType</Name>
        <Value><String>Premium</String></Value> <!-- Updated -->
        <Link rel="..." title="FieldDescription" href=".../fielddescriptions/f3a12b45-6c78-9de0-f1a2-b3c4d5e6f7a8/"/>
      </Field>
      <Field> <!-- Added -->
        <Name>PreferredContactMethod</Name>
        <Value><String>Email</String></Value>
        <Link rel="..." title="FieldDescription" href=".../fielddescriptions/a4b2c1d0-1234-5678-abcd-ef9012345678/"/>
      </Field>
    </CustomFields>
  </Link>
  <Link rel="..." title="PostalAddress" href=".../contacts/562/postaladdress/">
    <Address> <!-- Replaced -->
      <StreetLine1>21 Merchant Drive</StreetLine1>
      <SuburbOrRegion>Grafton</SuburbOrRegion>
      <City>Auckland</City>
      <PostCode>1010</PostCode>
      <Country>New Zealand</Country>
    </Address>
  </Link>
  ...
</Contact>

Important: The remove-then-add pattern for replacing a sub-resource (step 3 above) is necessary because <replace> on the Address element would replace the element's content while preserving the element itself, which may not produce the desired result when the new address has a different set of child elements. Removing and re-adding ensures a clean replacement.

Example 4 — Error response from a malformed selector

If the XPath selector in a sel attribute does not match any node in the resource, the server returns a 400 Bad Request response. This commonly occurs when the entity name is misspelled, the targeted property does not exist, or the ?expand= parameter was omitted.

Before:

GET /api/2012-02-01/auth/resources/registrations/9823/

<Registration>
  <RegistrationID>9823</RegistrationID>
  <Grade>Fair</Grade>
  ...
</Registration>

Patch: Note the misspelled entity name Regisration (missing a t) in the selector:

PATCH https://demo.arlo.co/api/2012-02-01/auth/resources/registrations/9823/ HTTP/1.1
Accept: application/xml
Content-Type: application/xml

<diff>
  <replace sel="Regisration/Grade/text()[1]">Excellent</replace>
</diff>

Error response: The server returns 400 Bad Request with a message identifying the failing path:

<ApiException>
  <Code>BadRequest</Code>
  <Message>Path Regisration/Grade/text()[1] did not match a node (line = 3, position = 3)</Message>
</ApiException>

Response codes

See HTTP response status codes for a general overview of all possible API status codes. Common response codes for PATCH operations are listed below.

Status Description
200 OK Resource was successfully updated.
400 Bad Request The diff document is malformed, contains an invalid XPath selector, or a selector did not match any node in the resource. Check the error message for the specific path that failed.
409 Conflict Resource could not be updated because it contains values that conflict with those on the server.

PATCH requests are also subject to RBAC permissions. The operations in the diff document are evaluated against the permissions of the authenticated user. If the user does not have permission to modify a targeted property, the server may reject the request.

Resources that support PATCH

The following resources support HTTP PATCH for partial updates. Refer to each resource's documentation for resource-specific properties, selectors, and examples: