> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pretectum.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Update Data Object

> Update an existing data object (record) in a dataset

The Update Data Object endpoint allows you to modify an existing record in a dataset. You can update specific fields while leaving others unchanged. The API uses optimistic locking via the `_version` field to prevent concurrent modification conflicts.

## Prerequisites

* A Pretectum API key (see [API Keys](/api-reference/authentication/api-keys))
* Permission to update data objects in your tenant
* Valid business area ID (see [List Business Areas](/api-reference/business-areas/list))
* Valid schema ID (see [List Schemas](/api-reference/schemas/list))
* Valid dataset ID (see [List Datasets](/api-reference/datasets/list))
* Valid data object ID (from [List Data Objects](/api-reference/dataobjects/list) or previous create)

## Authentication

Include your API key in the `Authorization` header.

```bash theme={null}
Authorization: pre_your_api_key
```

## Request

### Path Parameters

<ParamField path="businessAreaId" type="string" required>
  The unique identifier of the business area. You can obtain this from the [List Business Areas](/api-reference/business-areas/list) endpoint.
</ParamField>

<ParamField path="schemaId" type="string" required>
  The unique identifier of the schema. You can obtain this from the [List Schemas](/api-reference/schemas/list) endpoint.
</ParamField>

<ParamField path="datasetId" type="string" required>
  The unique identifier of the dataset. You can obtain this from the [List Datasets](/api-reference/datasets/list) endpoint.
</ParamField>

<ParamField path="dataObjectId" type="string" required>
  The unique identifier of the data object to update. You can obtain this from the [List Data Objects](/api-reference/dataobjects/list) endpoint or from a previous create operation.
</ParamField>

### Headers

