curl -s \
"https://engine.example.com/v1/holders/alpha/attribute-versions?limit=100" \
-H "Authorization: Bearer $TOKEN"
# Send each page's next back as after, until null.// A client from OpenAPI Generator: see Build a client.
import {
Configuration,
HoldersApi,
ProblemFromJSON,
ResponseError,
} from "./nodeasset-client";
const api = new HoldersApi(new Configuration({
basePath: "https://engine.example.com",
accessToken: process.env.TOKEN,
}));
try {
// Send each page's next back as after, until null.
let after: string | undefined;
do {
const page = await api.listHolderAttributeVersions({ holderId: "alpha", limit: 100, after });
for (const holderAttributeVersion of page.value ?? []) {
console.log(holderAttributeVersion);
}
after = page.next ?? undefined;
} while (after);
} catch (e) {
if (!(e instanceof ResponseError)) throw e;
// A refusal is a problem; its type ends in the slug.
const problem = ProblemFromJSON(await e.response.json());
const slug = problem.type.split(":").pop();
console.error(e.response.status, slug, problem.detail);
}
# A client from OpenAPI Generator: see Build a client.
import os
import sys
import nodeasset_client
config = nodeasset_client.Configuration(
host="https://engine.example.com",
access_token=os.environ["TOKEN"],
)
with nodeasset_client.ApiClient(config) as client:
api = nodeasset_client.HoldersApi(client)
try:
# Send each page's next back as after, until null.
after = None
while True:
page = api.list_holder_attribute_versions(holder_id="alpha", limit=100, after=after)
for holder_attribute_version in page.value or []:
print(holder_attribute_version)
after = page.next
if after is None:
break
except nodeasset_client.ApiException as e:
# A refusal is a problem; its type ends in the slug.
problem = nodeasset_client.Problem.from_json(e.body)
slug = problem.type.rsplit(":", 1)[-1]
print(e.status, slug, problem.detail, file=sys.stderr)
// A client from OpenAPI Generator: see Build a client.
import nodeasset.client.ApiClient;
import nodeasset.client.ApiException;
import nodeasset.client.api.HoldersApi;
import nodeasset.client.model.Problem;
public class ListHolderAttributeVersions {
public static void main(String[] args) throws Exception {
ApiClient client = new ApiClient();
client.updateBaseUri("https://engine.example.com");
client.setRequestInterceptor(builder ->
builder.header("Authorization", "Bearer " + System.getenv("TOKEN")));
HoldersApi api = new HoldersApi(client);
try {
// Send each page's next back as after, until null.
String after = null;
do {
var request = HoldersApi.APIListHolderAttributeVersionsRequest.newBuilder()
.holderId("alpha")
.limit(100)
.after(after)
.build();
var page = api.listHolderAttributeVersions(request);
for (var holderAttributeVersion : page.getValue()) {
System.out.println(holderAttributeVersion);
}
after = page.getNext();
} while (after != null);
} catch (ApiException e) {
// A refusal is a problem; its type ends in the slug.
Problem problem = client.getObjectMapper()
.readValue(e.getResponseBody(), Problem.class);
String type = problem.getType();
String slug = type.substring(type.lastIndexOf(':') + 1);
System.err.println(e.getCode() + " " + slug + " " + problem.getDetail());
}
}
}
{
"offset": 0,
"now": "2026-10-03T13:26:06.152290781Z",
"value": [
{
"version": 2,
"holderId": "alpha",
"attributes": {
"residency": {
"value": "SG",
"state": "verified",
"expiresAt": "2027-10-01T00:00:00Z",
"proofHash": "sha256:71bb0d85eaa3ef967532c1362a20fed032d5889aa1cdd659e18a61485aefde94",
"evidence": "kyc/alpha/residency"
},
"investorType": {
"value": "professional",
"state": "verified",
"expiresAt": null,
"proofHash": "sha256:99104191dccbd729f5ee8dd91329ceb2be83da5eec4358e7e33c410e2882ad96",
"evidence": "kyc/alpha/investor-type"
},
"accreditation": null
},
"recordedAt": "2026-10-03T13:22:41.508812Z",
"maker": "operator-1",
"makerName": "Olive Park",
"makerEmail": "olive.park@venue.example",
"makerRole": "operator",
"signers": [
{
"sub": "approver-1",
"name": "Ann Kim",
"email": "ann.kim@venue.example",
"signedAt": "2026-10-03T13:22:41.497205Z"
}
],
"operationId": "op-2b8e1c5d-4f3a-4d6e-9a7b-1c2d3e4f5a6b",
"actionKey": "holder.set-attributes-3f9c2a7e1b5d4c8a6e0f2b1d"
},
{
"version": 1,
"holderId": "alpha",
"attributes": {
"residency": {
"value": "SG",
"state": "pending",
"expiresAt": null,
"proofHash": null,
"evidence": "kyc/alpha/residency"
},
"investorType": null,
"accreditation": null
},
"recordedAt": "2026-10-03T13:21:07.115930Z",
"maker": "operator-1",
"makerName": "Olive Park",
"makerEmail": "olive.park@venue.example",
"makerRole": "operator",
"signers": [
{
"sub": "approver-1",
"name": "Ann Kim",
"email": "ann.kim@venue.example",
"signedAt": "2026-10-03T13:21:07.102448Z"
}
],
"operationId": "op-7d1f0e2c-8b3a-4e5f-a6c7-d8e9f0a1b2c3",
"actionKey": "holder.onboard-0c4e8a2f6b1d3e5a7c9f0b2d"
}
],
"next": null
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}List a holder's attribute versions
Lists each version of the holder’s eligibility attributes, newest first, with when it was recorded, its maker and its approvers. The versions are kept for as long as the holder is.
curl -s \
"https://engine.example.com/v1/holders/alpha/attribute-versions?limit=100" \
-H "Authorization: Bearer $TOKEN"
# Send each page's next back as after, until null.// A client from OpenAPI Generator: see Build a client.
import {
Configuration,
HoldersApi,
ProblemFromJSON,
ResponseError,
} from "./nodeasset-client";
const api = new HoldersApi(new Configuration({
basePath: "https://engine.example.com",
accessToken: process.env.TOKEN,
}));
try {
// Send each page's next back as after, until null.
let after: string | undefined;
do {
const page = await api.listHolderAttributeVersions({ holderId: "alpha", limit: 100, after });
for (const holderAttributeVersion of page.value ?? []) {
console.log(holderAttributeVersion);
}
after = page.next ?? undefined;
} while (after);
} catch (e) {
if (!(e instanceof ResponseError)) throw e;
// A refusal is a problem; its type ends in the slug.
const problem = ProblemFromJSON(await e.response.json());
const slug = problem.type.split(":").pop();
console.error(e.response.status, slug, problem.detail);
}
# A client from OpenAPI Generator: see Build a client.
import os
import sys
import nodeasset_client
config = nodeasset_client.Configuration(
host="https://engine.example.com",
access_token=os.environ["TOKEN"],
)
with nodeasset_client.ApiClient(config) as client:
api = nodeasset_client.HoldersApi(client)
try:
# Send each page's next back as after, until null.
after = None
while True:
page = api.list_holder_attribute_versions(holder_id="alpha", limit=100, after=after)
for holder_attribute_version in page.value or []:
print(holder_attribute_version)
after = page.next
if after is None:
break
except nodeasset_client.ApiException as e:
# A refusal is a problem; its type ends in the slug.
problem = nodeasset_client.Problem.from_json(e.body)
slug = problem.type.rsplit(":", 1)[-1]
print(e.status, slug, problem.detail, file=sys.stderr)
// A client from OpenAPI Generator: see Build a client.
import nodeasset.client.ApiClient;
import nodeasset.client.ApiException;
import nodeasset.client.api.HoldersApi;
import nodeasset.client.model.Problem;
public class ListHolderAttributeVersions {
public static void main(String[] args) throws Exception {
ApiClient client = new ApiClient();
client.updateBaseUri("https://engine.example.com");
client.setRequestInterceptor(builder ->
builder.header("Authorization", "Bearer " + System.getenv("TOKEN")));
HoldersApi api = new HoldersApi(client);
try {
// Send each page's next back as after, until null.
String after = null;
do {
var request = HoldersApi.APIListHolderAttributeVersionsRequest.newBuilder()
.holderId("alpha")
.limit(100)
.after(after)
.build();
var page = api.listHolderAttributeVersions(request);
for (var holderAttributeVersion : page.getValue()) {
System.out.println(holderAttributeVersion);
}
after = page.getNext();
} while (after != null);
} catch (ApiException e) {
// A refusal is a problem; its type ends in the slug.
Problem problem = client.getObjectMapper()
.readValue(e.getResponseBody(), Problem.class);
String type = problem.getType();
String slug = type.substring(type.lastIndexOf(':') + 1);
System.err.println(e.getCode() + " " + slug + " " + problem.getDetail());
}
}
}
{
"offset": 0,
"now": "2026-10-03T13:26:06.152290781Z",
"value": [
{
"version": 2,
"holderId": "alpha",
"attributes": {
"residency": {
"value": "SG",
"state": "verified",
"expiresAt": "2027-10-01T00:00:00Z",
"proofHash": "sha256:71bb0d85eaa3ef967532c1362a20fed032d5889aa1cdd659e18a61485aefde94",
"evidence": "kyc/alpha/residency"
},
"investorType": {
"value": "professional",
"state": "verified",
"expiresAt": null,
"proofHash": "sha256:99104191dccbd729f5ee8dd91329ceb2be83da5eec4358e7e33c410e2882ad96",
"evidence": "kyc/alpha/investor-type"
},
"accreditation": null
},
"recordedAt": "2026-10-03T13:22:41.508812Z",
"maker": "operator-1",
"makerName": "Olive Park",
"makerEmail": "olive.park@venue.example",
"makerRole": "operator",
"signers": [
{
"sub": "approver-1",
"name": "Ann Kim",
"email": "ann.kim@venue.example",
"signedAt": "2026-10-03T13:22:41.497205Z"
}
],
"operationId": "op-2b8e1c5d-4f3a-4d6e-9a7b-1c2d3e4f5a6b",
"actionKey": "holder.set-attributes-3f9c2a7e1b5d4c8a6e0f2b1d"
},
{
"version": 1,
"holderId": "alpha",
"attributes": {
"residency": {
"value": "SG",
"state": "pending",
"expiresAt": null,
"proofHash": null,
"evidence": "kyc/alpha/residency"
},
"investorType": null,
"accreditation": null
},
"recordedAt": "2026-10-03T13:21:07.115930Z",
"maker": "operator-1",
"makerName": "Olive Park",
"makerEmail": "olive.park@venue.example",
"makerRole": "operator",
"signers": [
{
"sub": "approver-1",
"name": "Ann Kim",
"email": "ann.kim@venue.example",
"signedAt": "2026-10-03T13:21:07.102448Z"
}
],
"operationId": "op-7d1f0e2c-8b3a-4e5f-a6c7-d8e9f0a1b2c3",
"actionKey": "holder.onboard-0c4e8a2f6b1d3e5a7c9f0b2d"
}
],
"next": null
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"requestId": "<string>",
"gate": "<string>",
"check": "<string>",
"recovery": "<string>",
"retryAfter": 123,
"retryable": true,
"packageName": "<string>",
"party": "<string>",
"contractId": "<string>",
"projectionOffset": 123,
"ledgerEnd": 123,
"code": 123,
"reason": "<string>",
"policyVersion": 123,
"errors": [
{
"pointer": "<string>",
"detail": "<string>"
}
]
}app, approver, auditor, operator, risk.Authorizations
A JWT from the deployment's identity provider, whose roles claim names the caller's roles and whose holder claim names an investor's holder.
Headers
A signed request's key id, as venue.api.signing.clients configures it for the bearer's subject.
Seconds since the epoch, within venue.api.signing.window of the engine's clock, 5 minutes by default.
^[0-9]+$At least 16 random bytes in base64url, never reused within twice the window.
22 - 128^[A-Za-z0-9_-]+={0,2}$The base64 HMAC-SHA256, under the key's secret, of the method, the path and query, the timestamp, the nonce and the body's SHA-256.
Your id for this request, 1 to 128 printable characters, repeated in the answer; absent, the engine makes one.
128^[\x21-\x7E]+$A W3C trace context, which the engine joins and passes on.
^[0-9a-f]{2}-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$Path Parameters
The holder's id.
Query Parameters
Only versions recorded at this instant or later, by recordedAt.
Only versions recorded before this instant, by recordedAt.
The most records a page holds, 1 to 1000; absent, every record.
1 <= x <= 1000The previous page's next; absent, the first page.
Response
The versions.
The ledger offset the answer was read at; 0 for an answer from the engine's own records.
The engine's clock when it answered, an ISO-8601 instant.
What the read answers; for a list, the page's records in the list's order.
Show child attributes
Show child attributes
The cursor for the next page, sent back as after; null on a list's last page, never on a feed.

