# Properties and values

Location: [gRPC API](https://developer.m-files.com/APIs/gRPC-API/index.md) > [Concepts](https://developer.m-files.com/APIs/gRPC-API/index.md#concepts)

HTML version: https://developer.m-files.com/APIs/gRPC-API/concepts/properties-and-values/

The metadata of an object version is a list of property values. Each one pairs a property
definition ID with a typed value:

```text
PropertyValue
  property_def: 1002                       property definition ID ("Document date")
  value: TypedValue
    type: DATATYPE_DATE                    must match PropertyDef.data_type
    is_null_value: false                   true = empty value; data is then unset
    data: TypedValueUnion { date: ... }    exactly one member, the one that matches type
```

- [PropertyValue](https://developer.m-files.com/APIs/gRPC-API/Reference/Messages/MFiles.PropertyValue/index.md) carries `property_def`, an ID from the property
  definition space (see [the ID spaces](https://developer.m-files.com/APIs/gRPC-API/concepts/vault-and-metadata-structure/index.md#the-id-spaces)).
- [TypedValue](https://developer.m-files.com/APIs/gRPC-API/Reference/Messages/MFiles.TypedValue/index.md) carries the data type in `type` and the value in one
  member of [TypedValueUnion](https://developer.m-files.com/APIs/gRPC-API/Reference/Messages/MFiles.TypedValueUnion/index.md). Set both, and pick the member that
  matches `type`; a `DATATYPE_TEXT` value sent in `multi_line_text` fails with "The parameter is
  incorrect."
- The type must also match the property definition's `data_type` (read with
  [GetPropertyDefs](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCPropertyDefs/GetPropertyDefs/index.md)). A text value for the date
  property 1002 fails with 'Wrong data type for property definition "Document date".'

## Data types

| Data type | Union member | Example property (Sample Vault) | Notes |
| --- | --- | --- | --- |
| `DATATYPE_TEXT` | `text` | 0 Name or title, 1004 Keywords | at most 100 characters; longer text is cut to 100 without an error |
| `DATATYPE_MULTI_LINE_TEXT` | `multi_line_text` | 33 Comment, 1034 Description | long text; `\n` line breaks are kept |
| `DATATYPE_INTEGER` | `integer` | 1103 Proposal number | 32-bit |
| `DATATYPE_REAL_NUMBER` | `real_number` | (none in the Sample Vault) | double |
| `DATATYPE_DATE` | `date` | 1002 Document date | a `Timestamp` at midnight UTC; a time of day is dropped |
| `DATATYPE_TIMESTAMP` | `timestamp` | 20 Created, 21 Last modified | UTC `Timestamp` |
| `DATATYPE_BOOLEAN` | `boolean` | 22 Single file, 1098 Accepted | |
| `DATATYPE_LOOKUP` | `lookup` | 100 Class, 39 Workflow State, 1143 Agreement type | one item or object |
| `DATATYPE_MULTI_SELECT_LOOKUP` | `multi_select_lookup` | 1079 Customer, 101 Class groups | any number of items or objects |

[Datatype](https://developer.m-files.com/APIs/gRPC-API/Reference/Enums/MFiles.Datatype/index.md) lists more types, such as `DATATYPE_TIME`; the Sample Vault
has no properties of them. By their descriptions, `DATATYPE_INTEGER64` and `DATATYPE_FILETIME`
are not used in document properties.

The 100-character limit is easy to miss: the server stores the first 100 characters of a longer
single-line text and reports success. Use a multi-line text property for longer values.

## Empty values

An empty value keeps its type: `type` set, `is_null_value` true, `data` unset. The server returns
empty properties the same way, for example `1034 Description` on an object without a
description:

```text
property_def: 1034  value { type: DATATYPE_MULTI_LINE_TEXT  is_null_value: true }
```

Send the same shape to empty a property. Removing a property from the object entirely is a
different operation (`remove` in
[SetPropertiesRequest](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/SetProperties/index.md#request)). It works only for properties that the
class does not list: removing one that it lists fails with 'The property "Keywords" cannot be
removed from the object.' A property that the class lists is present on the object even when
nobody set it, as an empty value.

## Lookups

A lookup value points to a value list item or an object. To set one, only the IDs are needed:

```text
property_def: 1143                          Agreement type (lookup to value list 160)
value {
  type: DATATYPE_LOOKUP
  data { lookup { value_list_item_info { obj_id { type: 160  item_id { internal_id: 2 } } } } }
}
```

- `value_list_item_info.obj_id.type` must be the property definition's `value_list` (for a
  lookup to objects, the object type ID: 136 for property 1079 Customer). Any other value fails
  with "The parameter is incorrect." followed by the IDs, for example "(136-2, 160)".
- `item_id.internal_id` is the item or object ID in that list. An ID that does not exist fails
  with 'The value "9999, referencing object type: 0" does not exist, or it is a conflict object.'
- A multi-select lookup holds a [Lookup](https://developer.m-files.com/APIs/gRPC-API/Reference/Messages/MFiles.Lookup/index.md) per selected item in
  `multi_select_lookup.values`.
- When you read values, the server fills in the display data: `name` (the item's title, which
  is what a user sees), `guid`, `external_id`, and `version` with `OBJ_VER_VERSION_TYPE_LATEST`
  (-1). You do not need to send these.

## Rules the server applies

- **Required properties.** A class lists its properties in
  `ObjectClass.associated_property_defs`, each with `is_required`. Creating or saving an object
  without a required value fails with 'The mandatory property value "Document date" is missing.'
- **Class first.** Property 100 (Class) decides which properties are expected, the title source
  and the workflow rules. Every object version has it.
- **The title.** Property 0 (Name or title) always holds the object's title. When a class uses
  another property as its name (`ObjectClass.name_property_def`, such as 1144 Agreement title for
  "Contract or Agreement"), property 0 holds the same value.
- **Server-maintained values.** Properties whose `PropertyDef.update_type` is
  `UPDATE_TYPE_SET_BY_SERVER` (Created, Last modified, Created by, sizes, ...) are set by the
  server. Properties with an `automatic_value_type` other than `AUTOMATIC_VALUE_TYPE_NONE` (in
  the Sample Vault: 1102 Proposal title, calculated from a template; 1103 Proposal number, an
  incrementing number) get their values automatically.
- **Workflow and state** are ordinary lookup properties (38 and 39) with extra rules; see
  [Workflows](https://developer.m-files.com/APIs/gRPC-API/concepts/workflows/index.md).

## Writing values

| Task | Call |
| --- | --- |
| Create an object with values | [AddObject](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/AddObject/index.md) (`properties`) |
| Change values | [SetProperties](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/SetProperties/index.md) (`properties`, `remove`) |
| Change values when checking in | [CheckIn](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/CheckIn/index.md) (`properties`) |
| Read values | [GetProperties](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/GetProperties/index.md), [GetObjectVersionAndPropertiesOfMultipleObjects](https://developer.m-files.com/APIs/gRPC-API/Reference/MFiles.IRPCObjectOperations/GetObjectVersionAndPropertiesOfMultipleObjects/index.md) |

`SetProperties` changes only the properties you send, unless `remove_unspecified_properties` is
true: then every property not in the request is removed. Leave it false unless you send the
complete set.

Methods whose names end in `WithMetadata` use
[PropertyValueWithMetadata](https://developer.m-files.com/APIs/gRPC-API/Reference/Messages/MFiles.PropertyValueWithMetadata/index.md) instead, which adds
`value_metadata` (who or what set the value, such as a user or AI, and why). The plain
`PropertyValue` methods above do not need it.
