Skip to content

Data Authority API Guide

How to call Data Authority REST endpoints for bitemporal entities. This guide covers the consumer side: what requests to send, what responses to expect, and how to query historical state.

Companion documents:

Every request to a Data Authority endpoint requires the following headers.

HeaderRequiredDescription
AuthorizationYesBearer token (JWT) issued by the identity provider
Content-TypeYes (POST/PUT)application/json — required on requests with a body
AcceptYesapplication/json
X-Tenant-IDYesUUID of the tenant whose data is being accessed

The X-Tenant-ID header is the primary scoping mechanism. Every query, mutation, and navigation call is filtered to the tenant specified in this header. Requests that omit it are rejected with 400 Bad Request.

Send a POST to create a new entity. The server assigns a new eId (entity ID) and records the first version.

Request

POST /v1/{app}/{resource}
Authorization: Bearer <token>
X-Tenant-ID: <tenantUUID>
Content-Type: application/json
Accept: application/json
{
"name": "example value"
}

Response201 Created

{
"eId": "a1b2c3d4-...",
"rId": "e5f6g7h8-...",
"asOf": {
"effectiveFrom": 1700000000000,
"recordedFrom": 1700000000000
},
"payload": { "eId": "a1b2c3d4-...", "name": "example value" },
"metadata": { "tenantId": "<tenantUUID>" }
}

PlantUML diagram

Send a GET to retrieve the current state of an entity. Append bitemporal query parameters to retrieve historical state — see Bitemporal Query Patterns.

Request

GET /v1/{app}/{resource}/{eId}
Authorization: Bearer <token>
X-Tenant-ID: <tenantUUID>
Accept: application/json

Optional query parameters:

ParameterTypeDescription
effectiveAsOfepoch millisecondsRetrieve the version effective at this point in business time
recordedAsOfepoch millisecondsRetrieve the version as it was recorded at this point in system time

Response200 OK or 404 Not Found

{
"eId": "a1b2c3d4-...",
"rId": "e5f6g7h8-...",
"asOf": {
"effectiveFrom": 1700000000000,
"recordedFrom": 1700000000000
},
"payload": { "eId": "a1b2c3d4-...", "name": "example value" },
"metadata": { "tenantId": "<tenantUUID>" }
}

PlantUML diagram

Send a PUT to update an existing entity. The server closes the previous version and creates a new one with an incremented version number and a new rId.

Request

PUT /v1/{app}/{resource}/{eId}
Authorization: Bearer <token>
X-Tenant-ID: <tenantUUID>
Content-Type: application/json
Accept: application/json
{
"name": "updated value"
}

Response200 OK

The response is an EntityRecord identical in structure to the Create response. The rId will differ from the previous version; the eId remains the same.

PlantUML diagram

Send a DELETE to retire an entity. Data Authority performs a logical soft delete: no rows are removed from the database. The entity is marked retired: true and will not appear in subsequent reads or queries.

Request

DELETE /v1/{app}/{resource}/{eId}
Authorization: Bearer <token>
X-Tenant-ID: <tenantUUID>
Accept: application/json

Response200 OK

{
"eId": "a1b2c3d4-...",
"rId": "z9y8x7w6-...",
"retired": true
}

PlantUML diagram

Data Authority uses a two-step query protocol. The first call initiates a query and returns the first page of results together with an opaque page token. Subsequent calls use the page token to navigate forward through the result set.

Request

POST /v1/{app}/{resource}/query
Authorization: Bearer <token>
X-Tenant-ID: <tenantUUID>
Content-Type: application/json
Accept: application/json
{
"filter": { ... },
"sort": [{ "field": "name", "direction": "ASC" }],
"pagination": { "pageSize": 25 }
}

Response200 OK

{
"items": [ { "eId": "...", "payload": { ... }, "metadata": { ... } } ],
"nextPageToken": "eyJwYWdlIjoxfQ==",
"totalCount": 143
}

When nextPageToken is absent from the response, the current page is the last page.

PlantUML diagram

Request

GET /v1/{app}/{resource}/query/{pageToken}
Authorization: Bearer <token>
X-Tenant-ID: <tenantUUID>
Accept: application/json

The pageToken value is opaque — treat it as a string and do not attempt to parse or construct it. Pass the exact value received in the previous response.

Response200 OK

Same structure as the initiate response. When nextPageToken is absent, this is the last page.

PlantUML diagram

The filter field in the query body accepts a recursive expression tree. Each node is either a leaf condition or a logical combinator.

OperatorDescription
EQEqual to
NEQNot equal to
GTGreater than
GTEGreater than or equal to
LTLess than
LTELess than or equal to
OperatorDescription
INValue is one of a supplied list
OperatorDescription
IsNullField is null
OperatorDescription
LikeSQL-style pattern match (% wildcard)
ContainsSubstring match
StartsWithPrefix match
EndsWithSuffix match
OperatorDescription
ANDAll child conditions must be true
ORAt least one child condition must be true
NOTNegates a single child condition

For full JSON examples and the complete filter schema, see the Query DSL reference.

All error responses use a consistent body structure:

{
"error": "<code>",
"message": "<human-readable detail>",
"requestId": "<correlation id>"
}

Use requestId when reporting issues — it correlates the client error to server-side logs.

CodeMeaningWhen
400Bad RequestValidation failure, malformed JSON, missing required header
401UnauthorizedMissing or invalid bearer token
403ForbiddenToken is valid but the caller lacks sufficient scope for this operation
404Not FoundEntity does not exist, belongs to a different tenant, or has been retired
409ConflictConcurrent modification detected, or a uniqueness constraint was violated
500Internal Server ErrorUnexpected server-side failure — contact the service owner with the requestId

Every entity version carries two independent time axes:

  • Effective time — when the fact was true in the business domain (e.g., when a price change took effect).
  • Recorded time — when the fact was written into the system (system clock at write time).

The GET endpoint accepts effectiveAsOf and recordedAsOf query parameters as epoch milliseconds. Omitting a parameter defaults it to “now” on the server, which returns the currently effective, currently recorded version.

Common patterns

GoalParameters
Current stateOmit both parameters
State as it was at a past business dateeffectiveAsOf=<past epoch ms>
What the system believed at a past system timerecordedAsOf=<past epoch ms>
Full bitemoral point-in-time queryeffectiveAsOf=<epoch ms>&recordedAsOf=<epoch ms>

Bitemporal queries are read-only. Mutations (POST, PUT, DELETE) always write at the current server time for the recorded axis; the effective time may be set by including an effectiveAsOf parameter on mutation requests if the endpoint supports backdating.

For the conceptual model, time coordinate types, and the closed-open interval convention used by the persistence layer, see Bitemporal Persistence.