<ParamField header="Authorization" type="string" required initialValue="pre_your_api_key">
  Your Pretectum API key. Create one in the Pretectum app under **Configuration → API Keys**.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`.
</ParamField>

<ParamField header="Accept" type="string" default="application/json">
  The response content type. Currently only `application/json` is supported.
</ParamField>

### Request Body

<ParamField body="_version" type="integer" required>
  The current version of the data object. This must match the version currently stored in the system to prevent overwriting concurrent changes. You can get this value from [List Data Objects](/api-reference/dataobjects/list), [Get Data Object by Primary Key](/api-reference/dataobjects/get-by-primary-key), or the create response (a newly created object starts at `0`).
</ParamField>

<ParamField body="[Field Name]" type="varies">
  The fields to update. Only include fields you want to change. Field names must match the schema field names exactly. Omitted fields remain unchanged.
</ParamField>

### Example Requests

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT "https://api.pretectum.io/v1/businessareas/20240115103000123a1b2c3d4e5f6789012345678901234/schemas/20240115103000456d1e2f3a4b5c6789012345678901234/datasets/20240925152201042a1b2c3d4e5f6789012345678901234/dataobjects/20240601120000123f1a2b3c4d5e6789012345678901234" \
    -H "Authorization: pre_your_api_key" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{
      "_version": 1,
      "Email": "john.smith.updated@example.com",
      "Phone": "+1 555-999-8888",
      "Status": "Premium"
    }'
  ```

  ```javascript JavaScript theme={null}
  const apiKey = 'pre_your_api_key';
  const businessAreaId = '20240115103000123a1b2c3d4e5f6789012345678901234';
  const schemaId = '20240115103000456d1e2f3a4b5c6789012345678901234';
  const datasetId = '20240925152201042a1b2c3d4e5f6789012345678901234';
  const dataObjectId = '20240601120000123f1a2b3c4d5e6789012345678901234';

  async function updateDataObject(businessAreaId, schemaId, datasetId, dataObjectId, data) {
    const response = await fetch(
      `https://api.pretectum.io/v1/businessareas/${businessAreaId}/schemas/${schemaId}/datasets/${datasetId}/dataobjects/${dataObjectId}`,
      {
        method: 'PUT',
        headers: {
          'Authorization': apiKey,
          'Content-Type': 'application/json',
          'Accept': 'application/json'
        },
        body: JSON.stringify(data)
      }
    );

    if (!response.ok) {
      throw new Error(`Failed to update data object: ${response.statusText}`);
    }

    // Returns 204 No Content on success
    return response.status === 204;
  }

  const updates = {
    '_version': 1,
    'Email': 'john.smith.updated@example.com',
    'Phone': '+1 555-999-8888',
    'Status': 'Premium'
  };

  const success = await updateDataObject(businessAreaId, schemaId, datasetId, dataObjectId, updates);
  if (success) {
    console.log('Data object updated successfully');
  }
  ```

  ```python Python theme={null}
  import requests

  api_key = 'pre_your_api_key'
  business_area_id = '20240115103000123a1b2c3d4e5f6789012345678901234'
  schema_id = '20240115103000456d1e2f3a4b5c6789012345678901234'
  dataset_id = '20240925152201042a1b2c3d4e5f6789012345678901234'
  data_object_id = '20240601120000123f1a2b3c4d5e6789012345678901234'

  def update_data_object(business_area_id, schema_id, dataset_id, data_object_id, data):
      response = requests.put(
          f'https://api.pretectum.io/v1/businessareas/{business_area_id}/schemas/{schema_id}/datasets/{dataset_id}/dataobjects/{data_object_id}',
          json=data,
          headers={
              'Authorization': api_key,
              'Content-Type': 'application/json',
              'Accept': 'application/json'
          }
      )
      response.raise_for_status()
      # Returns 204 No Content on success
      return response.status_code == 204

  updates = {
      '_version': 1,
      'Email': 'john.smith.updated@example.com',
      'Phone': '+1 555-999-8888',
      'Status': 'Premium'
  }

  success = update_data_object(business_area_id, schema_id, dataset_id, data_object_id, updates)
  if success:
      print('Data object updated successfully')
  ```
</CodeGroup>

## Response

A successful update returns a `204 No Content` response with no body.

### Success Response

```
HTTP/1.1 204 No Content
```

<Note>
  The `204 No Content` response indicates the update was successful. The data object's version is automatically incremented.
</Note>

## Error Responses

| Status Code | Description |
| - | - |
| `400 Bad Request` | Invalid request body or malformed JSON (`INVALID_REQUEST_BODY`); a stale `_version` (`DATA_OBJECT_VERSION_CONFLICT`); a primary key value already used by another record in the dataset (`DUPLICATE_PRIMARY_KEY`); or an attempt to clear the primary key field (`PRIMARY_KEY_REQUIRED`). In every case nothing is written. |
| `401 Unauthorized` | The API key is missing, malformed, unknown, inactive, expired or deleted. Check the key in **Configuration → API Keys**. |
| `403 Forbidden` | Your application client does not have permission to update data objects. Contact your tenant administrator. |
| `404 Not Found` | The specified business area, schema, dataset, or data object does not exist, or you do not have access to it. A missing or deleted data object is reported with the code `DATA_OBJECT_NOT_FOUND`. |
| `500 Internal Server Error` | An unexpected error occurred on the server. Try again later or contact support. |

## Optimistic Locking

The API uses optimistic locking to prevent concurrent modification conflicts:

1. When you read a data object, note its `_version` value.
2. Include this `_version` in your update request.
3. If another process updated the object between your read and update, the versions won't match and your update is rejected.
4. On version conflict, re-read the data object to get the latest version and retry your update.

### Version Conflict Response

A stale `_version` is rejected with `400 Bad Request` and the code `DATA_OBJECT_VERSION_CONFLICT`. The record is left exactly as it was:

```json theme={null}
{
  "code": "DATA_OBJECT_VERSION_CONFLICT",
  "message": "The data object has been modified since it was read. Fetch it again and retry with the current version",
  "fields": [
    {
      "name": "_version",
      "errors": "The data object has been modified since it was read. Fetch it again and retry with the current version"
    }
  ]
}
```

<Note>
  The check applies to every update, including one that changes the primary key value. A successful update increments `_version` by exactly one, so after a `204` you can send `_version + 1` on the next update without re-reading, as long as nothing else writes to the record in between.
</Note>

<CodeGroup>
  ```javascript JavaScript theme={null}
  async function updateWithRetry(businessAreaId, schemaId, datasetId, dataObjectId, updates, maxRetries = 3) {
    for (let attempt = 0; attempt < maxRetries; attempt++) {
      try {
        // Get current version
        const dataObjects = await getDataObjects(businessAreaId, schemaId, datasetId);
        const current = dataObjects.items.find(obj => obj._dataObjectId === dataObjectId);

        if (!current) {
          throw new Error('Data object not found');
        }

        // Attempt update with current version
        const success = await updateDataObject(
          businessAreaId,
          schemaId,
          datasetId,
          dataObjectId,
          { ...updates, _version: current._version }
        );

        if (success) {
          return true;
        }
      } catch (error) {
        if (attempt === maxRetries - 1) {
          throw error;
        }
        // Wait before retry
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
    }
    return false;
  }
  ```

  ```python Python theme={null}
  import time

  def update_with_retry(business_area_id, schema_id, dataset_id, data_object_id, updates, max_retries=3):
      for attempt in range(max_retries):
          try:
              # Get current version
              data_objects = get_data_objects(business_area_id, schema_id, dataset_id)
              current = next(
                  (obj for obj in data_objects['items'] if obj['_dataObjectId'] == data_object_id),
                  None
              )

              if not current:
                  raise ValueError('Data object not found')

              # Attempt update with current version
              success = update_data_object(
                  business_area_id,
                  schema_id,
                  dataset_id,
                  data_object_id,
                  {**updates, '_version': current['_version']}
              )

              if success:
                  return True
          except Exception as error:
              if attempt == max_retries - 1:
                  raise error
              # Wait before retry
              time.sleep(1)

      return False
  ```
</CodeGroup>

## Partial Updates

You only need to include the fields you want to change. Omitted fields retain their current values:

```json theme={null}
{
  "_version": 1,
  "Status": "Inactive"
}
```

This updates only the `Status` field while keeping all other fields unchanged.

## Best Practices

1. **Always include `_version`**: The version field is required for updates to prevent data conflicts.
2. **Handle version conflicts**: Implement retry logic for scenarios where concurrent updates may occur.
3. **Update only changed fields**: Send only the fields that need to be updated to minimize payload size.
4. **Validate before updating**: Ensure updated values meet schema requirements before sending.
5. **Log update operations**: Keep track of updates for audit purposes.

## Related Endpoints

<CardGroup cols={2}>
  <Card title="List Data Objects" icon="list" href="/api-reference/dataobjects/list">
    Retrieve records and their versions
  </Card>

  <Card title="Create Data Object" icon="plus" href="/api-reference/dataobjects/create">
    Add new records to a dataset
  </Card>

  <Card title="Delete Data Object" icon="trash" href="/api-reference/dataobjects/delete">
    Remove records from a dataset
  </Card>

  <Card title="Get Data Object by Primary Key" icon="fingerprint" href="/api-reference/dataobjects/get-by-primary-key">
    Fetch one record by its primary key value
  </Card>

  <Card title="Get Schema Details" icon="file-code" href="/api-reference/schemas/get">
    View schema field definitions
  </Card>
</CardGroup>
