A property in LUSID can be either perpetual or time-variant. The lifetime is determined by the property type.
Note the following:
- The concept of lifetime refers to validity rather than mutability; any property value can be corrected at any time. Rather, a perpetual property represents information expected to be valid forever, for example a person's place of birth. A time-variant property represents information expected to change over time, for example a person's address. More on LUSID and bitemporality.
- While entities of most types support perpetual properties, not all support time-variant properties.
- Either can be single or multi-value.
Perpetual properties
A perpetual property has a value that is considered to be permanent in LUSID, for example a person's place of birth.
When you add a perpetual property value, it is applied with the current AsAt
date and is effective from the beginning of time until the end of time. For example, to set John Smith’s place of birth, you might make the following request to the SetPersonProperties API:
URL: POST /api/persons/corporate/username/john_smith/properties
Request body:
{ "properties": { "person/info/placeOfBirth": [ { "key": "Person/info/placeOfBirth", "value": { "labelValue": "London" } } ] } }
The response might be as follows:
{ "displayName": "JohnSmith", "identifiers": { "person/corporate/username": { "key": "Person/corporate/username", "value": { "labelValue": "john_smith" } } }, "properties": { "person/info/placeOfBirth": [ { "key": "Person/info/placeOfBirth", "value": { "labelValue": "London" }, "effectiveFrom": "0001-01-01T00:00:00.0000000+00:00", "effectiveUntil": "9999-12-31T23:59:59.9999999+00:00" } ] }, "version": { "effectiveFrom": "2021-08-03T00:00:00.0000000+00:00", "asAtDate": "1" // Integer value used for illustrative purposes; the actual system time uses the 0000-00-00T00:00:00.0000000+00:00 format. } }
We can represent this visually as follows:
While the property is considered perpetual, it is of course possible to enter the wrong information. LUSID allows you to correct bad data by overwriting any perpetual property value. A full audit history is maintained, with past values available by requesting the property with an AsAt
datetime prior to the correction. The new value is stored with the AsAt
datetime of the correction, which we could represent visually as follows:
Time-variant properties
A time-variant property has a value that is considered likely to change in LUSID over time, for example a person's address. A time-variant property is therefore associated with an effective date range.
The effective date range is described by effectiveFrom
and effectiveUntil
datetimes. If no effectiveUntil
date is provided, the value will be applied until the effectiveFrom
date of the next value in the timeline (which is the end of time if there are no subsequent values).
Consider the following sequence of events. In the first request, we'll set John Smith's address to be 1 Main Street, with an effectiveFrom
date of 1 January 2019 until the end of time.
First request: AsAt=1
URL: POST /api/persons/corporate/username/john_smith/properties
Request body:
{ "properties": { "person/info/address": [ { "key": "Person/info/address", "value": { "labelValue": "1 Main Street" }, "effectiveFrom": "2019-01-01T00:00:00.00Z" } ] } }
In the second request, we'll update John Smith's address to be 2 High Street, with an effectiveFrom
date of 1 January 2020 until the end of time. The previous value of 1 Main Street is automatically updated so that it is now effectiveUntil
the 1 January 2020.
Second request: AsAt=2
URL: POST /api/persons/corporate/username/john_smith/properties
Request body:
{ "properties": { "person/info/address": [ { "key": "Person/info/address", "value": { "labelValue": "2 High Street" }, "effectiveFrom": "2020-01-01T00:00:00.00Z" } ] } }
We subsequently learn that instead of moving to 2 High Street on 1 January 2020, John Smith actually moved to 3 Station Road, staying there for one year. In the third request, we'll change the property value to 3 Station Road with an effectiveFrom
date of 1 January 2020, and specify an explicit effectiveUntil
date of 1 January 2021. This is now the 'second value'. The previous second value of 2 High Street becomes the 'third value'; its effectiveFrom
date is automatically updated to 1 January 2021.
Second request: AsAt=3
URL: POST /api/persons/corporate/username/john_smith/properties
Request body:
{ "properties": { "person/info/address": [ { "key": "Person/info/address", "value": { "labelValue": "3 Station Road" }, "effectiveFrom": "2020-01-01T00:00:00.00Z" "effectiveUntil": "2021-01-01T00:00:00.00Z" } ] } }
We can represent this visually as follows:
Retrieving property values as a time-series
You can specify EffectiveAt
and AsAt
datetimes when retrieving properties for an entity, but it can be difficult and time-consuming to try to understand the full extent of historic changes.
Certain types of entity therefore have property time series API endpoints that return the full list of values for a particular property. For example, for a Person entity you could use the GetPersonPropertyTimeSeries API, specifying the person's identifier in the URL and the property key as a query string parameter.
If we retrieve John Smith's time-variant address property, for example, we can see that values are returned firstly in EffectiveAt
datetime order, and subsequently in AsAt
datetime order if they cover the same period. Values that are no longer valid at the AsAt
datetime of the request have the status superseded
, and current values have the status prevailing
:
{ "values": [ { "value": { "labelValue": "1 Main Street" }, "effectiveRange": { "fromDate": "2019-01-01T00:00:00.0000000+00:00", "untilDate": "9999-12-31T23:59:59.9999999+00:00" }, "asAtRange": { "fromDate": "1", "untilDate": "2" }, "status": "superseded" }, { "value": { "labelValue": "1 Main Street" }, "effectiveRange": { "fromDate": "2019-01-01T00:00:00.0000000+00:00", "untilDate": "2020-01-01T00:00:00.0000000+00:00" }, "asAtRange": { "fromDate": "2" }, "status": "prevailing" }, { "value": { "labelValue": "2 High Street" }, "effectiveRange": { "fromDate": "2020-01-01T00:00:00.0000000+00:00", "untilDate": "9999-12-31T23:59:59.9999999+00:00" }, "asAtRange": { "fromDate": "2", "untilDate": "3" }, "status": "superseded" }, { "value": { "labelValue": "3 Station Rd" }, "effectiveRange": { "fromDate": "2020-01-01T00:00:00.0000000+00:00", "untilDate": "2021-01-01T00:00:00.0000000+00:00" }, "asAtRange": { "fromDate": "3" }, "status": "prevailing" }, { "value": { "labelValue": "2 High Street" }, "effectiveRange": { "fromDate": "2021-01-01T00:00:00.0000000+00:00", "untilDate": "9999-12-31T23:59:59.9999999+00:00" }, "asAtRange": { "fromDate": "3" }, "status": "prevailing" } ] }
To only retrieve prevailing values, set the API endpoint's filter
parameter, for example status eq 'prevailing'
.