curl -s -X POST \
"https://engine.example.com/v1/standing-approvals" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: create-standing-approval-FUND" \
-H "Content-Type: application/json" \
-d '{
"instrumentId": "FUND",
"action": "distribution.execute",
"validUntil": "2026-10-04T13:18:17.799526192Z",
"maxTotalPayout": 10000000,
"maxYearlyGrowth": 100000
}'// A client from OpenAPI Generator: see Build a client.
import {
Configuration,
DistributionsApi,
ProblemFromJSON,
ResponseError,
StandingApprovalBodyFromJSON,
} from "./nodeasset-client";
const api = new DistributionsApi(new Configuration({
basePath: "https://engine.example.com",
accessToken: process.env.TOKEN,
}));
try {
const answer = await api.createStandingApproval({
// Your id for this action: a retry is the same write.
idempotencyKey: "create-standing-approval-FUND",
standingApprovalBody: StandingApprovalBodyFromJSON({
instrumentId: "FUND",
action: "distribution.execute",
validUntil: "2026-10-04T13:18:17.799526192Z",
maxTotalPayout: 10000000,
maxYearlyGrowth: 100000,
}),
});
if (answer.state === "awaiting") {
// Awaiting approval: it runs once approved.
console.log("Awaiting approval:", answer.actionKey);
} else {
// Follow the operation until it succeeds or fails.
console.log("Operation:", answer.operationId, answer.state);
}
} 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.DistributionsApi(client)
try:
answer = api.create_standing_approval(
# Your id for this action: a retry is the same write.
idempotency_key="create-standing-approval-FUND",
standing_approval_body=nodeasset_client.StandingApprovalBody.model_validate({
"instrumentId": "FUND",
"action": "distribution.execute",
"validUntil": "2026-10-04T13:18:17.799526192Z",
"maxTotalPayout": 10000000,
"maxYearlyGrowth": 100000,
}),
)
if answer.state == "awaiting":
# Awaiting approval: it runs once approved.
print("Awaiting approval:", answer.action_key)
else:
# Follow the operation until it succeeds or fails.
print("Operation:", answer.operation_id, answer.state)
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.DistributionsApi;
import nodeasset.client.model.Problem;
import nodeasset.client.model.StandingApprovalBody;
import nodeasset.client.model.WriteAnswer;
public class CreateStandingApproval {
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")));
DistributionsApi api = new DistributionsApi(client);
try {
var request = DistributionsApi.APICreateStandingApprovalRequest.newBuilder()
// Your id for this action: a retry is the same write.
.idempotencyKey("create-standing-approval-FUND")
.standingApprovalBody(client.getObjectMapper().readValue("""
{
"instrumentId": "FUND",
"action": "distribution.execute",
"validUntil": "2026-10-04T13:18:17.799526192Z",
"maxTotalPayout": 10000000,
"maxYearlyGrowth": 100000
}
""", StandingApprovalBody.class))
.build();
WriteAnswer answer = api.createStandingApproval(request);
if (answer.getState() == WriteAnswer.StateEnum.AWAITING) {
// Awaiting approval: it runs once approved.
System.out.println("Awaiting approval: " + answer.getActionKey());
} else {
// Follow the operation until it succeeds or fails.
System.out.println("Operation: " + answer.getOperationId() + " " + answer.getState());
}
} 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());
}
}
}
{
"state": "queued",
"operationId": "<string>",
"kind": "instrument.record",
"resource": {
"kind": "instrument",
"id": "<string>",
"href": "<string>"
},
"request": "<unknown>",
"result": "<unknown>",
"problem": "<unknown>",
"actor": "<string>",
"actorName": "<string>",
"actorEmail": "<string>",
"role": "operator",
"createdAt": "<string>",
"startedAt": "<string>",
"finishedAt": "<string>",
"updateId": "<string>",
"offset": 123,
"actionKey": "<string>",
"maker": "<string>",
"makerRole": "operator",
"madeAt": "<string>",
"required": 123,
"signedBy": [
"<string>"
],
"recovery": "<string>"
}Create a standing approval
Grants a standing approval: the scheduler executes one instrument’s due distributions within its bounds. An operator makes it and two approvers sign it.
curl -s -X POST \
"https://engine.example.com/v1/standing-approvals" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: create-standing-approval-FUND" \
-H "Content-Type: application/json" \
-d '{
"instrumentId": "FUND",
"action": "distribution.execute",
"validUntil": "2026-10-04T13:18:17.799526192Z",
"maxTotalPayout": 10000000,
"maxYearlyGrowth": 100000
}'// A client from OpenAPI Generator: see Build a client.
import {
Configuration,
DistributionsApi,
ProblemFromJSON,
ResponseError,
StandingApprovalBodyFromJSON,
} from "./nodeasset-client";
const api = new DistributionsApi(new Configuration({
basePath: "https://engine.example.com",
accessToken: process.env.TOKEN,
}));
try {
const answer = await api.createStandingApproval({
// Your id for this action: a retry is the same write.
idempotencyKey: "create-standing-approval-FUND",
standingApprovalBody: StandingApprovalBodyFromJSON({
instrumentId: "FUND",
action: "distribution.execute",
validUntil: "2026-10-04T13:18:17.799526192Z",
maxTotalPayout: 10000000,
maxYearlyGrowth: 100000,
}),
});
if (answer.state === "awaiting") {
// Awaiting approval: it runs once approved.
console.log("Awaiting approval:", answer.actionKey);
} else {
// Follow the operation until it succeeds or fails.
console.log("Operation:", answer.operationId, answer.state);
}
} 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.DistributionsApi(client)
try:
answer = api.create_standing_approval(
# Your id for this action: a retry is the same write.
idempotency_key="create-standing-approval-FUND",
standing_approval_body=nodeasset_client.StandingApprovalBody.model_validate({
"instrumentId": "FUND",
"action": "distribution.execute",
"validUntil": "2026-10-04T13:18:17.799526192Z",
"maxTotalPayout": 10000000,
"maxYearlyGrowth": 100000,
}),
)
if answer.state == "awaiting":
# Awaiting approval: it runs once approved.
print("Awaiting approval:", answer.action_key)
else:
# Follow the operation until it succeeds or fails.
print("Operation:", answer.operation_id, answer.state)
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.DistributionsApi;
import nodeasset.client.model.Problem;
import nodeasset.client.model.StandingApprovalBody;
import nodeasset.client.model.WriteAnswer;
public class CreateStandingApproval {
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")));
DistributionsApi api = new DistributionsApi(client);
try {
var request = DistributionsApi.APICreateStandingApprovalRequest.newBuilder()
// Your id for this action: a retry is the same write.
.idempotencyKey("create-standing-approval-FUND")
.standingApprovalBody(client.getObjectMapper().readValue("""
{
"instrumentId": "FUND",
"action": "distribution.execute",
"validUntil": "2026-10-04T13:18:17.799526192Z",
"maxTotalPayout": 10000000,
"maxYearlyGrowth": 100000
}
""", StandingApprovalBody.class))
.build();
WriteAnswer answer = api.createStandingApproval(request);
if (answer.getState() == WriteAnswer.StateEnum.AWAITING) {
// Awaiting approval: it runs once approved.
System.out.println("Awaiting approval: " + answer.getActionKey());
} else {
// Follow the operation until it succeeds or fails.
System.out.println("Operation: " + answer.getOperationId() + " " + answer.getState());
}
} 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());
}
}
}
{
"state": "queued",
"operationId": "<string>",
"kind": "instrument.record",
"resource": {
"kind": "instrument",
"id": "<string>",
"href": "<string>"
},
"request": "<unknown>",
"result": "<unknown>",
"problem": "<unknown>",
"actor": "<string>",
"actorName": "<string>",
"actorEmail": "<string>",
"role": "operator",
"createdAt": "<string>",
"startedAt": "<string>",
"finishedAt": "<string>",
"updateId": "<string>",
"offset": 123,
"actionKey": "<string>",
"maker": "<string>",
"makerRole": "operator",
"madeAt": "<string>",
"required": 123,
"signedBy": [
"<string>"
],
"recovery": "<string>"
}operator. Four eyes: it runs once two approvers, neither of them the maker, approve it.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
Names this write, so a retry answers the same operation; absent, the write is keyed on its body.
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}$Body
The standing approval to grant.
The instrument's id on the Registry.
The one action a grant may name.
distribution.execute When the grant lapses, an ISO-8601 instant after now and at most a year after the last approver signs.
The most one period may pay, in the instrument's units.
The most the priced NAV may grow a year from the NAV the period accrues from; 0.1 is 10%.
Whether a period whose withholding rate changed may execute under the grant, where the deployment allows alert too; absent, refuse.
refuse, alert Response
The same write again, with the same key and body; the operation it already is.
What every write answers: an operation, or an action awaiting approval, told apart by state.
Where the write stands: an operation's state, or awaiting for an action awaiting its approvers.
queued, running, succeeded, failed The operation's id.
What the operation does.
instrument.record, policy.set, admission-consent.propose, instrument.pause, holder.register, holder.onboard, holder.close, holder.register-successor, holder.set-attributes, admission.offer, admission.withdraw, accepted-terms.accept, subscription.claim, subscription.withdraw, subscription.deliver, subscription.settle, subscription.release, primary-market.propose, redemption.claim, redemption.withdraw, redemption.release, redemption.settle, dealing-cycle.open, dealing-cycle.settle, dealing-cycle.release, standing-settlement.open, standing-settlement.settle, standing-settlement.pause, standing-settlement.resume, standing-settlement.close, reserve.propose, reserve.close, lock-agreement.propose, lock-agreement.release, mint.start, mint.cancel, reserve-redemption.start, reserve-redemption.cancel, reserve-report.create, amendment.propose, amendment.withdraw, provision-settlement.propose, distribution.execute, distribution.roll, standing-approval.grant, standing-approval.revoke, holder.restrict, holder.restrict-batch, restriction.lift, issuer-powers-agreement.propose, issuer-powers-consent.offer, holder.force-transfer, holder.recover, instrument.force-transfer, instrument.recover, hold.release, external-account.map, webhook.register, webhook.remove, webhook.test The record it acts on, and, once it succeeds, the record it created or changed.
Show child attributes
Show child attributes
The body the operation was opened with, beside the ids its path named.
What the operation came to, once succeeded; null otherwise.
The problem the operation failed with; null otherwise.
Who asked, by sub.
The name claim of the bearer that asked; null where it carried none, and for an operation the engine opened itself.
The email claim of the bearer that asked; null where it carried none, and for an operation the engine opened itself.
The role the operation ran under; null for an operation the engine opened itself, whose actor names it.
operator, approver, risk, compliance, auditor, investor, app, monitor, feed, registrar When the operation was opened.
When the operation started running; null while queued.
When the operation finished; null until it does.
The ledger update the operation committed; null until it commits.
The offset the operation's transaction committed at; null until it commits.
The four-eyes action's key.
Who made the action, by sub.
The role the maker acted in.
operator, approver, risk, compliance, auditor, investor, app, monitor, feed, registrar When the maker made the action.
How many distinct approvers the action needs.
The approvers who have signed it so far.
What completes the action awaiting approval.

