Canton agentic.
tenzro_submitDamlCommand, tenzro_listDamlContracts, tenzro_canton_*), composed with the agent delegation fields on tenzro_createApiKey.- STATUS
- Testnet
- STABILITY
- Stable
- AUTHORIZATION
- Key + Mandate + Delegation
- REFERENCE
- canton-agentic
Three RPCs
tenzro_canton_submitWithMandate— submit a DAML command bound to an AP2 mandate pair. Validates the cart against AP2 invariants + TDIP DelegationScope + runtime SpendingPolicy + optional on-chain escrow + optional Stripe SPT ceiling.tenzro_canton_watchParty— active-contracts snapshot for a single party. Gated against the API key'scan_read_as_partiesallow-list.tenzro_canton_aggregateAnalytics— operator admin-read of rolled-up per-key Canton call counters, grouped bysubjectorkey_id.
Access and network selection
Canton is an operator-brokered resource — the ledger sits outside Tenzro and the node reaches it with credentials the operator supplies. Every RPC on this page needs an API key carrying the canton scope, sent as X-Tenzro-Api-Key. Keys do not gate the marketplace: publishing an agent, skill, workflow, or MCP server is permissionless, priced by the provider in TNZO or offered free, and needs no operator approval.
A node serves each Canton network independently, and a key is authorized for a subset of them. Name the target with the canton_network JSON-RPC param, the X-Canton-Network header on the Canton MCP server (its gate sits above the MCP envelope and cannot read tool arguments), or --canton-networkon the CLI. Resolution order is the explicit selector, then the key’s sole authorized network, then the node’s configured default. A key authorizing exactly one network needs no selector; a key authorizing more and given none returns -32004 naming the authorized set.
Each key carries a tier bounding its budget over a sliding 60-second window: free at 60 requests/min with writes refused, standard at 600, priority at 6,000. A mandate-bound write needs standard or above. Over-budget returns -32005 with retry_after_ms, requests_per_minute, and tier.
A tenant key acts as its bound primaryParty and is bounded by canton_networks. The operator admin token skips the key gate entirely, so it is bounded by no key and reaches party allocation, DAR upload, rights grants, and identity-provider management — but it must still name a network explicitly, because there is no key from which to infer one.
Mandate-bound write
The autonomous agent presents two things on every Canton write: a scoped API key with can_act_as_parties populated, and an AP2 cart mandate pair (a checkout VDC signed by the principal + a payment VDC signed by the agent).
{
"jsonrpc": "2.0",
"method": "tenzro_canton_submitWithMandate",
"params": {
"mandate": {
"checkout": { /* AP2 checkout VDC */ },
"payment": { /* AP2 payment VDC */ }
},
"command_type": "create",
"template_id": "#splice-amulet:Splice.AmuletRules:Transfer",
"create_arguments": {
"to": "Counterparty::abc123...",
"amount": "1000000",
"memo": "settlement-2026-06"
}
},
"id": 1
}The handler executes fail-closed at every step: parse → AP2 validate with delegation enforcement → forward the stripped command to the existing DAML submit handler → return both receipts.
Scoped read
tenzro_canton_watchParty is the agent-facing read surface. Authorization: the presenting API key must satisfy can_read_as(party) (which can_act_as_parties implies).
{
"jsonrpc": "2.0",
"method": "tenzro_canton_watchParty",
"params": {
"party": "TenzroLabs::abc123...",
"template_ids": ["#splice-amulet:Splice.AmuletRules:Holding"]
},
"id": 1
}Operator analytics
tenzro_canton_aggregateAnalytics rolls up the per-key counters CantonAnalyticsManager tracks. Admin-token-gated; tenants can't read across each other.
{
"buckets": [
{ "key": "did:tenzro:machine:abc...", "total_calls": 12450, "last_called_at": 1717977600 },
{ "key": "did:tenzro:machine:def...", "total_calls": 3187, "last_called_at": 1717976000 }
],
"row_count": 2,
"group_by": "subject"
}Workflow templates
The Canton-settlement reference workflow template wraps submitWithMandate as a single-step workflow. Tenants instantiate it via tenzro_useResource; the workflow executor handles the dispatch.
See Resources for the full workflow runtime model.
SDK access
Rust SDK — the canton() accessor on TenzroClient:
let client = TenzroClient::connect(SdkConfig::testnet()).await?;
let canton = client.canton();
let receipt = canton
.create_contract_with_mandate(&mandate, template_id, args, None)
.await?;TypeScript SDK — the CantonClient class:
import { TenzroClient } from '@tenzro/sdk';
const client = new TenzroClient({ rpcUrl: 'https://rpc.tenzro.xyz' });
const receipt = await client.canton.submitWithMandate(mandate, {
command_type: 'create',
template_id: templateId,
create_arguments: args,
});Mandate-bound writes, scoped party reads and the analytics rollup all live on the same client as the operator reads and writes, so onNetwork() pinning and the API-key tier apply uniformly.