CapTableBatch wraps Canton’s UpdateCapTable choice for incremental OCF changes. Instances are created exclusively through ocp.OpenCapTable.capTable.update, chaining create / edit / delete before build (manual Canton submission via submitAndWaitForTransactionTree) or execute (SDK-led submission). All-or-nothing semantics hold: one transaction, one choice, every batched row.
Import and construction
import { OcpClient, toContractId, toPartyId } from '@open-captable-protocol/canton';
const batch = ocp.OpenCapTable.capTable.update({
capTableContractId: toContractId('CAP_TABLE_CONTRACT_ID'),
capTableContractDetails: { templateId: 'optional when template diverges' },
actAs: [toPartyId('issuer::namespace')],
readAs: optionalReadScope,
});
The constructor is not public—always start from update.
Operations
| Method | Purpose |
|---|---|
create(type, data) | Queue an OCF create for supported type keys (for example stakeholder, stockIssuance, vestingTerms). Rejects issuer—issuers must join through CreateCapTable. |
edit(type, data) | Queue an edit; data.id must match the live OCF id. |
delete(type, id) | Queue a delete by OCF id; issuer delete is blocked. |
build() | Validate JSON safety, synthesize ExerciseCommand, expose disclosedContracts ([] today for UpdateCapTable). Throws OcpValidationError on empty batches (batch) or unsafe payloads (batch.payload). |
execute() | Calls build(), submits via submitAndWaitForTransactionTree with actAs/readAs from params. Throws OcpValidationError if no ledger client (construct through update) or OcpContractError on ledger faults—execution wraps context with getDetailedSummary. Successful runs include updatedCapTableCid—cache it immediately for the next update. |
clear() | Reset queued operations/metadata to reuse builder instance safely. Returns this for chaining. |
getDetailedSummary() | Returns { creates: BatchItemMeta[]; edits: BatchItemMeta[]; deletes: BatchItemMeta[] } correlating id/entityType/securityId paths for issuance rows—used in OcpContractError debugging. |
size / isEmpty | Inspect queue cardinality. |
JSON safety: Canton rejects undefined anywhere in payloads. Use null for optional/absent scalar slots; assertJsonSafe walks the tree (batch.payload path on failure).
Plan security synonyms (planSecurity* aliases) internally normalize toward equity-compensation payloads.
Example — multi-step round trip
batch
.create('stakeholder', {
id: 'sh_alice',
object_type: 'STAKEHOLDER',
name: { legal_name: 'Alice Example' },
stakeholder_type: 'INDIVIDUAL',
current_relationship: 'EMPLOYEE',
})
.create('stockClass', {
id: 'sc_common',
object_type: 'STOCK_CLASS',
name: 'Common Stock',
class_type: 'COMMON',
default_id_prefix: 'CS-',
initial_shares_authorized: '10000000',
votes_per_share: '1',
par_value: { amount: '0.01', currency: 'USD' },
price_per_share: { amount: '0.10', currency: 'USD' },
seniority: '1',
})
.edit('issuer', { id: 'issuer_demo', comments: [{ comment_type: 'NOTE', comment: 'Seeded stakeholder + class.' }] })
.delete('document', 'doc_placeholder');
const { updateId, updatedCapTableCid } = await batch.execute();
Errors
| Scenario | Raised error |
|---|---|
| No operations queued | OcpValidationError('batch') (REQUIRED_FIELD_MISSING) |
undefined in payload | OcpValidationError('batch.payload') (INVALID_TYPE) plus JSON path diagnostics |
| Invalid entity key or unsupported combo | OcpValidationError('type') (INVALID_TYPE) |
Issuer create/delete attempted | OcpValidationError('type') |
Ledger submission failure during execute | OcpContractError with CHOICE_FAILED, attaches batchItems, includes cause |
build()/execute() sans ledger-backed batch (client null) | OcpValidationError('client') |
Execution success returns CapTableBatchExecuteResult = UpdateCapTableResult + updateId.
Auth & disclosure
actAs must include issuer signatories; readAs is optional stakeholder visibility widening. Disclosure requirements follow ledger auth—FeaturedAppRight is not auto-attached (disclosedContracts empty unless extended manually via advanced flows).
Always rotate capTableContractId to updatedCapTableCid after each execute (or sync ocp.context.setCapTableContractId).
Related links
Source
CapTableBatch:functions/OpenCapTable/capTable/CapTableBatch.ts- Batch enums:
batchTypes.ts