openapi: 3.0.3 info: title: Ledger v3 API description: API for the Ledger v3, a distributed accounting ledger with Raft consensus version: 1.0.0 contact: name: Formance url: https://formance.com servers: - url: http://localhost:9000 description: Local development server security: - BearerAuth: [] - {} paths: /v3/: get: summary: List all ledgers description: | Lists the ledgers in the cluster, paged by name (ascending unless `reverse=true`). Requires `ledger:read` scope. operationId: listAllLedgers tags: - Ledgers security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/PageCursor' - name: reverse in: query schema: type: boolean default: false description: List in descending name order when true. responses: '200': description: List of ledgers retrieved successfully content: application/json: schema: $ref: '#/components/schemas/ListAllLedgersResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /health: get: summary: Health check description: Returns the health status of the node. Returns 503 if the node is not connected to the cluster. operationId: health tags: - Health responses: '200': description: Node is healthy content: application/json: schema: $ref: '#/components/schemas/HealthResponse' '503': $ref: '#/components/responses/ServiceUnavailable' /livez: get: summary: Liveness probe description: Returns 200 as long as the process is alive. Suitable for Kubernetes liveness probes. operationId: livez tags: - Health responses: '200': description: Process is alive content: application/json: schema: $ref: '#/components/schemas/HealthResponse' /readyz: get: summary: Readiness probe description: | Returns 200 once the local Raft loop has started, regardless of whether a leader has been elected. Suitable for Kubernetes readiness probes and StatefulSet `OrderedReady` ordering: it is intentionally permissive so peer pods can be brought up during a cold start where quorum cannot form until they exist. Use `/clusterz` for the stricter cluster-availability signal. operationId: readyz tags: - Health responses: '200': description: Local Raft loop has started content: application/json: schema: $ref: '#/components/schemas/HealthResponse' '503': $ref: '#/components/responses/ServiceUnavailable' /clusterz: get: summary: Cluster-availability probe description: | Returns 200 only when the node is part of a healthy cluster (Raft state healthy and a leader elected). Disk and clock skew gate writes (see admission), not cluster readiness. Returns 503 otherwise. Use this for external monitoring or any client that needs to wait until the node can actually serve cluster-dependent traffic. Kubernetes readiness probes should target `/readyz` instead — this endpoint MUST NOT gate StatefulSet ordering, otherwise the cluster cannot recover from a full-kill cold start. operationId: clusterz tags: - Health responses: '200': description: Node is part of a healthy cluster content: application/json: schema: $ref: '#/components/schemas/HealthResponse' '503': $ref: '#/components/responses/ServiceUnavailable' /_info: get: summary: Get server build information description: Returns the server build metadata (version, commit, build date, Go runtime version). Unauthenticated. operationId: info tags: - Health responses: '200': description: Server build information content: application/json: schema: $ref: '#/components/schemas/ServerInfo' /v3/{ledgerName}: get: summary: Get a ledger description: Retrieves a ledger by its name. Requires `ledger:read` scope. operationId: getLedger tags: - Ledgers security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' responses: '200': description: Ledger retrieved successfully content: application/json: schema: $ref: '#/components/schemas/GetLedgerResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' post: summary: Create a new ledger description: | Creates a new ledger with the specified name. Storage is configured at the server level. Each ledger has its own Raft group for data consistency. Requires `ledger:write` scope. The ledger name `_` is reserved: all system / non-ledger routes live under the `/v3/_/…` segment (e.g. `/v3/_/audit-entries`), so a ledger named `_` would be unreachable over REST. Creating it is rejected with a validation error. The exact name `_system` is also reserved for system events and rejected. Other underscore-prefixed names remain valid. operationId: createLedger tags: - Ledgers security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateLedgerRequest' responses: '201': description: Ledger created successfully content: application/json: schema: $ref: '#/components/schemas/CreateLedgerResponse' links: GetCreatedLedger: operationId: getLedger parameters: ledgerName: '$response.body#/data/name' DeleteCreatedLedger: operationId: deleteLedger parameters: ledgerName: '$response.body#/data/name' GetLedgerStats: operationId: getLedgerStats parameters: ledgerName: '$response.body#/data/name' CreateTransactionInLedger: operationId: createTransaction parameters: ledgerName: '$response.body#/data/name' ListLedgerAccounts: operationId: listAccounts parameters: ledgerName: '$response.body#/data/name' ListLedgerLogs: operationId: listLedgerLogs parameters: ledgerName: '$response.body#/data/name' SaveNumscriptInLedger: operationId: saveNumscript parameters: ledgerName: '$response.body#/data/name' BulkInLedger: operationId: bulkOperations parameters: ledgerName: '$response.body#/data/name' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' delete: summary: Delete a ledger description: Deletes a ledger by its name. This operation removes the ledger and its associated Raft group from the cluster. Requires `ledger:write` scope. operationId: deleteLedger tags: - Ledgers security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/IdempotencyKey' responses: '204': description: Ledger deleted successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/stats: get: summary: Get ledger statistics description: >- Returns aggregate usage statistics (transaction, volume, reference, posting, log, revert and Numscript-execution counts, plus ephemeral-evicted and transient-used volume tallies) for a ledger. Requires `ledger:read` scope. On live reads, `transactionCount` and `logCount` are FSM-backed. The seven usage-derived counters (`postingCount`, `revertCount`, `numscriptExecutionCount`, `referenceCount`, `ephemeralEvictedCount`, `transientUsedCount`, `volumeCount`) are materialised asynchronously in the serving replica's usagestore and may lag committed state even after the request's ReadIndex barrier. Note: for checkpoint-scoped (historical) reads, only `transactionCount` and `logCount` are checkpoint-consistent; the usage-derived counters (`postingCount`, `revertCount`, `numscriptExecutionCount`, `referenceCount`, `ephemeralEvictedCount`, `transientUsedCount`, `volumeCount`) are sourced from the live usagestore projection, which is not checkpoint-aware, and are returned as `0` at a checkpoint rather than a live value — treat `0` on a checkpoint read as "not available at this checkpoint". operationId: getLedgerStats tags: - Ledgers security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' responses: '200': description: Ledger statistics retrieved successfully content: application/json: schema: $ref: '#/components/schemas/GetLedgerStatsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: Ledger not found (`LEDGER_NOT_FOUND`) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/logs: get: summary: List logs for a ledger description: | Lists log entries for a specific ledger, paged by ledger-local log ID (ascending unless `reverse=true`). Requires the builtin `LOG` index to be enabled on the ledger via `CreateIndex`. Requires `ledger:read` scope. operationId: listLedgerLogs tags: - Logs security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/PageCursor' - name: reverse in: query schema: type: boolean default: false description: List in descending ledger-local log ID order when true. - name: startDate in: query schema: type: string format: date-time description: | Filter logs with date >= startDate (inclusive, RFC3339 format). Must be on or after the Unix epoch (1970-01-01T00:00:00Z); earlier dates are rejected with a 400. Requires the builtin `LOG_DATE` index to be enabled on the ledger. - name: endDate in: query schema: type: string format: date-time description: | Filter logs with date < endDate (exclusive, RFC3339 format). Must be on or after the Unix epoch (1970-01-01T00:00:00Z); earlier dates are rejected with a 400. Requires the builtin `LOG_DATE` index to be enabled on the ledger. - $ref: '#/components/parameters/ListFilter' responses: '200': description: Logs retrieved successfully content: application/json: schema: type: object required: - data - hasMore properties: data: type: array items: $ref: '#/components/schemas/SystemLog' next: $ref: '#/components/schemas/PageToken' previous: $ref: '#/components/schemas/PageToken' hasMore: type: boolean description: True when a following page exists; set iff `next` is. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/_/audit-entries: get: summary: List audit entries description: | Lists audit trail entries (one per proposal, success or failure) across the whole bucket, paged by audit sequence (ascending unless `reverse=true`). Audit reads are not ledger-scoped in the path — a single proposal can touch several ledgers — so ledger scope, outcome and other dimensions are expressed through the `filter` query parameter. This endpoint always performs a live read and does not expose pinned checkpoint reads. Filters containing indexed audit conditions wait for the audit projection to certify the request's fixed main-store horizon; matching entries are loaded from that same main snapshot. Unfiltered reads and sequence-only bounds scan the audit zone directly without waiting for the audit projection. Requires `ledger:AuditRead` scope. operationId: listAuditEntries tags: - Audit security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/PageCursor' - name: reverse in: query schema: type: boolean default: false description: Iterate newest-first (descending sequence) when true - name: filter in: query schema: type: string description: | A filter, decoded by the same shared dual-format decoder every list endpoint uses (see the `ListFilter` parameter). In practice audit filters use the **textual** representation, restricted to bare audit fields (`outcome`, `ledger`, `seq`, `proposal_id`, `timestamp`, `log_seq`, `caller_subject`, `order_type`, `idempotency_key`). These are written without any prefix and are resolved against the audit query target (EN-1549 — this replaced the old `audit[...]` namespaced syntax; it is a breaking change with no backward compatibility): - `outcome == failure` - `ledger == main` - `order_type in (create_transaction, revert_transaction)` - `seq between 1000 and 2000` - `timestamp >= "2023-11-14T22:13:20Z"` - `idempotency_key == "retry-123"` - `idempotency_key ^= "import-2026-"` Supported fields: `seq`, `proposal_id`, `log_seq` (numeric); `timestamp` (RFC3339 or unix microseconds); `outcome` (success|failure), `ledger`, `caller_subject`, `order_type`, `idempotency_key` (string; `idempotency_key` also supports prefix matching with `^=`; a reused key returns every historical audit entry; bare alphanumeric values are accepted unquoted, while values containing `-`, `:`, spaces, or other non-identifier characters must be single- or double-quoted; keys containing both `"` and `'` cannot be expressed in the textual DSL and require the gRPC API directly: use `AuditCondition.string_cond` (one value per leaf) for exact lookups, an `OrFilter` of such leaves for `in` lookups, and `AuditCondition.string_prefix` for prefix lookups). Bare audit fields are resolved against the audit query target: `timestamp` and `ledger` collide with the transaction `timestamp` field and the top-level `ledger` condition, so on the audit target they resolve to the audit condition (and only there — hence audit fields are valid on this endpoint only). Audit conditions have NO structured JSON QueryFilter representation, so the textual form is the canonical one here; a JSON QueryFilter cannot carry an audit condition and is rejected. responses: '200': description: List of audit entries content: application/json: schema: type: object required: - data - hasMore properties: data: type: array items: $ref: '#/components/schemas/AuditEntry' next: $ref: '#/components/schemas/PageToken' previous: $ref: '#/components/schemas/PageToken' hasMore: type: boolean description: True when a following page exists; set iff `next` is. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/_/audit-entries/{sequence}: get: summary: Get an audit entry description: | Returns a single audit entry by its global sequence, with per-order `items` populated (the list endpoint omits `items` for compactness). Requires `ledger:AuditRead` scope. operationId: getAuditEntry tags: - Audit security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - name: sequence in: path required: true schema: type: integer format: uint64 minimum: 0 description: Audit entry sequence responses: '200': description: The audit entry content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/AuditEntry' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/promote: post: summary: Promote a mirror ledger description: | Promotes a mirror-mode ledger to normal mode. After promotion, the mirror sync worker is stopped and the ledger accepts direct write operations. Requires `ledger:write` scope. operationId: promoteLedger tags: - Ledgers security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' responses: '201': description: Ledger promoted successfully content: application/json: schema: $ref: '#/components/schemas/PromoteLedgerResponse' '400': description: The request is invalid, or the ledger is not in mirror mode (`LEDGER_NOT_IN_MIRROR_MODE`). content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': description: The ledger has been deleted (`LEDGER_DELETED`). content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/transactions: post: summary: Create a new transaction description: Creates a new transaction in the specified ledger with the specified postings. Requires `ledger:write` scope. operationId: createTransaction tags: - Transactions security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateTransactionRequest' responses: '201': description: Transaction created successfully content: application/json: schema: $ref: '#/components/schemas/CreateTransactionResponse' links: GetCreatedTransaction: operationId: getTransaction parameters: ledgerName: '$request.path.ledgerName' transactionId: '$response.body#/data/transaction/id' RevertCreatedTransaction: operationId: revertTransaction parameters: ledgerName: '$request.path.ledgerName' transactionId: '$response.body#/data/transaction/id' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': description: Conflict (concurrent modification, or reference already claimed by another transaction). Callers that need continue-on-failure semantics should use the bulk endpoint with a per-entry `skippableReasons` list. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' get: summary: List transactions for a ledger description: | Lists transactions for a specific ledger. The default order is newest-first (descending transaction id); pass `reverse=true` to get oldest-first (ascending). Supports cursor pagination (`pageSize`, `cursor`), an optional date range (`startDate`/`endDate`), and the generic `filter` parameter (e.g. reference selection via `filter={"$match":{"reference":"..."}}`, URL-encoded). Requires `ledger:TransactionRead` scope. This is a live read, linearizable by default. `X-Consistency: stale` reads the receiving node's local state, which may lag the leader. Every projection used by the filter is automatically aligned. Unlike the gRPC API, it does not accept the `checkpointId` option to pin the read to a specific historical snapshot — use gRPC for checkpoint-pinned reads. (Tracked follow-up, same carve-out as the audit reads.) operationId: listLedgerTransactions tags: - Transactions security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/PageCursor' - name: reverse in: query schema: type: boolean default: false description: | Reverse the default order. Default (`false`) returns newest-first (descending); `true` returns oldest-first (ascending). Mirrors the gRPC `ListTransactions` reverse flag semantic. - name: startDate in: query schema: type: string format: date-time description: | Filter transactions with timestamp >= startDate (inclusive, RFC3339 format). Requires the builtin `TX_BUILTIN_INDEX_TIMESTAMP` index to be enabled on the ledger. - name: endDate in: query schema: type: string format: date-time description: | Filter transactions with timestamp < endDate (exclusive, RFC3339 format). Requires the builtin `TX_BUILTIN_INDEX_TIMESTAMP` index to be enabled on the ledger. - $ref: '#/components/parameters/ListFilter' - $ref: '#/components/parameters/QueryProfile' responses: '200': description: Transactions retrieved successfully. headers: X-Query-Profile-Result: $ref: '#/components/headers/QueryProfileResult' content: application/json: schema: type: object required: - data - hasMore properties: data: type: array items: $ref: '#/components/schemas/TransactionResponse' next: $ref: '#/components/schemas/PageToken' previous: $ref: '#/components/schemas/PageToken' hasMore: type: boolean description: True when a following page exists; set iff `next` is. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/transactions/{transactionId}: get: summary: Get a transaction description: Retrieves a transaction by its ID from the specified ledger. Requires `ledger:read` scope. operationId: getTransaction tags: - Transactions security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/TransactionId' responses: '200': description: Transaction retrieved successfully content: application/json: schema: $ref: '#/components/schemas/GetTransactionResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/accounts: get: summary: List accounts description: | Lists accounts in a ledger in alphabetical order with cursor pagination and an optional generic `filter` (e.g. address-prefix selection via `filter=address ^= "users:"`). Requires `ledger:read` scope. operationId: listAccounts tags: - Accounts security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/PageCursor' - name: reverse in: query schema: type: boolean default: false description: | Reverse the default order. Default (`false`) returns accounts in alphabetical order; `true` returns reverse alphabetical order. - $ref: '#/components/parameters/ListFilter' - $ref: '#/components/parameters/QueryProfile' responses: '200': description: List of accounts headers: X-Query-Profile-Result: $ref: '#/components/headers/QueryProfileResult' content: application/json: schema: type: object required: - data - hasMore properties: data: type: array items: $ref: '#/components/schemas/Account' next: $ref: '#/components/schemas/PageToken' previous: $ref: '#/components/schemas/PageToken' hasMore: type: boolean description: True when a following page exists; set iff `next` is. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/accounts/{address}: get: summary: Get an account description: Retrieves account information including metadata for a specific account address. Requires `ledger:read` scope. operationId: getAccount tags: - Accounts security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/AccountAddress' - name: collapseColors in: query required: false schema: type: boolean default: false description: | When true, every colored bucket of the same asset is summed into a single AccountVolume entry with color = "". By default each (asset, color) tuple is returned as its own entry. responses: '200': description: Account retrieved successfully content: application/json: schema: $ref: '#/components/schemas/GetAccountResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/volumes: get: summary: Aggregate volumes description: | Returns aggregated volumes (input/output/balance per asset) across all accounts in the ledger. Supports filtering accounts with the generic `filter` parameter, grouping by account prefixes, and max-precision merging. Requires `ledger:AccountRead` scope. operationId: aggregateVolumes tags: - Volumes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/ListFilter' - name: useMaxPrecision in: query description: Merge assets with the same base at the highest observed precision schema: type: boolean default: false - name: groupByPrefixes in: query description: Comma-separated list of account prefixes to group volumes by schema: type: string - name: collapseColors in: query description: | When true, every colored bucket of the same (asset, precision) is summed and the resulting AggregatedVolume entry carries color = "". By default the response is segregated per (asset, color). schema: type: boolean default: false - $ref: '#/components/parameters/QueryProfile' responses: '200': description: Aggregated volumes retrieved successfully headers: X-Query-Profile-Result: $ref: '#/components/headers/QueryProfileResult' content: application/json: schema: $ref: '#/components/schemas/AggregateVolumesResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/metadata: post: summary: Save ledger metadata description: >- Saves metadata key-value pairs on the ledger itself. Requires `ledger:MetadataWrite`; `ledger:write` grants it under the default scope mapping. Custom scope mappings can differ. operationId: saveLedgerMetadata tags: - Ledgers security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: Metadata key-value pairs (supports typed values) example: environment: production team: payments region: eu-west-1 responses: '204': description: Ledger metadata saved successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/metadata/{key}: delete: summary: Delete ledger metadata description: Deletes a metadata key from the ledger. Requires `ledger:MetadataWrite` scope (included in the default `ledger:write` mapping). operationId: deleteLedgerMetadata tags: - Ledgers security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/MetadataKey' - $ref: '#/components/parameters/IdempotencyKey' responses: '204': description: Ledger metadata deleted successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/accounts/{address}/metadata: post: summary: Save account metadata description: Saves metadata for a specific account in the ledger. Requires `ledger:MetadataWrite` scope (included in the default `ledger:write` mapping). operationId: saveAccountMetadata tags: - Accounts security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/AccountAddress' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: Metadata key-value pairs (supports typed values) example: account_type: asset label: Bank Account active: true balance_threshold: 1000 responses: '204': description: Account metadata saved successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/transactions/{transactionId}/metadata: post: summary: Save transaction metadata description: Saves metadata for a specific transaction in the ledger. Requires `ledger:MetadataWrite` scope (included in the default `ledger:write` mapping). operationId: saveTransactionMetadata tags: - Transactions security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/TransactionId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: Metadata key-value pairs (supports typed values) example: reason: correction source: support priority: 1 responses: '204': description: Transaction metadata saved successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/accounts/{address}/metadata/{key}: delete: summary: Delete account metadata description: Deletes a metadata key for a specific account in the ledger. Requires `ledger:MetadataWrite` scope (included in the default `ledger:write` mapping). operationId: deleteAccountMetadata tags: - Accounts security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/AccountAddress' - $ref: '#/components/parameters/MetadataKey' - $ref: '#/components/parameters/IdempotencyKey' responses: '204': description: Account metadata deleted successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/transactions/{transactionId}/metadata/{key}: delete: summary: Delete transaction metadata description: Deletes a metadata key for a specific transaction in the ledger. Requires `ledger:MetadataWrite` scope (included in the default `ledger:write` mapping). operationId: deleteTransactionMetadata tags: - Transactions security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/TransactionId' - $ref: '#/components/parameters/MetadataKey' - $ref: '#/components/parameters/IdempotencyKey' responses: '204': description: Transaction metadata deleted successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/transactions/{transactionId}/revert: post: summary: Revert a transaction description: | Reverts a transaction by creating a reverse transaction that undoes its effects. Requires `ledger:write` scope. The body is optional; an absent or empty body uses default options. Supplied options and metadata are decoded for both known-length and HTTP/1.1 chunked requests. Malformed or truncated JSON, extra values, trailing non-whitespace and options of the wrong JSON type (for example `"atEffectiveDate": "true"` or a non-object `metadata`) return 400 before applying the revert. A JSON `null` option uses its default. The complete body, including trailing whitespace, counts towards the 4 MiB limit; exceeding it returns 413. operationId: revertTransaction tags: - Transactions security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/TransactionId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/RevertTransactionRequestBody' responses: '201': description: Transaction reverted successfully content: application/json: schema: $ref: '#/components/schemas/RevertedTransactionResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': description: Conflict (e.g. transaction already reverted) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '413': description: Request body exceeds the 4 MiB limit content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/metadata-schema: get: summary: Get metadata schema description: Returns the declared type of every metadata field on a ledger. Requires `ledger:read` scope. operationId: getMetadataSchemaStatus tags: - Metadata Schema security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' responses: '200': description: Metadata schema status retrieved successfully content: application/json: schema: $ref: '#/components/schemas/MetadataSchemaStatusResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/indexes/{canonicalId}/inspect: get: summary: Inspect a metadata index description: | Scans a metadata index and returns distinct values, facets (value + count), or a summary (cardinality, min/max, existence counts). The index must be in READY state. Only metadata indexes are inspectable (builtin indexes return 400). Requires `ledger:read` scope. operationId: inspectIndex tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' - name: canonicalId in: path required: true description: | Canonical form of the target IndexID, e.g. `metadata:TARGET_TYPE_ACCOUNT:color`. Must resolve to a metadata index; builtin indexes (`tx_builtin:...`, etc.) are rejected. schema: type: string - name: mode in: query description: Inspection mode schema: type: string enum: [summary, distinctValues, facets] default: summary - name: pageSize in: query description: Page size for distinctValues/facets modes schema: type: integer minimum: 1 maximum: 10000 - name: cursor in: query description: | Page token from a previous response's `nextCursor` or `previousCursor`, for distinctValues/facets modes (see the `PageToken` schema; the key is the base64url encoding of the metadata value). Omit for the first page. schema: $ref: '#/components/schemas/PageToken' responses: '200': description: Index inspection result content: application/json: schema: type: object required: - data properties: data: oneOf: - $ref: '#/components/schemas/InspectSummaryResponse' - $ref: '#/components/schemas/InspectDistinctValuesResponse' - $ref: '#/components/schemas/InspectFacetsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/analyze-accounts: get: summary: Analyze accounts and suggest a Chart of Accounts description: | Scans all accounts in a ledger, discovers address patterns, and returns a suggested Chart of Accounts. Useful after a mirror import to understand account structure. Requires `ledger:read` scope. operationId: analyzeAccounts tags: - Accounts security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' - name: variableThreshold in: query description: Max distinct children before classifying as variable (0 = default 10) required: false schema: type: integer format: int32 default: 0 responses: '200': description: Analysis completed successfully content: application/json: schema: $ref: '#/components/schemas/AnalyzeAccountsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/analyze-transactions: get: summary: Analyze transaction flow patterns description: | Scans all transactions in a ledger, discovers flow patterns by normalizing account addresses, and returns statistics per flow type including temporal distribution and volume metrics. Requires `ledger:read` scope. operationId: analyzeTransactions tags: - Transactions security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - name: variableThreshold in: query description: Max distinct children before classifying as variable (0 = default 10) required: false schema: type: integer format: int32 default: 0 responses: '200': description: Analysis completed successfully content: application/json: schema: $ref: '#/components/schemas/AnalyzeTransactionsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/metadata-schema/{targetType}/{key}: put: summary: Set metadata field type description: | Declares or changes the type used to encode a metadata key in an attached query index. Metadata values are neither validated nor converted by this declaration, and existing primary values remain unchanged. Any attached index is rewritten asynchronously. Requires `ledger:MetadataWrite` scope (included in the default `ledger:write` mapping). operationId: setMetadataFieldType tags: - Metadata Schema security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/TargetType' - $ref: '#/components/parameters/MetadataKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SetMetadataTypeRequest' responses: '204': description: Metadata field type set successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' delete: summary: Remove metadata field type description: | Removes the type declaration for a metadata key on a ledger. Existing metadata values remain unchanged and any attached index is dropped. Requires `ledger:MetadataWrite` scope (included in the default `ledger:write` mapping). operationId: removeMetadataFieldType tags: - Metadata Schema security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/TargetType' - $ref: '#/components/parameters/MetadataKey' responses: '204': description: Metadata field type removed successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/numscripts: get: summary: List all numscripts description: | Lists every numscript of a ledger at its greatest stored version, paged by name (ascending unless `reverse=true`). operationId: listNumscripts tags: - Numscript Library security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/PageCursor' - name: reverse in: query schema: type: boolean default: false description: List in descending name order when true. responses: '200': description: List of numscripts retrieved successfully content: application/json: schema: $ref: '#/components/schemas/ListNumscriptsResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '400': $ref: '#/components/responses/BadRequest' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/numscripts/{name}: get: summary: Get a numscript description: | Retrieves a numscript by name from a ledger. Use the `version` query parameter to get a specific semver version. If omitted or empty, the latest version is returned. operationId: getNumscript tags: - Numscript Library security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' - name: name in: path required: true schema: type: string description: Name of the numscript - name: version in: query required: false schema: type: string description: | Semver version to retrieve (e.g. "1.0.0"). If omitted or empty, the latest version is returned. responses: '200': description: Numscript retrieved successfully content: application/json: schema: $ref: '#/components/schemas/GetNumscriptResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '400': $ref: '#/components/responses/BadRequest' '404': description: Numscript not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': $ref: '#/components/responses/ServiceUnavailable' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '405': $ref: '#/components/responses/MethodNotAllowed' put: summary: Save a numscript description: | Appends an immutable version to a ledger's numscript library. The `version` field must be an explicit full semver (e.g. "1.0.0"); it creates a new version and fails if that version already exists. The per-name latest is always the greatest stored semver. operationId: saveNumscript tags: - Numscript Library security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - name: name in: path required: true schema: type: string description: Name of the numscript requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SaveNumscriptRequest' responses: '201': description: Numscript saved successfully content: application/json: schema: $ref: '#/components/schemas/GetNumscriptResponse' links: GetSavedNumscript: operationId: getNumscript parameters: ledgerName: '$request.path.ledgerName' name: '$response.body#/data/name' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '400': description: Bad request (version not an explicit full semver, parse error, etc.) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '409': description: | The version already exists (`NUMSCRIPT_VERSION_ALREADY_EXISTS`) — stored versions are immutable and cannot be overwritten — or the ledger has been deleted (`LEDGER_DELETED`). content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/numscripts/{name}/versions: get: summary: List numscript versions description: | Returns the numscript's history: its current latest (greatest stored semver) and every stored version, highest-first. operationId: listNumscriptVersions tags: - Numscript Library security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' - name: name in: path required: true schema: type: string description: Name of the numscript responses: '200': description: Numscript versions retrieved successfully content: application/json: schema: $ref: '#/components/schemas/ListNumscriptVersionsResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '400': $ref: '#/components/responses/BadRequest' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/numscripts/{name}/usage: get: summary: Get template usage description: | Returns the invocation counter and last-used timestamp for a Numscript template. Values are materialised asynchronously by the `usagebuilder` subsystem from the FSM audit chain and may lag the live FSM while the worker drains pending batches. A never-invoked template returns a zero-valued response (not 404), so clients handle "never used" uniformly. operationId: getNumscriptUsage tags: - Numscript Library security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' - name: name in: path required: true schema: type: string description: Name of the numscript template responses: '200': description: Template usage retrieved successfully content: application/json: schema: $ref: '#/components/schemas/GetTemplateUsageResponse' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '400': $ref: '#/components/responses/BadRequest' '404': description: Ledger not found (`LEDGER_NOT_FOUND`) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': $ref: '#/components/responses/ServiceUnavailable' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/bulk: post: summary: Bulk operations description: | Execute multiple operations (create transactions, add metadata, revert transactions, delete metadata) in a single request. Requires `ledger:write` scope. With `atomic=true`, all elements target the URL's ledger and are submitted as one batch. `Idempotency-Key` identifies that whole batch; per-element `ik` values are ignored. With `atomic=false` (default), each element is submitted separately under its own `ik`; the header is ignored. `continueOnFailure` controls sequential continuation and business-error status rollup. It does not allow partial application of an atomic batch. Non-atomic failures can follow already committed elements: inspect every result and preserve the original identities when retrying. A timeout or infrastructure failure does not prove that work was not committed. This contract does not enable automatic SDK retries. The response status is decided in three tiers: 1. **Request-level failures** (before per-element processing): malformed body → `400`, missing/insufficient scope → `401` or `403`, too many elements → `413`. Exceeding the byte limit while decoding the body currently returns `400`. Returned unconditionally, `continueOnFailure` does not apply. 2. **Infrastructure failures during processing** (transport timeout, cache-horizon exceeded, storage error): the overall status is `503` for retryable failures and `500` otherwise, regardless of `continueOnFailure`. Callers must inspect the element outcomes before deciding what to retry. 3. **Per-element errors during processing**: each element's error carries the HTTP status it would surface as a single request (via the same mapping `handleError` uses). The top-level status is the "worst" of them, with `continueOnFailure` applying only to per-element business failures (4xx): - Business failures (validation, not-found, conflict, precondition, permission — 4xx): rolled up per `continueOnFailure`. `true` → `200`; `false` (default) → the highest 4xx among failing elements (typically `400`). - Resource exhaustion (`KindResourceExhausted`, `429`), including rate limits and permanent authoritative-sequence exhaustion: surface unconditionally as `429`. - Retryable infrastructure failures (leader loss, cache-horizon exceeded, `KindUnavailable`): surface as `503` with `Retry-After: 1`, regardless of `continueOnFailure`. - Non-retryable infrastructure failures (transport / storage errors, `KindInternal`, unclassified): surface as `500`. - Aborted elements (`context.Canceled` from the sequential runner after a prior failure): contribute nothing — the originating error drives the rollup. operationId: bulkOperations tags: - Transactions security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/IdempotencyKey' - name: continueOnFailure in: query schema: type: boolean default: false description: | Continue sequential processing after a failure and suppress the top-level status for business errors. Does not suppress 429 or 5xx failures, or permit partial application when atomic=true. - name: atomic in: query schema: type: boolean default: false description: | Submit all operations as one atomic batch under the optional Idempotency-Key header. Per-element ik values are ignored. All elements target ledgerName. On failure every element reports the batch error; continueOnFailure does not change atomicity. requestBody: required: true content: application/json: schema: type: array items: $ref: '#/components/schemas/BulkElement' responses: '200': description: Bulk operations completed content: application/json: schema: $ref: '#/components/schemas/BulkResponse' '400': description: Bulk operations completed with errors, or invalid request content: application/json: schema: $ref: '#/components/schemas/BulkErrorResponse' '429': description: | A per-element error mapped to `KindResourceExhausted` (quota, rate limit, or authoritative-sequence exhaustion during processing). Surfaces unconditionally, regardless of `continueOnFailure`. Body carries the per-element details in `data`. content: application/json: schema: $ref: '#/components/schemas/BulkResponse' '401': description: Authentication failure before processing or in an element content: application/json: schema: $ref: '#/components/schemas/BulkErrorResponse' text/plain: schema: type: string '403': description: Insufficient scope before processing or permission failure in an element content: application/json: schema: $ref: '#/components/schemas/BulkErrorResponse' '404': description: A ledger or resource was not found during processing content: application/json: schema: $ref: '#/components/schemas/BulkErrorResponse' '409': description: An element or the atomic batch conflicts with existing state content: application/json: schema: $ref: '#/components/schemas/BulkErrorResponse' '413': description: Request entity too large content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '503': description: | Retryable processing failure, including leader loss or an expired admission cache horizon. Surfaces regardless of continueOnFailure. Inspect per-element outcomes before retrying a non-atomic batch. headers: Retry-After: description: Number of seconds to wait before retrying schema: type: integer format: int32 minimum: 1 example: 1 content: application/json: schema: $ref: '#/components/schemas/BulkErrorResponse' '500': description: | Processing failure with per-element outcomes, or an ordinary error from panic recovery. Surfaces regardless of continueOnFailure. An infrastructure failure does not establish whether work committed. content: application/json: schema: $ref: '#/components/schemas/BulkErrorResponse' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/prepared-queries: post: summary: Create a prepared query description: | Creates a new prepared query for a ledger. A prepared query defines a reusable filter that can be executed later with parameter substitution. Requires `ledger:QueryWrite` scope. operationId: createPreparedQuery tags: - Prepared Queries security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreatePreparedQueryRequest' responses: '204': description: Prepared query created successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' get: summary: List prepared queries description: Returns a list of all prepared queries for a ledger. Requires `ledger:QueryRead` scope. operationId: listPreparedQueries tags: - Prepared Queries security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' responses: '200': description: List of prepared queries retrieved successfully content: application/json: schema: $ref: '#/components/schemas/ListPreparedQueriesResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/prepared-queries/{queryName}: put: summary: Update a prepared query description: | Updates the filter of an existing prepared query. Requires `ledger:QueryWrite` scope. operationId: updatePreparedQuery tags: - Prepared Queries security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/QueryName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdatePreparedQueryRequest' responses: '204': description: Prepared query updated successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' delete: summary: Delete a prepared query description: Deletes a prepared query from a ledger. Requires `ledger:QueryWrite` scope. operationId: deletePreparedQuery tags: - Prepared Queries security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/QueryName' responses: '204': description: Prepared query deleted successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/prepared-queries/{queryName}/execute: post: summary: Execute a prepared query description: | Executes a prepared query with optional parameter substitution. Supports LIST and AGGREGATE_VOLUMES modes with cursor pagination. Also accepts pageSize, cursor and reverse as query parameters. Requires `ledger:QueryRead` scope. operationId: executePreparedQuery tags: - Prepared Queries security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/BigIntAsString' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/QueryName' - name: pageSize in: query description: Maximum number of results per page (overrides body value) schema: type: integer format: uint32 - name: cursor in: query description: | Page token from a previous response's `cursor.next` or `cursor.previous` (see the `PageToken` schema). Overrides the body value. schema: $ref: '#/components/schemas/PageToken' - name: reverse in: query description: List in descending entity order when true (overrides body value) schema: type: boolean - $ref: '#/components/parameters/QueryProfile' requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/ExecutePreparedQueryRequest' responses: '200': description: Query executed successfully headers: X-Query-Profile-Result: $ref: '#/components/headers/QueryProfileResult' content: application/json: schema: $ref: '#/components/schemas/ExecutePreparedQueryResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/account-types: post: summary: Add an account type description: | Adds a new account type to a ledger's chart of accounts. Account types define address patterns for account validation. Requires `ledger:MetadataWrite` scope. operationId: addAccountType tags: - Account Types security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddAccountTypeRequest' responses: '201': description: Account type added successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' get: summary: List account types description: | Returns all account types defined on a ledger, sorted by name. Requires `ledger:AccountRead` scope. operationId: listAccountTypes tags: - Account Types security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' responses: '200': description: Account types retrieved successfully content: application/json: schema: $ref: '#/components/schemas/ListAccountTypesResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/account-types/default-enforcement-mode: put: summary: Set default enforcement mode description: | Sets the default enforcement mode for accounts that do not match any defined account type. Must be STRICT or AUDIT. STRICT rejects an order that uses an unmatched account with `400 ACCOUNT_NOT_MATCHING_TYPE`. AUDIT accepts the order and does not report the unmatched account: the response carries no warning. Requires `ledger:MetadataWrite` scope. operationId: setDefaultEnforcementMode tags: - Account Types security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SetDefaultEnforcementModeRequest' responses: '204': description: Default enforcement mode set successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/{ledgerName}/account-types/{typeName}: get: summary: Get an account type description: Retrieves a specific account type by name from a ledger. Requires `ledger:AccountRead` scope. operationId: getAccountType tags: - Account Types security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/TypeName' responses: '200': description: Account type retrieved successfully content: application/json: schema: $ref: '#/components/schemas/GetAccountTypeResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' delete: summary: Remove an account type description: Removes an account type from a ledger's chart of accounts. Requires `ledger:MetadataWrite` scope. operationId: removeAccountType tags: - Account Types security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - $ref: '#/components/parameters/TypeName' responses: '204': description: Account type removed successfully '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' '500': $ref: '#/components/responses/InternalServerError' '405': $ref: '#/components/responses/MethodNotAllowed' /v3/_/logs/{sequence}: get: summary: Get a single system log by bucket-wide sequence description: | Returns the system log entry with the given bucket-wide sequence number. Requires `ledger:OpsRead` scope. operationId: getLog tags: - Logs security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/BigIntAsString' - name: sequence in: path required: true schema: type: integer format: uint64 responses: '200': description: Log retrieved successfully. content: application/json: schema: type: object required: - data properties: data: $ref: '#/components/schemas/SystemLog' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalServerError' /v3/_/events-sinks: get: summary: List configured event sinks description: | Returns every event sink configured on the cluster. Requires `ledger:OpsRead` scope. operationId: getEventsSinks tags: - Ops security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' responses: '400': $ref: '#/components/responses/BadRequest' '200': description: Event sinks retrieved successfully. content: application/json: schema: type: object required: - data properties: data: type: object description: > Configured sinks together with their per-sink status, at parity with the gRPC GetEventsSinks response. properties: sinks: type: array items: type: object additionalProperties: true description: SinkConfig (protobuf JSON representation) sinkStatuses: type: array items: type: object additionalProperties: true description: > SinkStatus (protobuf JSON representation): per-sink error status and last-emitted cursor. Contains one entry per configured sink; removed sinks are not listed. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '500': $ref: '#/components/responses/InternalServerError' post: summary: Add an event sink description: | Adds a named event sink to the cluster. Requires `ledger:OpsWrite` scope. The body is a direct SinkConfig in protobuf JSON form, without a config wrapper. A non-empty name and exactly one sink type are required. Unknown fields, malformed protobuf JSON and multiple oneof members are rejected with `INVALID_REQUEST`. Sink-specific connection settings and credentials are not validated by business admission; successful creation does not guarantee that the sink can connect or publish events. `batchSize` above 100000 returns `SINK_BATCH_SIZE_TOO_LARGE` (400). An existing name returns `SINK_ALREADY_EXISTS` (409). operationId: addEventsSink tags: - Ops security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SinkConfig' responses: '201': description: Event sink created successfully. Only its name is returned. content: application/json: schema: type: object required: [data] properties: data: type: object required: [name] properties: name: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '409': $ref: '#/components/responses/Conflict' '413': description: Request body exceeds the 4 MiB limit content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '429': $ref: '#/components/responses/ResourceExhausted' '500': $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' /v3/_/events-sinks/{sinkName}: delete: summary: Remove an event sink description: | Removes a named event sink from the cluster. Requires `ledger:OpsWrite` scope. A non-empty controllerId must match the sink's controllerId; a mismatch returns `SINK_CONTROLLER_MISMATCH` (409). An omitted or empty controllerId removes the sink without an ownership precondition. A missing sink returns `SINK_NOT_FOUND` (404). Malformed query encoding or repeated controllerId parameters return `INVALID_REQUEST` (400) before Apply, instead of becoming unconditional removal. operationId: removeEventsSink tags: - Ops security: - BearerAuth: [] - {} parameters: - name: sinkName in: path required: true description: Name of the event sink to remove schema: type: string minLength: 1 - name: controllerId in: query required: false description: Optional opaque owner identity used as a removal precondition schema: type: string - $ref: '#/components/parameters/IdempotencyKey' responses: '204': description: Event sink removed successfully. No response body. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/ResourceExhausted' '500': $ref: '#/components/responses/InternalServerError' '503': $ref: '#/components/responses/ServiceUnavailable' /v3/_/signing-keys: get: summary: List registered Ed25519 signing keys description: | Lists the Ed25519 signing keys registered on the cluster, paged by key id (ascending unless `reverse=true`). Requires `ledger:OpsRead` scope. This route performs a live read, linearizable by default. `X-Consistency: stale` reads the receiving node's local state, which may lag the leader. Signing-key reads are live-only on both transports. operationId: listSigningKeys tags: - Ops security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/PageSize' - $ref: '#/components/parameters/PageCursor' - name: reverse in: query schema: type: boolean default: false description: List in descending key id order when true. responses: '200': description: Signing keys retrieved successfully. content: application/json: schema: type: object required: - data - hasMore properties: data: type: array items: type: object additionalProperties: true description: SigningKey (protobuf JSON representation) next: $ref: '#/components/schemas/PageToken' previous: $ref: '#/components/schemas/PageToken' hasMore: type: boolean description: True when a following page exists; set iff `next` is. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '500': $ref: '#/components/responses/InternalServerError' /v3/_/indexes: get: summary: List bucket-wide indexes description: | Streams the bucket-scoped index registry. The `scope` query parameter selects the flavor: `all` (default, matches the ListIndexesRequest proto default) streams every entry across ledgers, skipping orphan entries whose owning ledger no longer exists; `bucket` surfaces only bucket-scoped entries (empty ledger, e.g. audit indexes). Use `GET /v3/{ledgerName}/indexes` for the per-ledger view. Requires `ledger:OpsRead` scope. operationId: listBucketIndexes tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - name: scope in: query schema: type: string enum: [all, bucket] default: all responses: '200': description: Indexes retrieved successfully. content: application/json: schema: type: object required: - data properties: data: type: array items: type: object additionalProperties: true description: Index (protobuf JSON representation) '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '500': $ref: '#/components/responses/InternalServerError' /v3/_/indexes/{canonicalId}: get: summary: Get a single bucket-scoped index registry entry description: | Returns the `Index` registry entry for a bucket-scoped index (`Ledger == ""`, e.g. audit indexes). Ledger-scoped lookups go through `GET /v3/{ledgerName}/indexes/{canonicalId}` — the two keyspaces are distinct so a bucket-scoped lookup with the same canonical will NotFound if only the ledger-scoped entry exists. Requires `ledger:OpsRead` scope. operationId: getBucketIndex tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - name: canonicalId in: path required: true schema: type: string description: Canonical form of the target IndexID. responses: '200': description: Index retrieved successfully. content: application/json: schema: type: object required: - data properties: data: type: object additionalProperties: true description: Index (protobuf JSON representation) '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalServerError' /v3/_/indexes/{canonicalId}/status: get: summary: Get the per-replica status of a single bucket-scoped index description: | Returns the `IndexEntry` (registry entry + backfill cursor + per-replica IndexVersionState) for a bucket-scoped index. Requires `ledger:OpsRead` scope. operationId: getBucketIndexEntryStatus tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - name: canonicalId in: path required: true schema: type: string description: Canonical form of the target IndexID. responses: '200': description: Index entry retrieved successfully. content: application/json: schema: type: object required: - data properties: data: type: object additionalProperties: true description: IndexEntry (protobuf JSON representation) '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalServerError' /v3/_/indexes/status: get: summary: Get aggregated index registry status description: | Returns the aggregated index registry status: per-index backfill cursor, per-replica IndexVersionState (current/pending), and cluster-wide counters (LastIndexedSequence, LastLogSequence, Lag, IndexFileSize). The optional `ledger` query parameter narrows the per-index entries to a single ledger; the aggregated counters always cover the bucket. Requires `ledger:OpsRead` scope. operationId: getIndexStatus tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - name: ledger in: query schema: type: string responses: '400': $ref: '#/components/responses/BadRequest' '200': description: Index status retrieved successfully. content: application/json: schema: type: object required: - data properties: data: type: object additionalProperties: true description: GetIndexStatusResponse (protobuf JSON representation) '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '500': $ref: '#/components/responses/InternalServerError' /v3/{ledgerName}/indexes: get: summary: List indexes for a ledger description: | Streams the indexes registered on a specific ledger. Requires `ledger:LedgerRead` scope. operationId: listLedgerIndexes tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' responses: '200': description: Indexes retrieved successfully. content: application/json: schema: type: object required: - data properties: data: type: array items: type: object additionalProperties: true description: Index (protobuf JSON representation) '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalServerError' post: summary: Create an index on a ledger description: | Registers a new index on the ledger. An existing canonical index on this ledger is rejected with `INDEX_ALREADY_EXISTS` (HTTP 409), even while building or retyping, without changing its definition or progress. Replaying an identical batch with its retained `Idempotency-Key` returns the original result. The indexbuilder processes the accepted creation. The request body carries the target `IndexID` in canonical form (see `DELETE /v3/{ledgerName}/indexes/{canonicalId}` for the format). Requires `ledger:LedgerWrite` scope. operationId: createIndex tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - name: Idempotency-Key in: header schema: type: string requestBody: required: true content: application/json: schema: type: object required: [id] properties: id: type: string description: | Canonical form of the target IndexID. One of: `tx_builtin:` `log_builtin:` `account_builtin:` `metadata::` example: metadata:TARGET_TYPE_ACCOUNT:color responses: '201': description: | Index creation queued. The body carries the canonical id of the created index (round-trip normalized), usable directly on the follow-up GET/DELETE `/v3/{ledgerName}/indexes/{canonicalId}` routes. content: application/json: schema: $ref: '#/components/schemas/CreateIndexResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': description: | Conflict: `INDEX_ALREADY_EXISTS` when the canonical index already exists on this ledger, or an idempotency key conflict. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': $ref: '#/components/responses/InternalServerError' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' /v3/{ledgerName}/indexes/{canonicalId}: get: summary: Get a single index registry entry description: | Returns the `Index` registry entry (id, ledger, createdAt, forwardEncodingVersion) for a single index, serialized in protobuf-JSON camelCase. Requires `ledger:LedgerRead` scope. operationId: getIndex tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' - name: canonicalId in: path required: true schema: type: string description: Canonical form of the target IndexID. responses: '200': description: Index retrieved successfully. content: application/json: schema: type: object required: - data properties: data: type: object additionalProperties: true description: Index (protobuf JSON representation) '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalServerError' delete: summary: Drop an index from a ledger description: | Removes an index from a ledger. The path parameter carries the target `IndexID` in canonical form (e.g. `metadata:TARGET_TYPE_ACCOUNT:color`, `tx_builtin:TX_BUILTIN_INDEX_TIMESTAMP`). Requires `ledger:LedgerWrite` scope. The drop is idempotent. An `IndexID` that has no registry entry on the ledger (never created, or already dropped) also answers `204`, and each committed drop appends a `DROP_INDEX` entry to the ledger log. A mistyped canonical id is therefore not reported; read the index with `GET /v3/{ledgerName}/indexes/{canonicalId}` first when the caller must know that it exists. `404` means that the ledger does not exist. operationId: dropIndex tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/LedgerName' - name: canonicalId in: path required: true schema: type: string description: Canonical form of the target IndexID. - name: Idempotency-Key in: header schema: type: string responses: '204': description: Index removed, or no index with this id was registered on the ledger. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: The ledger does not exist. A missing index does not produce `404`. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '409': $ref: '#/components/responses/Conflict' '500': $ref: '#/components/responses/InternalServerError' '429': $ref: '#/components/responses/ResourceExhausted' '503': $ref: '#/components/responses/ServiceUnavailable' /v3/{ledgerName}/indexes/{canonicalId}/status: get: summary: Get the per-replica status of a single index description: | Returns the `IndexEntry` for a single index — the registry entry joined with the backfill cursor and the per-replica IndexVersionState (current + pending version). Use this to poll for backfill completion after a `POST /v3/{ledgerName}/indexes`. Requires `ledger:LedgerRead` scope. operationId: getIndexEntryStatus tags: - Indexes security: - BearerAuth: [] - {} parameters: - $ref: '#/components/parameters/Consistency' - $ref: '#/components/parameters/LedgerName' - name: canonicalId in: path required: true schema: type: string description: Canonical form of the target IndexID. responses: '200': description: Index entry retrieved successfully. content: application/json: schema: type: object required: - data properties: data: type: object additionalProperties: true description: IndexEntry (protobuf JSON representation) '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '500': $ref: '#/components/responses/InternalServerError' components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT description: > JWT token issued by a trusted OIDC provider. Required when the server is started with `--auth-enabled`. Scopes: `ledger:read` (read operations), `ledger:write` (write operations), `ledger:admin` (cluster operations). parameters: PageSize: name: pageSize in: query required: false schema: type: integer format: uint32 minimum: 0 default: 100 description: Maximum number of items per page. 0 or absent means 100; values above 1000 are clamped to 1000. PageCursor: name: cursor in: query required: false schema: $ref: '#/components/schemas/PageToken' description: | Page token from a previous response's `next` or `previous` field (see the `PageToken` schema). Omit for the first page. Pass the same `reverse` and `filter` on every page of a walk. BigIntAsString: name: Formance-Bigint-As-String in: header required: false description: | Render monetary amounts (postings, volume input/output and balances) as canonical decimal strings. Case-insensitive true, yes, y and 1 enable this option, matching Ledger v2. Whitespace is not trimmed. Omission and every other value retain JSON number tokens. This affects only this response, including nested transaction/log/cursor and bulk results. schema: type: string example: 'true' LedgerName: name: ledgerName in: path required: true schema: type: string description: Name of the ledger TransactionId: name: transactionId in: path required: true schema: type: integer format: int64 description: Transaction ID AccountAddress: name: address in: path required: true schema: type: string description: Account address MetadataKey: name: key in: path required: true schema: type: string example: formance.com/reviewed description: | Raw metadata key, for example formance.com/reviewed. SDK callers pass the raw key and let the SDK encode it. Direct HTTP clients URL-encode the key as one path segment, encoding slashes as %2F. Decoded exactly once; percent characters remaining after decoding, including double-encoded slashes, are invalid metadata keys and are rejected with HTTP 400. TargetType: name: targetType in: path required: true schema: type: string enum: - account - transaction - ledger description: Target type (account, transaction, or ledger) QueryName: name: queryName in: path required: true schema: type: string description: Prepared query name TypeName: name: typeName in: path required: true schema: type: string description: Account type name IdempotencyKey: name: Idempotency-Key in: header required: false schema: type: string maxLength: 256 description: Idempotency key for the request Consistency: name: X-Consistency in: header required: false schema: type: string enum: [linearizable, stale] default: linearizable description: | Read consistency. `linearizable` (the default) runs a Raft ReadIndex barrier and waits for the receiving node to apply up to it. `stale` serves the read from the receiving node's own store, with no barrier and no forwarding to the leader, so the answer may lag the leader. Matching ignores case and surrounding whitespace. An unknown value, or a repeated or comma-joined header, returns `400 INVALID_REQUEST` on every `/v3` route, writes included; a valid value has no effect on writes. The gRPC equivalent is the `x-consistency` request metadata. QueryProfile: name: X-Query-Profile in: header required: false schema: type: string description: | Set to any non-empty value to receive the query profile in the `X-Query-Profile-Result` response header. The profile reports server-side request timing (how long the server spent handling the request, broken down into prepare / execute / read-barrier / deliver phases) plus the query execution plan. Use it to tell a slow network from a slow server: `serverDurationUs` is the consumer-independent server cost, and it excludes both the caller-requested read barrier and response delivery. Supported on the transactions list, accounts list, aggregated volumes and prepared-query execution endpoints. The equivalent gRPC opt-in is the `x-query-profile` request metadata, answered in the `x-query-profile-result-bin` trailer; `serverDurationUs` has the same definition on both surfaces, so the two are directly comparable. ListFilter: name: filter in: query required: false schema: type: string description: | A filter, accepted in EITHER of two interchangeable representations that parse to the same filter and are validated against the same per-target rules: - **Textual** — the human-readable filter grammar, e.g. `metadata[status] == "active"`, `address ^= "users:"`, `metadata[a] == "x" and metadata[b] == "y"`. Passed verbatim as the query-parameter value (URL-encoded). - **Structured** — the JSON QueryFilter DSL (see the `QueryFilter` schema: `$and`/`$or`/`$not` + `$match`/`$gt`/`$exists`/…). Passed by URL-encoding the JSON object as the query-parameter value. A condition that is not valid on the endpoint's target (e.g. a transaction-only condition on the accounts list) is rejected with 400. This generic filter is AND-combined with any convenience parameters the endpoint also exposes (e.g. the transactions `startDate`/`endDate` timestamp range). Selections that used to have dedicated aliases are expressed through this filter: an account address prefix via `filter=address ^= "users:"`, a transaction reference via `filter={"$match":{"reference":"..."}}` (URL-encoded). Date fields accept either an RFC3339 timestamp or raw Unix microseconds, in both representations: on transactions `timestamp` / `insertedAt` / `revertedAt` (e.g. textual `filter=timestamp >= "2023-11-14T22:13:20Z"` or structured `filter={"$gte":{"timestamp":"2023-11-14T22:13:20Z"}}`), and on logs `date` (e.g. `filter=date >= "2023-11-14T22:13:20Z"`). An RFC3339 value before the Unix epoch (1970-01-01) is rejected with 400. Note: bare audit fields (`outcome`, `ledger`, `seq`, `proposal_id`, `timestamp`, `log_seq`, `caller_subject`, `order_type`) have no structured JSON form and must be passed in the textual representation. headers: QueryProfileResult: description: | Query profile for this request, returned only when the request carried the `X-Query-Profile` header. The value is the base64 (standard alphabet) encoding of a serialized `QueryProfile` protobuf message (`misc/proto/bucket.proto`). Key durations, all in microseconds: - `serverDurationUs` — consumer-independent server cost: request entry to response-ready, excluding the read barrier and response delivery. Cannot be moved by a slow client. Over HTTP, request entry is the router chain just before authentication; over gRPC it is the handler's first statement, because grpc-go unmarshals the request before dispatching. It does NOT include row serialization. - `prepareDurationUs` — authentication, query/body decoding, validation and filter compilation. - `executeDurationUs` — query execution (contains `indexDurationUs` + `enrichmentDurationUs`). - `barrierDurationUs` — time blocked on caller-requested read consistency waits. Excluded from `serverDurationUs`. Measures LOCAL waits only, and counts one that fails or is superseded: see `forwarded`. - `deliverDurationUs` — response serialization and transport hand-off. Excluded from `serverDurationUs`. Always 0 over HTTP: this header must be flushed before the response body, so the body write is out of reach. It is populated for gRPC server streams. - `firstRowDurationUs` — always 0 over HTTP (the response is buffered); populated for gRPC server streams. - `forwarded` — true when another node served the read. Its barrier and execution are then folded into `executeDurationUs`, so the breakdown describes the local hop only. `barrierDurationUs` then covers the local waits only: 0 means none happened (not "no barrier was needed"), non-zero means a `ReadIndex` attempt failed and caused the forward. Do not infer the remote node's health from it. For a latency objective, pick a total and state which: `serverDurationUs` is client-independent but omits serialization, while `serverDurationUs + deliverDurationUs` is the complete server-side cost but absorbs consumer back-pressure on a gRPC stream. Neither is unbiased on a streaming read. schema: type: string format: byte responses: ResourceExhausted: description: >- Resource exhausted. Write admission can reject with `WRITES_BLOCKED_DISK_FULL` while disk pressure blocks writes; `SEQUENCE_EXHAUSTED` means an authoritative identifier allocator cannot allocate another identifier and is permanent for that allocator. Inspect `errorCode` before deciding whether to retry. No retry interval is supplied, and retrying cannot resolve sequence exhaustion. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' ServiceUnavailable: description: >- Service unavailable — the server cannot serve the request right now but an immediate retry can succeed. The `errorCode` field discriminates the cause: `NO_LEADER` (no elected Raft leader), `CACHE_HORIZON_EXCEEDED` (admission snapshot too old, retry against a fresh one), `UNAVAILABLE` (an internal forwarded stream was torn down mid-transfer), or the reason of any domain error of the unavailable kind (e.g. `INDEX_BUILDING`). headers: Retry-After: description: Number of seconds to wait before retrying the request schema: type: integer format: int32 minimum: 1 example: 1 content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' BadRequest: description: Bad request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' NotFound: description: Not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' Unauthorized: description: Authentication required (missing or invalid JWT token) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' text/plain: schema: type: string Forbidden: description: Insufficient permissions (missing required scope) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' text/plain: schema: type: string InternalServerError: description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' Conflict: description: Conflict (e.g. idempotency key conflict, ledger deleted) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' MethodNotAllowed: description: Method not allowed content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' schemas: PageToken: type: string description: | Page token of a paged list. Clients normally pass back the `next` or `previous` value of a previous response verbatim; building one by hand is supported. A token is base64url (unpadded, RFC 4648 §5) of the JSON object `{"key": , "back": }`. Both fields are omitted when empty, and unknown fields are rejected. `key` is a position in the endpoint's textual form: - transactions: decimal transaction id - logs: decimal ledger-local log id - audit entries: decimal audit sequence - accounts: address - ledgers and numscripts: name - signing keys: key id - prepared queries: decimal id for TRANSACTIONS and LOGS targets, address for ACCOUNTS - index inspection: base64url of the encoded metadata value Both directions exclude the key and return rows in the requested order (`reverse` included): - `{"key": K}` serves the rows strictly after K; - `{"key": K, "back": true}` serves the page that ends strictly before K; - `{"back": true}` serves the last page; - an absent or empty token, or `e30` (`{}`), serves the first page. On a forward page, `next` is set when a further row follows the page, and `previous` whenever the request carried a key. On a back page, `previous` is set when a further row precedes the page, and `next` whenever the request carried a key. A first page therefore has no `previous`, and the last page requested with `{"back": true}` has no `next`. A malformed token, or a key that is not a valid position for the endpoint, is rejected with 400 `INVALID_REQUEST`. UnsignedMonetaryAmount: description: | Exact unsigned integer encoded as a JSON number by default, or a canonical decimal string when Formance-Bigint-As-String is enabled. JavaScript consumers should enable the header to avoid number rounding. oneOf: - type: integer format: bigint minimum: 0 - type: string pattern: '^(0|[1-9][0-9]*)$' SignedMonetaryAmount: description: | Exact signed integer encoded as a JSON number by default, or a canonical decimal string when Formance-Bigint-As-String is enabled. oneOf: - type: integer format: bigint - type: string pattern: '^(0|-?[1-9][0-9]*)$' PostingAmount: description: | Unsigned amount from 0 through 2^256-1. Requests accept JSON integer tokens or canonical decimal strings independently of the response header; the server enforces the bound for both forms. Responses use numbers by default and strings with Formance-Bigint-As-String enabled. oneOf: - type: integer format: bigint minimum: 0 - type: string pattern: '^(0|[1-9][0-9]*)$' SinkConfig: type: object additionalProperties: false description: | Named sink configuration from common.SinkConfig, in protobuf JSON form. Property names below use canonical lowerCamelCase; the decoder also accepts protobuf snake_case names. Exactly one sink type is required. Connection settings and credentials are stored without business validation. Defaults described below are applied by the event publisher. required: [name] oneOf: - required: [nats] - required: [clickhouse] - required: [kafka] - required: [http] - required: [databricks] properties: name: type: string minLength: 1 description: Stable identifier for per-sink cursor and status keys nats: $ref: '#/components/schemas/NatsSinkConfig' clickhouse: $ref: '#/components/schemas/ClickHouseSinkConfig' kafka: $ref: '#/components/schemas/KafkaSinkConfig' http: $ref: '#/components/schemas/HttpSinkConfig' databricks: $ref: '#/components/schemas/DatabricksSinkConfig' format: type: string description: Event encoding, json or protobuf; defaults to json. Not validated at admission. batchSize: type: integer format: int32 maximum: 100000 description: Maximum events per batch; non-positive values use the publisher default of 64 batchDelayMs: description: Maximum delay before flush in milliseconds; non-positive values use 10. Protobuf int64 JSON uses a decimal string; numeric input is also accepted. oneOf: - type: string pattern: '^-?[0-9]+$' - type: integer format: int64 eventTypes: type: array description: Event types to publish; omitted or empty means all events items: $ref: '#/components/schemas/EventType' controllerId: type: string description: Opaque owner identity (EventSink CR UID); empty for manually managed sinks EventType: description: Protobuf EventType; canonical JSON uses enum names, and numeric enum values are also accepted oneOf: - type: string enum: - EVENT_TYPE_UNSPECIFIED - COMMITTED_TRANSACTION - REVERTED_TRANSACTION - SAVED_METADATA - DELETED_METADATA - CREATED_LEDGER - DELETED_LEDGER - SKIPPED_ORDER - type: integer format: int32 description: Protobuf enum numeric value (unknown numeric values are accepted by the decoder) NatsSinkConfig: type: object additionalProperties: false description: NATS JetStream connection settings properties: url: type: string description: NATS server URL topic: type: string description: NATS topic ClickHouseSinkConfig: type: object additionalProperties: false description: ClickHouse connection settings properties: dsn: type: string description: ClickHouse connection DSN, which may include credentials example: clickhouse://user:pass@host:9000/db table: type: string description: Table name; defaults to ledger_events KafkaSinkConfig: type: object additionalProperties: false description: Apache Kafka connection settings properties: brokers: type: array description: Kafka broker addresses items: type: string example: [localhost:9092] topic: type: string description: Kafka topic name tls: type: boolean description: Enable TLS saslMechanism: type: string description: SASL mechanism (empty, PLAIN, SCRAM-SHA-256 or SCRAM-SHA-512); not validated at admission saslUsername: type: string description: SASL username saslPassword: type: string description: SASL password HttpSinkConfig: type: object additionalProperties: false description: HTTP webhook connection settings properties: endpoint: type: string description: Target webhook URL example: https://example.com/webhooks/ledger secret: type: string description: Optional HMAC-SHA256 secret for the X-Webhook-Signature header DatabricksSinkConfig: type: object additionalProperties: false description: | Databricks SQL Warehouse connection settings. token and oauthM2m are protobuf auth oneof members and cannot both be supplied. Business admission does not require either member or validate connection details. not: required: [token, oauthM2m] properties: serverHostname: type: string description: Databricks server hostname example: adb-123456.azuredatabricks.net httpPath: type: string description: SQL Warehouse HTTP path example: /sql/1.0/warehouses/abc123 catalog: type: string description: Unity Catalog name example: main schema: type: string description: Schema name example: default table: type: string description: Table name; defaults to ledger_events port: type: integer format: int32 description: Port number; defaults to 443 token: type: string description: Personal Access Token (PAT); alternative to oauthM2m oauthM2m: $ref: '#/components/schemas/DatabricksOAuthM2M' DatabricksOAuthM2M: type: object additionalProperties: false description: OAuth M2M client credentials for a Databricks service principal properties: clientId: type: string description: Service principal client ID clientSecret: type: string description: Service principal client secret SystemLog: type: object description: | System log entry, shared by single-log responses, ledger-log lists, prepared-query logData, and JSON events. The system payload keeps its named variant (apply, createLedger, deleteLedger, etc.). A ledger log inside payload.apply.log uses the flat LedgerLog contract. Non-apply system payload variants are not exhaustively described here. properties: sequence: type: integer format: uint64 minimum: 0 payload: type: object description: | Named system payload variants are preserved as supplied, including nested fields and future sibling variants. Only apply is typed here; other variants remain open-ended (EN-2781). additionalProperties: true properties: apply: type: object properties: ledgerName: type: string log: $ref: '#/components/schemas/LedgerLog' responseSignature: type: object additionalProperties: true LedgerLog: type: object description: | Ledger-local log. The type selects the direct object in data, following the v2 type/data structure; data has no variant-name wrapper. New v3 operations have distinct type values. Metadata remains typed, volumes retain colors, and reversals contain the original transaction ID and the reversing transaction rather than the full original transaction. This JSON projection is not an audit replay or backup format. required: - type - data properties: type: type: string enum: - NEW_TRANSACTION - REVERTED_TRANSACTION - SET_METADATA - DELETE_METADATA - SET_METADATA_FIELD_TYPE - REMOVED_METADATA_FIELD_TYPE - ORDER_SKIPPED - FILL_GAP - CREATE_INDEX - DROP_INDEX - ADDED_ACCOUNT_TYPE - REMOVED_ACCOUNT_TYPE - UPDATED_DEFAULT_ENFORCEMENT_MODE data: type: object additionalProperties: true description: | Direct operation payload selected by type. NEW_TRANSACTION contains transaction and optional accountMetadata. REVERTED_TRANSACTION contains revertedTransactionId and revertTransaction. SET_METADATA and DELETE_METADATA contain targetType (ACCOUNT or TRANSACTION) and targetId: an account-address string or an unsigned 64-bit transaction integer, including zero. SET_METADATA also contains metadata; DELETE_METADATA contains key. ORDER_SKIPPED contains reason and optional context. Other types carry the fields of their corresponding operation directly. FILL_GAP contains originalId, a uint64 encoded as a decimal JSON string by protobuf JSON. Transaction IDs, revertedTransactionId and transaction targetId are JSON numbers; consumers must preserve full integer precision. Metadata integers are JSON numbers and null-valued keys are preserved. date: type: string format: date-time id: type: integer format: uint64 minimum: 0 description: Ledger-local log ID; omitted when zero. example: type: SET_METADATA data: targetType: ACCOUNT targetId: users:alice metadata: category: premium MetadataValue: description: >- A typed metadata value (string, integer, boolean, or null). Integer numbers are decoded exactly, including int64 bounds and values beyond 2^53. Integral decimal and exponent spellings are accepted; fractions and out-of-range values are rejected. String values must not contain NUL bytes. A value is limited to 16384 bytes by default; the effective ceiling comes from the cluster policy (`--metadata-max-value-bytes`). Exceeding it returns 400 with reason `METADATA_LIMIT_EXCEEDED`. nullable: true oneOf: - type: string pattern: '^[^\u0000]*$' description: Metadata string value without NUL bytes - type: integer minimum: -9223372036854775808 maximum: 18446744073709551615 description: Negative values fit int64; nonnegative values fit uint64. - type: boolean MetadataFieldTypeCommand: type: object description: Declares the type of a metadata field, seeding a ledger's initial metadata schema. required: - targetType - key - type properties: targetType: type: string enum: [account, transaction, ledger] description: Which entity the metadata field applies to. key: type: string description: Metadata key. example: color type: type: string enum: [string, int64, bool, uint64, int8, int16, int32, uint8, uint16, uint32, datetime] description: Declared metadata value type. example: string CreateLedgerRequest: type: object properties: metadata: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: >- Initial typed metadata, persisted atomically with creation in NORMAL and MIRROR modes. Creation requires ledger:LedgerWrite, including initial metadata; later metadata saves require ledger:MetadataWrite. JSON null entries are omitted. Schema declarations govern indexing and queries, not write-time value coercion. Cluster policy defaults allow 128 entries per entity, 256 bytes per key, 16384 bytes per value, 65536 bytes per entity, and 1048576 bytes per request. Effective ceilings are configurable through the replicated cluster policy. mode: type: string enum: - NORMAL - MIRROR default: NORMAL description: Ledger mode. MIRROR creates a read-only ledger that syncs from an external v2 source. Values are case-sensitive; any other value is rejected with 400 INVALID_REQUEST. mirrorSource: $ref: '#/components/schemas/MirrorSourceConfig' defaultEnforcementMode: type: string enum: - STRICT - AUDIT description: Default chart-of-accounts enforcement for accounts that match no account type. initialSchema: type: array description: Metadata field type declarations to seed at creation time. items: $ref: '#/components/schemas/MetadataFieldTypeCommand' accountTypes: type: object description: Initial account types (name -> account type definition). additionalProperties: $ref: '#/components/schemas/AddAccountTypeRequest' example: user-checking: name: user-checking pattern: 'users:{id}:checking' persistence: EPHEMERAL segmentTypes: id: type: uuid CreateLedgerResponse: type: object required: - data properties: data: $ref: '#/components/schemas/LedgerInfo' CreateIndexResponse: type: object required: - data properties: data: type: object required: - id properties: id: type: string description: | Canonical form of the created IndexID (round-trip normalized), e.g. `metadata:TARGET_TYPE_ACCOUNT:color` or `tx_builtin:TX_BUILTIN_INDEX_TIMESTAMP`. example: metadata:TARGET_TYPE_ACCOUNT:color GetLedgerResponse: type: object required: - data properties: data: $ref: '#/components/schemas/LedgerInfo' ListAllLedgersResponse: type: object required: - data - hasMore properties: data: type: array items: $ref: '#/components/schemas/LedgerInfo' description: One page of ledgers, in the requested name order next: $ref: '#/components/schemas/PageToken' previous: $ref: '#/components/schemas/PageToken' hasMore: type: boolean description: True when a following page exists; set iff `next` is. LedgerInfo: type: object required: [name, mode, defaultEnforcementMode] properties: name: type: string description: Name of the ledger createdAt: type: string format: date-time deletedAt: type: string format: date-time description: Soft deletion timestamp; omitted for active ledgers metadata: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: Enriched typed ledger metadata metadataSchema: $ref: '#/components/schemas/LedgerMetadataSchema' mode: type: string enum: [NORMAL, MIRROR] description: Ledger mode, including the default NORMAL value mirrorSource: $ref: '#/components/schemas/MirrorSourceRead' mirrorSyncProgress: $ref: '#/components/schemas/MirrorSyncProgress' accountTypes: type: object additionalProperties: $ref: '#/components/schemas/AccountTypeInfo' defaultEnforcementMode: type: string enum: [STRICT, AUDIT] description: Default enforcement for unmatched accounts; defaults to STRICT LedgerMetadataSchema: type: object properties: accountFields: type: object additionalProperties: $ref: '#/components/schemas/LedgerMetadataFieldSchema' transactionFields: type: object additionalProperties: $ref: '#/components/schemas/LedgerMetadataFieldSchema' ledgerFields: type: object additionalProperties: $ref: '#/components/schemas/LedgerMetadataFieldSchema' LedgerMetadataFieldSchema: type: object required: [type] properties: type: type: string enum: [string, int64, bool, uint64, int8, int16, int32, uint8, uint16, uint32, datetime] description: Declared metadata type, using the same tokens as schema creation MirrorSyncProgress: type: object description: Sync progress for MIRROR ledgers (populated at read time) required: - state - cursor - sourceLogCount - remainingLogs properties: state: type: string enum: - SYNCING - FOLLOWING description: Current sync state (SYNCING = catching up, FOLLOWING = up to date) cursor: type: string format: bigint pattern: '^(0|[1-9][0-9]*)$' description: Last ingested v2 log ID sourceLogCount: type: string format: bigint pattern: '^(0|[1-9][0-9]*)$' description: Latest known log ID in the v2 source remainingLogs: type: string format: bigint pattern: '^(0|[1-9][0-9]*)$' description: Number of remaining logs to sync (sourceLogCount - cursor) error: $ref: '#/components/schemas/MirrorSyncError' MirrorSyncError: type: object description: Most recent mirror sync error (null if healthy) properties: message: type: string description: Error message occurredAt: type: string format: date-time description: When the error occurred CreateTransactionRequest: type: object description: | A transaction must declare exactly one content source: explicit `postings`, an inline `script`, or a `scriptReference`. The `postings` array cannot be combined with `script` or `scriptReference`. Idempotency is controlled exclusively via the `Idempotency-Key` HTTP header — there is no body-level key. properties: accountMetadata: type: object additionalProperties: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: >- Metadata for accounts involved in the transaction (supports typed values). Each account's map is bounded independently. Cluster policy defaults allow 128 entries per entity, 256 bytes per key, 16384 bytes per value, 65536 bytes per entity, and 1048576 bytes per request. Effective ceilings are configurable through the replicated cluster policy. timestamp: type: string format: date-time description: Transaction timestamp (ISO 8601 format). If not provided, current time is used. metadata: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: >- Transaction metadata (supports typed values). Cluster policy defaults allow 128 entries per entity, 256 bytes per key, 16384 bytes per value, 65536 bytes per entity, and 1048576 bytes per request. Effective ceilings are configurable through the replicated cluster policy. reference: type: string description: Transaction reference postings: type: array items: $ref: '#/components/schemas/PostingRequest' description: List of postings for the transaction. Mutually exclusive with `script` and `scriptReference`. script: $ref: '#/components/schemas/Script' description: Inline Numscript to execute. Mutually exclusive with `postings` and `scriptReference`. scriptReference: $ref: '#/components/schemas/ScriptReference' description: Reference to a numscript saved in the ledger's library. Mutually exclusive with `postings` and `script`. force: type: boolean default: false description: Skip the balance check, so the transaction commits even when a source account has insufficient funds. PostingRequest: type: object required: - source - destination - amount - asset properties: source: type: string description: Source account address destination: type: string description: Destination account address amount: $ref: '#/components/schemas/PostingAmount' asset: type: string description: Asset identifier color: type: string pattern: '^[A-Z]*$' maxLength: 32 description: | Optional segregation key for "color of money". The empty string (or omitted field) means the uncolored bucket. Two postings on the same (account, asset) but different colors operate on strictly isolated balances. Color is constrained to `^[A-Z]*$`, capped at 32 characters, and is immutable once carried by funds. Script: type: object required: - plain properties: plain: type: string description: The numscript source code vars: type: object additionalProperties: type: string description: Variables to pass to the script ScriptReference: type: object required: - name - version properties: name: type: string description: Name of the numscript in the ledger's library version: type: string description: | Version selector: the literal `latest` or an exact full semver (`1.2.3`). Partial selectors such as `1` or `1.2` are read-only and rejected here. vars: type: object additionalProperties: type: string description: Variables to pass to the referenced script BulkElement: type: object required: - action - data properties: action: type: string enum: - CREATE_TRANSACTION - ADD_METADATA - REVERT_TRANSACTION - DELETE_METADATA description: | The type of operation to perform. The REST bulk endpoint accepts these four actions only; account-type actions (`ADD_ACCOUNT_TYPE` / `REMOVE_ACCOUNT_TYPE`) are gRPC-only and are rejected here. ik: type: string maxLength: 256 description: Idempotency key for this operation data: oneOf: - $ref: '#/components/schemas/CreateTransactionRequest' - $ref: '#/components/schemas/AddMetadataRequest' - $ref: '#/components/schemas/RevertTransactionRequest' - $ref: '#/components/schemas/DeleteMetadataRequest' description: Operation-specific data skippableReasons: type: array items: type: string enum: - TRANSACTION_REFERENCE_CONFLICT - TRANSACTION_ALREADY_REVERTED - METADATA_NOT_FOUND description: | Opt-in continue-on-failure list for this entry. When the FSM would otherwise reject the underlying order with a business error whose typed reason matches one of these entries, the order is recorded as an `OrderSkippedLog` (no state mutation) and the bulk result's `data` surfaces the skip context. Reasons outside the per-action business whitelist (structural / internal reasons) are rejected at admission. Accepted reasons per action on this REST endpoint: - `CREATE_TRANSACTION` → `TRANSACTION_REFERENCE_CONFLICT` - `REVERT_TRANSACTION` → `TRANSACTION_ALREADY_REVERTED` - `DELETE_METADATA` → `METADATA_NOT_FOUND` The FSM also supports skipping `ADD_ACCOUNT_TYPE` (`ACCOUNT_TYPE_ALREADY_EXISTS`) and `REMOVE_ACCOUNT_TYPE` (`ACCOUNT_TYPE_NOT_FOUND`), but those actions are **gRPC-only**: the REST bulk endpoint does not accept account-type actions (see the `action` enum above), so their reasons are not offered here. Empty (default) preserves the historical fail-on-error behaviour. AddMetadataRequest: type: object required: - targetType - targetId - metadata properties: targetType: type: string enum: - ACCOUNT - TRANSACTION description: Type of target (account or transaction) targetId: oneOf: - type: string - type: integer description: | ID of the target (account address or transaction ID). Required. metadata: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: >- Metadata to add (supports typed values). Cluster policy defaults allow 128 entries per entity, 256 bytes per key, 16384 bytes per value, 65536 bytes per entity, and 1048576 bytes per request. Effective ceilings are configurable through the replicated cluster policy. RevertTransactionRequest: type: object required: - id properties: id: type: integer format: int64 description: Transaction ID to revert. Required. force: type: boolean default: false description: Force revert even if accounts don't have sufficient funds atEffectiveDate: type: boolean default: false description: Set the timestamp of the reverted transaction to the original transaction timestamp metadata: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: >- Metadata for the revert transaction (supports typed values). Cluster policy defaults allow 128 entries per entity, 256 bytes per key, 16384 bytes per value, 65536 bytes per entity, and 1048576 bytes per request. Effective ceilings are configurable through the replicated cluster policy. RevertTransactionRequestBody: type: object properties: force: type: boolean default: false description: Force revert even if accounts don't have sufficient funds atEffectiveDate: type: boolean default: false description: Set the timestamp of the reverted transaction to the original transaction timestamp metadata: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: >- Metadata for the revert transaction (supports typed values). Cluster policy defaults allow 128 entries per entity, 256 bytes per key, 16384 bytes per value, 65536 bytes per entity, and 1048576 bytes per request. Effective ceilings are configurable through the replicated cluster policy. DeleteMetadataRequest: type: object required: - targetType - targetId - key properties: targetType: type: string enum: - ACCOUNT - TRANSACTION description: Type of target (account or transaction) targetId: oneOf: - type: string - type: integer description: | ID of the target (account address or transaction ID). Required. key: type: string description: Metadata key to delete BulkResponse: type: object properties: data: type: array items: $ref: '#/components/schemas/BulkResult' errorCode: type: string errorMessage: type: string BulkErrorResponse: description: | Bulk processing returns per-element outcomes in data, including any preceding successes and subsequent aborted elements. Failures before processing and panic recovery can return only errorCode/errorMessage. These object shapes overlap: use a non-exclusive union and preserve the bulk fields when decoding a processing failure. anyOf: - $ref: '#/components/schemas/BulkResponse' - $ref: '#/components/schemas/ErrorResponse' BulkResult: type: object properties: responseType: type: string description: Type of response (action name or ERROR) logID: type: integer format: int64 description: Log ID of the applied operation (0 on error) errorCode: type: string description: Error code (present only on error) errorDescription: type: string description: | Client-facing error description (present only on error). Unknown internal failures carry a generic message with a correlation ID; internal index/coverage details are omitted. Machine-readable error codes and the bulk response shape are preserved. data: description: | Operation result data. Shape depends on the originating action: - `CREATE_TRANSACTION` success: a `TransactionResponse` — the created Transaction object. - Any skippable action skip (when the item opted into `skippableReasons` and the FSM matched one): an `OrderSkippedResponse` with `skipped: true`, `reason`, and reason-specific `context`. Emitted for every REST-supported skippable action — CREATE_TRANSACTION, REVERT_TRANSACTION, DELETE_METADATA — not just create. - Other successful non-create actions: `null`. Branch on `OrderSkippedResponse.skipped` to distinguish a skip from a successful transaction. nullable: true oneOf: - $ref: '#/components/schemas/TransactionResponse' - $ref: '#/components/schemas/OrderSkippedResponse' CreateTransactionResponse: type: object required: - data properties: data: type: object properties: transaction: $ref: '#/components/schemas/TransactionResponse' accountMetadata: type: object additionalProperties: type: object additionalProperties: true description: Metadata for accounts involved in the transaction OrderSkippedResponse: type: object description: | Shape returned in the bulk result's `data` field when a bulk entry opted into `skippableReasons` and the FSM matched one of the listed reasons (no state mutation occurred). `skipped` is always `true` on this shape — branch on it to distinguish from the normal Transaction data. required: - skipped - reason - code properties: skipped: type: boolean description: Always true on this shape. reason: type: string description: Typed reason that matched the skip (e.g. `TRANSACTION_REFERENCE_CONFLICT`). Same identifier the gRPC ErrorInfo.reason and the REST error responses use. code: type: string description: Stable subcode for the skipped failure. facts: type: object additionalProperties: type: string description: | Validated, reason-specific correlators. For `TRANSACTION_REFERENCE_CONFLICT`, contains `reference` and `existingTransactionId`. GetTransactionResponse: type: object required: - data properties: data: type: object required: - transaction properties: transaction: $ref: '#/components/schemas/TransactionResponse' GetAccountResponse: type: object required: - data properties: data: $ref: '#/components/schemas/Account' GetLedgerStatsResponse: type: object required: - data properties: data: $ref: '#/components/schemas/LedgerStats' LedgerStats: type: object required: - transactionCount - volumeCount - referenceCount - postingCount - logCount - ephemeralEvictedCount - transientUsedCount - revertCount - numscriptExecutionCount properties: transactionCount: type: integer format: uint64 minimum: 0 description: Number of transactions in the ledger volumeCount: type: integer format: uint64 minimum: 0 description: Number of persisted (account, asset, color) volume rows referenceCount: type: integer format: uint64 minimum: 0 description: Number of transaction references registered in the ledger postingCount: type: integer format: uint64 minimum: 0 description: Total number of postings across all transactions logCount: type: integer format: uint64 minimum: 0 description: Number of log entries in the ledger ephemeralEvictedCount: type: integer format: uint64 minimum: 0 description: Number of ephemeral/draining volumes evicted from storage at commit transientUsedCount: type: integer format: uint64 minimum: 0 description: Number of transient volumes used across proposals revertCount: type: integer format: uint64 minimum: 0 description: Number of reverted transactions in the ledger numscriptExecutionCount: type: integer format: uint64 minimum: 0 description: Number of Numscript executions in the ledger Account: type: object required: - address properties: address: type: string description: Account address metadata: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' description: Account metadata (typed values) volumes: type: array items: $ref: '#/components/schemas/AccountVolume' description: | Account volumes listed per (asset, color). Sorted by (asset, color) ascending for stable serialization. The empty color is the uncolored bucket; colored buckets are strictly isolated. Use the `collapseColors=true` query parameter on GET /accounts to sum every colored bucket of the same asset into a single uncolored entry. AccountVolume: type: object required: - asset - color - volumes properties: asset: type: string description: Asset identifier (e.g. "USD/2") color: type: string pattern: '^[A-Z]*$' maxLength: 32 description: Color of the bucket. Empty string is the uncolored bucket. volumes: $ref: '#/components/schemas/VolumesWithBalance' VolumesWithBalance: type: object required: - input - output - balance properties: input: $ref: '#/components/schemas/UnsignedMonetaryAmount' output: $ref: '#/components/schemas/UnsignedMonetaryAmount' balance: $ref: '#/components/schemas/SignedMonetaryAmount' AggregateVolumesResponse: type: object required: - data properties: data: $ref: '#/components/schemas/AggregateVolumesData' AggregateVolumesData: type: object required: - volumes properties: volumes: type: array items: $ref: '#/components/schemas/AggregatedVolume' description: Flat aggregated volumes per asset groups: type: array items: $ref: '#/components/schemas/GroupedAggregateResult' description: Per-prefix aggregated volumes (present when groupByPrefixes is set) AggregatedVolume: type: object description: | Per-asset aggregated volume as emitted by `GET /v3/{ledgerName}/volumes`. Prepared-query `AGGREGATE_VOLUMES` responses (under the `aggregateResult` envelope of `ExecutePreparedQueryResponse`) use this exact shape: header-negotiated monetary amounts, a computed `balance`, and `color` always present. required: - asset - color - input - output - balance properties: asset: type: string description: Asset identifier (e.g. "USD/2") color: type: string pattern: '^[A-Z]*$' maxLength: 32 description: | Color of the aggregated bucket. By default the response contains one AggregatedVolume per (asset, color) tuple. With `collapseColors=true`, every colored bucket of the same (asset, precision) is summed and the resulting entry carries color = "". input: $ref: '#/components/schemas/UnsignedMonetaryAmount' output: $ref: '#/components/schemas/UnsignedMonetaryAmount' balance: $ref: '#/components/schemas/SignedMonetaryAmount' GroupedAggregateResult: type: object required: - prefix - volumes properties: prefix: type: string description: Account prefix this group matches volumes: type: array items: $ref: '#/components/schemas/AggregatedVolume' description: Aggregated volumes for accounts matching this prefix TransactionResponse: type: object # required <=> always emitted. postings and metadata are emitted # unconditionally as [] / {} (see Transaction.MarshalJSON), reverted is a # non-pointer bool, and id is emitted even when 0. Anything not listed # here carries omitempty and is legitimately absent. required: - id - postings - metadata - reverted properties: postings: type: array items: $ref: '#/components/schemas/PostingResponse' metadata: type: object additionalProperties: $ref: '#/components/schemas/MetadataValue' timestamp: type: string format: date-time description: Transaction timestamp (ISO 8601 format) reference: type: string id: type: integer format: int64 description: Transaction ID (assigned by the system) reverted: type: boolean description: Whether this transaction has been reverted insertedAt: type: string format: date-time description: When the transaction was inserted into the ledger updatedAt: type: string format: date-time description: Last update timestamp revertedAt: type: string format: date-time description: When the transaction was reverted (null if not reverted) nullable: true revertedByTransactionId: type: integer format: int64 description: ID of the transaction that reverted this one (absent when not reverted) revertsTransactionId: type: integer format: int64 description: ID of the original transaction this transaction reverts (absent when this is not a revert) postCommitVolumes: $ref: '#/components/schemas/PostCommitVolumes' description: | Post-commit volumes for every (account, asset, color) tuple touched by this transaction, captured at the transaction's sequence. An immutable historical snapshot, present on every transaction; never recomputed from current balances. RevertedTransaction: type: object properties: revertedTransactionId: type: integer format: uint64 description: ID of the original transaction that was reverted revertTransaction: $ref: '#/components/schemas/TransactionResponse' description: The new transaction that reverses the original transaction RevertedTransactionResponse: type: object required: - data properties: data: $ref: '#/components/schemas/RevertedTransaction' PostingResponse: type: object required: - source - destination - amount - asset - color properties: source: type: string destination: type: string amount: $ref: '#/components/schemas/PostingAmount' asset: type: string color: type: string pattern: '^[A-Z]*$' maxLength: 32 description: | Segregation key for "color of money". The empty string means the uncolored bucket. Always present on responses (never omitted); two postings on the same (account, asset) but different colors operate on strictly isolated balances. LedgerClusterStateResponse: type: object required: - data properties: data: type: object required: - state - localNode - innerState properties: state: type: string enum: [Leader, Follower, Candidate, PreCandidate, Unknown] description: Current state of the local node leader: type: integer format: int64 minimum: 0 description: ID of the current leader (0 if no leader) localNode: type: integer format: int64 minimum: 0 description: ID of the local node nodes: type: array items: $ref: '#/components/schemas/NodeInfo' description: List of all nodes in the cluster raftStatus: $ref: '#/components/schemas/RaftStatus' description: Complete Raft status information innerState: $ref: '#/components/schemas/LedgerState' description: State contained in the FSM SystemState: type: object required: - ledgers properties: ledgers: type: object additionalProperties: $ref: '#/components/schemas/LedgerState' description: Map of ledger name to ledger state LedgerState: type: object required: - ledgerInfo - nextLogId - nextTransactionId properties: ledgerInfo: $ref: '#/components/schemas/LedgerInfo' nextLogId: type: integer format: uint64 minimum: 0 description: Next log ID to be assigned nextTransactionId: type: integer format: uint64 minimum: 0 description: Next transaction ID to be assigned NodeInfo: type: object required: - id - address - suffrage properties: id: type: integer format: int64 minimum: 0 description: Node ID address: type: string description: Node address suffrage: type: string enum: [Voter, Nonvoter, Learner] description: Node suffrage (Voter, Nonvoter, or Learner) ClusterState: type: object required: - state - localNode properties: state: type: string description: Current state of the Raft node (Leader, Follower, Candidate, PreCandidate, Unknown) leader: type: integer format: int64 minimum: 0 description: ID of the current leader (0 if no leader) nodes: type: array items: $ref: '#/components/schemas/NodeInfo' description: List of all nodes in the cluster localNode: type: integer format: int64 minimum: 0 description: ID of the local node raftStatus: $ref: '#/components/schemas/RaftStatus' description: Complete Raft status information RaftStatus: type: object required: - state - term - leader - applied - commit - lastIndex - vote properties: state: type: string enum: [Leader, Follower, Candidate, PreCandidate, Unknown] description: Current Raft state term: type: integer format: int64 minimum: 0 description: Current term leader: type: integer format: int64 minimum: 0 description: ID of the current leader (0 if no leader) applied: type: integer format: int64 minimum: 0 description: Index of the last applied entry commit: type: integer format: int64 minimum: 0 description: Index of the last committed entry lastIndex: type: integer format: int64 minimum: 0 description: Index of the last entry in the log vote: type: integer format: int64 minimum: 0 description: ID of the node that received the vote (0 if no vote) progress: type: object additionalProperties: $ref: '#/components/schemas/ProgressInfo' description: Progress information for each node in the cluster ProgressInfo: type: object required: - match - next - state - pendingSnapshot - recentActive - probeSent - isPaused properties: match: type: integer format: int64 minimum: 0 description: Match index - highest log entry known to be replicated to this node next: type: integer format: int64 minimum: 0 description: Next index - index of the next log entry to send to this node state: type: string enum: [Probe, Replicate, Snapshot, Unknown] description: State of the replication (Probe, Replicate, or Snapshot) pendingSnapshot: type: integer format: int64 minimum: 0 description: Index of pending snapshot (0 if none) recentActive: type: boolean description: Whether this node is recently active probeSent: type: boolean description: Whether probe message was sent (paused) isPaused: type: boolean description: Whether this node is paused InspectSummaryResponse: type: object required: - cardinality - entitiesWithKey - entitiesWithNull properties: cardinality: type: integer format: uint64 description: Number of distinct values min: description: Minimum value (null if index is empty) max: description: Maximum value (null if index is empty) entitiesWithKey: type: integer format: uint64 description: Number of entities that have this metadata key set (non-null) entitiesWithNull: type: integer format: uint64 description: Number of entities with a null value for this key InspectDistinctValuesResponse: type: object required: - values - hasMore properties: values: type: array items: {} description: Distinct values in sorted order hasMore: type: boolean description: Whether more values are available; set iff `nextCursor` is nextCursor: $ref: '#/components/schemas/PageToken' previousCursor: $ref: '#/components/schemas/PageToken' InspectFacetsResponse: type: object required: - facets - hasMore properties: facets: type: array items: $ref: '#/components/schemas/InspectFacet' description: Facets sorted by value hasMore: type: boolean description: Whether more facets are available; set iff `nextCursor` is nextCursor: $ref: '#/components/schemas/PageToken' previousCursor: $ref: '#/components/schemas/PageToken' InspectFacet: type: object required: - value - count properties: value: description: The metadata value count: type: integer format: uint64 description: Number of entities with this value MetadataSchemaStatusResponse: type: object required: - data properties: data: type: object required: - accountFields - transactionFields - ledgerFields properties: accountFields: type: object additionalProperties: $ref: '#/components/schemas/MetadataFieldStatus' description: Account metadata field declarations transactionFields: type: object additionalProperties: $ref: '#/components/schemas/MetadataFieldStatus' description: Transaction metadata field declarations ledgerFields: type: object additionalProperties: $ref: '#/components/schemas/MetadataFieldStatus' description: Ledger metadata field declarations MetadataFieldStatus: type: object required: - declaredType properties: declaredType: type: string enum: - string - int64 - bool - uint64 - int8 - int16 - int32 - uint8 - uint16 - uint32 - datetime description: Declared type for this metadata field SetMetadataTypeRequest: type: object required: - type properties: type: type: string enum: - string - int64 - bool - uint64 - int8 - int16 - int32 - uint8 - uint16 - uint32 - datetime description: Metadata type to set for the field PostCommitVolumes: type: object description: | Post-commit volumes, keyed by account address. Each account maps to a flat array of per-(asset, color) volume tuples. The wire is a plain `{"addr": [{asset, color, input, output}]}` map — the proto `volumesByAccount` / `volumes` wrappers are flattened away by `PostCommitVolumes.MarshalJSON`. This replaces the pre-color `{"addr": {"asset": Volumes}}` map shape, which can no longer key a bucket uniquely once a color dimension exists. additionalProperties: type: array items: $ref: '#/components/schemas/VolumeEntry' VolumeEntry: type: object description: | A single flat post-commit volume tuple for one (asset, color) bucket. Input/output are flattened onto the tuple (not nested under a `volumes` key). The empty color is the uncolored bucket and is always emitted. required: - asset - color - input - output properties: asset: type: string color: type: string pattern: '^[A-Z]*$' maxLength: 32 description: Empty string for the uncolored bucket; always emitted. input: $ref: '#/components/schemas/UnsignedMonetaryAmount' output: $ref: '#/components/schemas/UnsignedMonetaryAmount' Volumes: type: object required: - input - output properties: input: $ref: '#/components/schemas/UnsignedMonetaryAmount' output: $ref: '#/components/schemas/UnsignedMonetaryAmount' MirrorSourceRead: type: object description: Detached credential-safe mirror configuration returned by ledger reads required: [ledgerName] oneOf: - required: [http] - required: [postgres] properties: ledgerName: type: string batchSize: type: integer format: int64 minimum: 0 maximum: 4294967295 rewriteRules: type: array items: $ref: '#/components/schemas/MirrorRewriteRuleRead' http: $ref: '#/components/schemas/HttpMirrorSourceRead' postgres: $ref: '#/components/schemas/PostgresMirrorSourceRead' HttpMirrorSourceRead: type: object properties: baseUrl: type: string description: Source URL with userinfo (including passwordless tokens) and query credentials masked oauth2ClientCredentials: $ref: '#/components/schemas/MirrorOAuthRead' MirrorOAuthRead: type: object properties: clientId: type: string clientSecret: type: string enum: ['[redacted]'] description: Presence marker only; reusable secret material is never returned tokenEndpoint: type: string description: OAuth endpoint URL with userinfo (including passwordless tokens) and query credentials masked scopes: type: array items: type: string PostgresMirrorSourceRead: type: object properties: dsn: type: string description: Connection string with password material masked; malformed values are fully redacted awsIamAuth: $ref: '#/components/schemas/MirrorAwsIamAuthRead' MirrorAwsIamAuthRead: type: object properties: region: type: string assumeRoleArn: type: string MirrorSourceConfig: type: object description: Configuration for the mirror source (required when mode is MIRROR) required: - ledgerName properties: ledgerName: type: string description: Name of the source ledger in the v2 system type: type: string enum: - http - postgres default: http description: Source type (defaults to "http" if omitted) baseUrl: type: string description: Valid absolute HTTP(S) URL with a nonempty hostname for the v2 API (required for HTTP source); checked at creation before persistence, without a network probe oauth2ClientId: type: string description: OAuth2 client ID for the v2 API (HTTP source only) oauth2ClientSecret: type: string description: OAuth2 client secret for the v2 API (HTTP source only) oauth2TokenEndpoint: type: string description: OAuth2 token endpoint URL (HTTP source only) oauth2Scopes: type: array items: type: string description: OAuth2 scopes (HTTP source only) dsn: type: string description: PostgreSQL connection string (required for PostgreSQL source) batchSize: type: integer minimum: 0 default: 0 description: Max logs per batch (0 = server default 100, capped by server's --mirror-max-batch-size) rewriteRules: type: array items: $ref: '#/components/schemas/MirrorRewriteRule' description: > Mirror rewrite rules applied, in order, to every mirror log entry as v2 logs are translated into v3 orders. Each rule is scoped to exactly one variant of the log's `data` oneof, with a CEL `match` predicate and a list of typed actions. MirrorRewriteRuleRead: type: object description: > Read representation of a mirror rewrite rule, using protojson camelCase names. Default scalar values (including empty regex replacements) are omitted; missing replacements mean the empty string. Creation uses the separate MirrorRewriteRule schema. properties: createdTransaction: $ref: '#/components/schemas/CreatedTransactionRuleRead' revertedTransaction: $ref: '#/components/schemas/RevertedTransactionRuleRead' savedMetadata: $ref: '#/components/schemas/SavedMetadataRuleRead' deletedMetadata: $ref: '#/components/schemas/DeletedMetadataRuleRead' anyVariant: $ref: '#/components/schemas/AnyVariantRuleRead' stop: type: boolean CreatedTransactionRuleRead: type: object description: > Rule scoped to MirrorCreatedTransaction. Inside `match`, `log` is the created-transaction proto directly (e.g. `log.metadata["k"]`). properties: match: type: string actions: type: array items: $ref: '#/components/schemas/CreatedTransactionActionRead' RevertedTransactionRuleRead: type: object properties: match: type: string actions: type: array items: $ref: '#/components/schemas/RevertedTransactionActionRead' SavedMetadataRuleRead: type: object properties: match: type: string actions: type: array items: $ref: '#/components/schemas/SavedMetadataActionRead' DeletedMetadataRuleRead: type: object properties: match: type: string actions: type: array items: $ref: '#/components/schemas/DeletedMetadataActionRead' AnyVariantRuleRead: type: object description: > Rule scoped to every variant. `log` is the full MirrorLogEntry — use `has(log.)` guards to read variant-specific fields. properties: match: type: string actions: type: array items: $ref: '#/components/schemas/AnyVariantActionRead' CreatedTransactionActionRead: type: object description: Exactly one field must be set. properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressActionRead' setMetadata: $ref: '#/components/schemas/SetMetadataActionRead' deleteMetadata: $ref: '#/components/schemas/DeleteMetadataAction' setAccountMetadata: $ref: '#/components/schemas/SetAccountMetadataActionRead' deleteAccountMetadata: $ref: '#/components/schemas/DeleteAccountMetadataAction' setAccountMetadataFromAddress: $ref: '#/components/schemas/SetAccountMetadataFromAddressActionRead' drop: $ref: '#/components/schemas/DropAction' RevertedTransactionActionRead: type: object properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressActionRead' setMetadata: $ref: '#/components/schemas/SetMetadataActionRead' deleteMetadata: $ref: '#/components/schemas/DeleteMetadataAction' drop: $ref: '#/components/schemas/DropAction' SavedMetadataActionRead: type: object properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressActionRead' setMetadata: $ref: '#/components/schemas/SetMetadataActionRead' deleteMetadata: $ref: '#/components/schemas/DeleteMetadataAction' drop: $ref: '#/components/schemas/DropAction' DeletedMetadataActionRead: type: object properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressActionRead' drop: $ref: '#/components/schemas/DropAction' AnyVariantActionRead: type: object properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressActionRead' drop: $ref: '#/components/schemas/DropAction' RewriteAddressActionRead: type: object required: [pattern] properties: pattern: type: string description: RE2 pattern (validated at admission). replacement: type: string SetMetadataActionRead: type: object description: > `value` is a literal metadata string; `valueExpr` is a CEL expression typed against the current variant and evaluated at commit time (e.g. `log.reference`). Exactly one of the two should be set; if neither is set the value defaults to the empty string. Optional `type` coerces the produced string into a typed MetadataValue via the platform conversion matrix — one of "string" (default), "int64", "bool", "uint64", "int8"/"int16"/"int32", "uint8"/"uint16"/"uint32", "datetime". required: [key] properties: key: type: string value: type: string valueExpr: type: string type: type: string SetAccountMetadataActionRead: type: object description: > See SetMetadataActionRead for the literal-vs-CEL and `type` semantics. required: [account, key] properties: account: type: string key: type: string value: type: string valueExpr: type: string type: type: string SetAccountMetadataFromAddressActionRead: type: object description: > For every posting address matching `pattern`, iterate every entry in `replacements` and set accountMetadata[address][key] to the RE2 replacement of the address. Each replacement carries an optional metadata `type` token (same tokens as SetMetadataActionRead.type). required: [pattern, replacements] properties: pattern: type: string replacements: type: array items: $ref: '#/components/schemas/SetAccountMetadataFromAddressReplacementRead' SetAccountMetadataFromAddressReplacementRead: type: object required: [key] properties: key: type: string replacement: type: string type: type: string MirrorRewriteRule: type: object description: > Transforms a mirror log entry during v2→v3 translation. Exactly one scope field (createdTransaction, revertedTransaction, savedMetadata, deletedMetadata, or anyVariant) must be set. That scope determines both the CEL type of `log` in the rule's `match` and the set of actions the rule may carry. When `stop` is true and the rule matches (scope + predicate), no further rules are evaluated. Rewriting is a deterministic, translation-time projection; the source v2 ledger is never modified. properties: createdTransaction: $ref: '#/components/schemas/CreatedTransactionRule' revertedTransaction: $ref: '#/components/schemas/RevertedTransactionRule' savedMetadata: $ref: '#/components/schemas/SavedMetadataRule' deletedMetadata: $ref: '#/components/schemas/DeletedMetadataRule' anyVariant: $ref: '#/components/schemas/AnyVariantRule' stop: type: boolean CreatedTransactionRule: type: object description: > Rule scoped to MirrorCreatedTransaction. Inside `match`, `log` is the created-transaction proto directly (e.g. `log.metadata["k"]`). properties: match: type: string actions: type: array items: $ref: '#/components/schemas/CreatedTransactionAction' RevertedTransactionRule: type: object properties: match: type: string actions: type: array items: $ref: '#/components/schemas/RevertedTransactionAction' SavedMetadataRule: type: object properties: match: type: string actions: type: array items: $ref: '#/components/schemas/SavedMetadataAction' DeletedMetadataRule: type: object properties: match: type: string actions: type: array items: $ref: '#/components/schemas/DeletedMetadataAction' AnyVariantRule: type: object description: > Rule scoped to every variant. `log` is the full MirrorLogEntry — use `has(log.)` guards to read variant-specific fields. properties: match: type: string actions: type: array items: $ref: '#/components/schemas/AnyVariantAction' CreatedTransactionAction: type: object description: Exactly one field must be set. properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressAction' setMetadata: $ref: '#/components/schemas/SetMetadataAction' deleteMetadata: $ref: '#/components/schemas/DeleteMetadataAction' setAccountMetadata: $ref: '#/components/schemas/SetAccountMetadataAction' deleteAccountMetadata: $ref: '#/components/schemas/DeleteAccountMetadataAction' setAccountMetadataFromAddress: $ref: '#/components/schemas/SetAccountMetadataFromAddressAction' drop: $ref: '#/components/schemas/DropAction' RevertedTransactionAction: type: object properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressAction' setMetadata: $ref: '#/components/schemas/SetMetadataAction' deleteMetadata: $ref: '#/components/schemas/DeleteMetadataAction' drop: $ref: '#/components/schemas/DropAction' SavedMetadataAction: type: object properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressAction' setMetadata: $ref: '#/components/schemas/SetMetadataAction' deleteMetadata: $ref: '#/components/schemas/DeleteMetadataAction' drop: $ref: '#/components/schemas/DropAction' DeletedMetadataAction: type: object properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressAction' drop: $ref: '#/components/schemas/DropAction' AnyVariantAction: type: object properties: rewriteAddress: $ref: '#/components/schemas/RewriteAddressAction' drop: $ref: '#/components/schemas/DropAction' RewriteAddressAction: type: object required: [pattern, replacement] properties: pattern: type: string description: RE2 pattern (validated at admission). replacement: type: string SetMetadataAction: type: object description: > `value` is a literal metadata string; `value_expr` is a CEL expression typed against the current variant and evaluated at commit time (e.g. `log.reference`). Exactly one of the two should be set; if neither is set the value defaults to the empty string. Optional `type` coerces the produced string into a typed MetadataValue via the platform conversion matrix — one of "string" (default), "int64", "bool", "uint64", "int8"/"int16"/"int32", "uint8"/"uint16"/"uint32", "datetime". required: [key] properties: key: type: string value: type: string value_expr: type: string type: type: string DeleteMetadataAction: type: object required: [key] properties: key: type: string SetAccountMetadataAction: type: object description: > See SetMetadataAction for the literal-vs-CEL and `type` semantics. required: [account, key] properties: account: type: string key: type: string value: type: string value_expr: type: string type: type: string DeleteAccountMetadataAction: type: object required: [account, key] properties: account: type: string key: type: string SetAccountMetadataFromAddressAction: type: object description: > For every posting address matching `pattern`, iterate every entry in `replacements` and set accountMetadata[address][key] to the RE2 replacement of the address. Each replacement carries an optional metadata `type` token (same tokens as SetMetadataAction.type). required: [pattern, replacements] properties: pattern: type: string replacements: type: array items: $ref: '#/components/schemas/SetAccountMetadataFromAddressReplacement' SetAccountMetadataFromAddressReplacement: type: object required: [key, replacement] properties: key: type: string replacement: type: string type: type: string DropAction: type: object description: Turns the entry into a fill-gap that preserves log-ID and tx-ID continuity. SaveNumscriptRequest: type: object required: - content - version properties: content: type: string description: The numscript source code version: type: string description: | Explicit full semver (e.g. "1.0.0"). Appends a new immutable version; fails if that version already exists. "latest" and partial selectors are not accepted for save. example: "1.0.0" NumscriptInfo: type: object required: - name properties: name: type: string description: Name of the numscript content: type: string description: The numscript source code version: type: string description: Semver version string (e.g. "1.0.0") example: "1.0.0" createdAt: type: string format: date-time description: Creation/update timestamp (ISO 8601 format) ledger: type: string description: Ledger name this numscript belongs to NumscriptVersionEntry: type: object required: - version properties: version: type: string description: Stored semver version string (e.g. "1.0.0") example: "1.0.0" createdAt: type: string format: date-time description: When this version was stored (ISO 8601 format) ListNumscriptVersionsResponse: type: object required: - data properties: data: type: object properties: latestVersion: type: string description: The current latest — the greatest stored semver example: "2.0.0" versions: type: array items: $ref: '#/components/schemas/NumscriptVersionEntry' description: Every stored version, highest-first nullable: true PromoteLedgerResponse: type: object required: - data properties: data: $ref: '#/components/schemas/LedgerInfo' GetNumscriptResponse: type: object required: - data properties: data: $ref: '#/components/schemas/NumscriptInfo' ListNumscriptsResponse: type: object required: - data - hasMore properties: data: type: array items: $ref: '#/components/schemas/NumscriptInfo' description: One page of numscripts, in the requested name order next: $ref: '#/components/schemas/PageToken' previous: $ref: '#/components/schemas/PageToken' hasMore: type: boolean description: True when a following page exists; set iff `next` is. TemplateUsage: type: object required: - count properties: count: type: integer format: int64 minimum: 0 description: | Number of times the template has been invoked. `0` means never invoked (or the usagebuilder has not yet caught up to any invocation on this replica). lastUsed: type: string format: date-time nullable: true description: | Timestamp of the most recent invocation (ISO 8601). Absent when `count` is 0. GetTemplateUsageResponse: type: object required: - data properties: data: $ref: '#/components/schemas/TemplateUsage' ChartOfAccounts: type: object description: A suggested chart of accounts based on account analysis properties: accounts: type: array items: type: object properties: pattern: type: string description: Account name pattern description: type: string description: Suggested description for this account group AnalyzeAccountsResponse: type: object required: - data properties: data: type: object properties: patterns: type: array items: $ref: '#/components/schemas/AccountPattern' totalAccounts: type: integer format: int64 AccountPattern: type: object properties: pattern: type: string accountCount: type: integer format: int64 assets: type: array items: type: string metadataKeys: type: array items: type: string segments: type: array items: $ref: '#/components/schemas/PatternSegment' PatternSegment: type: object properties: position: type: integer format: int32 type: type: string enum: [fixed, variable] fixedValue: type: string variableName: type: string inferredPattern: type: string uniqueValues: type: integer format: int64 examples: type: array items: type: string AnalyzeTransactionsResponse: type: object required: - data properties: data: type: object properties: flowPatterns: type: array items: $ref: '#/components/schemas/FlowPattern' totalTransactions: type: integer format: int64 totalReverted: type: integer format: int64 FlowPattern: type: object properties: signature: type: string description: Canonical flow signature (e.g. "users:{id}:main->bank:fees[USD]") structure: type: string enum: [simple, multiSource, multiDestination, complex] transactionCount: type: integer format: int64 postings: type: array items: $ref: '#/components/schemas/NormalizedPosting' temporal: $ref: '#/components/schemas/TemporalStats' volumeStats: type: array items: $ref: '#/components/schemas/AssetVolumeStats' metadataKeys: type: array items: type: string NormalizedPosting: type: object required: - sourcePattern - destinationPattern - asset - color properties: sourcePattern: type: string destinationPattern: type: string asset: type: string color: type: string pattern: '^[A-Z]*$' maxLength: 32 description: | Color discriminates postings on the same (source, destination, asset) but different color buckets in the FSM. Always emitted (even empty) so clients can distinguish the uncolored bucket from patterns that differ only by color. TemporalStats: type: object properties: firstSeen: type: string format: date-time lastSeen: type: string format: date-time transactionsPerDay: type: number format: double peakHours: type: array items: $ref: '#/components/schemas/HourBucket' HourBucket: type: object properties: hour: type: integer format: int32 minimum: 0 maximum: 23 count: type: integer format: int64 AssetVolumeStats: type: object properties: asset: type: string totalVolume: $ref: '#/components/schemas/UnsignedMonetaryAmount' averageVolume: $ref: '#/components/schemas/UnsignedMonetaryAmount' minVolume: $ref: '#/components/schemas/UnsignedMonetaryAmount' maxVolume: $ref: '#/components/schemas/UnsignedMonetaryAmount' transactionCount: type: integer format: int64 CreatePreparedQueryRequest: type: object required: - name - target properties: name: type: string description: Unique name for the prepared query target: type: string enum: - ACCOUNTS - TRANSACTIONS - LOGS description: >- Target entity type. `LOGS` queries return log entries; the log-only filter fields (`logId`, `date`, `ledger`) are valid only when the target is `LOGS`. filter: $ref: '#/components/schemas/PreparedQueryFilterInput' description: >- Optional filter. Omit it or set it to `null` to create a match-all query for the selected target. An empty object or empty textual expression is invalid. UpdatePreparedQueryRequest: type: object properties: filter: $ref: '#/components/schemas/PreparedQueryFilterInput' description: >- Replacement filter. Omit the field to leave the stored filter unchanged; set it to `null` to remove the filter and make the query match all entities in its target. An empty object or empty textual expression is invalid. ExecutePreparedQueryRequest: type: object properties: parameters: type: object additionalProperties: type: string description: Parameter values for the query (substituted into filter placeholders) pageSize: type: integer format: int32 description: Maximum number of results per page cursor: type: string description: | Page token from a previous response's `cursor.next` or `cursor.previous` (see the `PageToken` schema). The key is the decimal id for TRANSACTIONS and LOGS targets, the address for ACCOUNTS. mode: type: string enum: - LIST - AGGREGATE_VOLUMES description: Execution mode (default LIST) reverse: type: boolean default: false description: | List in descending entity order (address, transaction id or log id). A page token is relative to the requested order, so every page of a descending walk must set `reverse`. Rejected with 400 in `AGGREGATE_VOLUMES` mode. PreparedQueryResponse: type: object required: - data properties: data: $ref: '#/components/schemas/PreparedQuery' ListPreparedQueriesResponse: type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/PreparedQuery' PreparedQuery: type: object required: - name - target properties: name: type: string description: Query name target: type: string enum: - ACCOUNTS - TRANSACTIONS - LOGS description: >- Target entity type. `LOGS`, `ACCOUNTS` and `TRANSACTIONS` are all usable prepared-query targets (create, list/get and execute). filter: $ref: '#/components/schemas/QueryFilter' description: >- Stored filter. Omitted for a match-all prepared query. allowedModes: type: array items: type: string QueryFilter: type: object description: >- Recursive filter expression using the Formance query DSL (aligned with the v2 API). Each node is an object with **exactly one** top-level `$`-prefixed operator key. Combinators: - `{"$and": [QueryFilter, ...]}` — all sub-filters must match (non-empty). - `{"$or": [QueryFilter, ...]}` — at least one sub-filter matches (non-empty). - `{"$not": QueryFilter}` — negates a single sub-filter. Leaf conditions are a single-key operator whose value is a `{ "": }` map with exactly one field: - `{"$match": {"": }}` — equality; for `address`/`source`/`destination` a trailing `:` means prefix match, otherwise exact. - `{"$gt"|"$gte"|"$lt"|"$lte": {"": }}` — range bound. A closed range is expressed as an `$and` of a lower and an upper bound on the same field. - `{"$exists": {"metadata": ""}}` — the metadata key is present. - `{"$exists": {"asset": ""}}` — the account has ever held the asset (`assetRef` is `BASE` or `BASE/PRECISION`, e.g. `USD/2`). Requires a READY `account-asset` index. Supported fields: `metadata[]`, `address`, `source`, `destination`, `reference`, `reverted` (bool), `ledger`, `id`, `timestamp`, `insertedAt`, `revertedAt`, `logId`, `date`. Not every field applies to every query target; a field that does not apply is rejected. The numeric built-ins (`id`, `timestamp`, `insertedAt`, `revertedAt`, `logId`, `date`) are **range-only** — use `$gt`/`$gte`/`$lt`/`$lte`; `$match` on them is rejected. The log-only fields (`logId`, `date`, `ledger`) are valid only when the prepared query targets `LOGS`; they are rejected on `ACCOUNTS` and `TRANSACTIONS` targets. A value is either a JSON literal or a parameter reference `{"$param": ""}`, resolved at prepared-query execution time. A JSON `null` in value position is rejected. uint64 fields (`id`, `timestamp`, `insertedAt`, `revertedAt`, `logId`, `date`) are carried as decimal strings to stay lossless above 2^53. The date-semantic fields (`timestamp`, `insertedAt`, `revertedAt`, `date`) additionally accept an RFC3339 timestamp string (e.g. `{"$gte":{"date":"2023-11-14T22:13:20Z"}}`), coerced to the same Unix microseconds as the raw form; a value before the Unix epoch (1970-01-01) is rejected. minProperties: 1 maxProperties: 1 additionalProperties: true properties: $and: type: array minItems: 1 items: $ref: '#/components/schemas/QueryFilter' $or: type: array minItems: 1 items: $ref: '#/components/schemas/QueryFilter' $not: $ref: '#/components/schemas/QueryFilter' $match: type: object description: '`{ "": }` — exact/prefix/bool match.' minProperties: 1 maxProperties: 1 additionalProperties: true $gt: type: object description: '`{ "": }` — strictly greater than.' minProperties: 1 maxProperties: 1 additionalProperties: true $gte: type: object description: '`{ "": }` — greater than or equal.' minProperties: 1 maxProperties: 1 additionalProperties: true $lt: type: object description: '`{ "": }` — strictly less than.' minProperties: 1 maxProperties: 1 additionalProperties: true $lte: type: object description: '`{ "": }` — less than or equal.' minProperties: 1 maxProperties: 1 additionalProperties: true $exists: type: object description: >- `{ "metadata": "" }` (metadata key present) or `{ "asset": "" }` (account has held the asset). minProperties: 1 maxProperties: 1 additionalProperties: true $in: type: object description: >- `{ "": [, ...] }` — value is one of a set. Reserved for the list endpoints; not accepted on prepared queries yet. minProperties: 1 maxProperties: 1 additionalProperties: true PreparedQueryFilterInput: description: >- A filter supplied to a prepared-query create/update request, accepted in EITHER of two interchangeable representations that parse to the same filter and are validated against the same per-target rules (EN-1511): - the structured JSON QueryFilter object (see `QueryFilter`); or - the textual filter grammar carried as a JSON string, e.g. `"metadata[status] == \"active\""`. `null` represents a match-all query. An empty object and an empty or whitespace-only textual expression are invalid. Responses echo a stored non-null filter in the structured `QueryFilter` form and omit this field for match-all queries. oneOf: - $ref: '#/components/schemas/QueryFilter' - type: string nullable: true description: Textual filter expression (filter grammar). ExecutePreparedQueryResponse: type: object description: | Result of executing a prepared query. Exactly one field is set, discriminated by the request execution `mode` (see `ExecutePreparedQueryRequest.mode`): `mode=LIST` returns `cursor`, `mode=AGGREGATE_VOLUMES` returns `aggregateResult`. (The query `target` — ACCOUNTS, TRANSACTIONS or LOGS — selects the row type inside the cursor, not which envelope field is set: `accountData`, `transactionData` or `logData` respectively. LOGS is a usable prepared-query target: `query.Execute` hydrates `logData` for it.) Both payloads use the same camelCase encoding as the equivalent non-prepared endpoints (header-negotiated monetary amounts, `color` always present on every volume row including the uncolored bucket). properties: cursor: type: object description: | Paged cursor, returned when the request `mode` is `LIST`. The row type follows the query `target`: `accountData` for ACCOUNTS, `transactionData` for TRANSACTIONS, `logData` for LOGS. Rows use the same camelCase shapes as the non-prepared list endpoints. properties: pageSize: type: integer hasMore: type: boolean description: True when a following page exists; set iff `next` is. next: $ref: '#/components/schemas/PageToken' previous: $ref: '#/components/schemas/PageToken' accountData: type: array items: $ref: '#/components/schemas/Account' transactionData: type: array items: $ref: '#/components/schemas/TransactionResponse' logData: type: array items: $ref: '#/components/schemas/SystemLog' aggregateResult: $ref: '#/components/schemas/AggregateVolumesData' HealthResponse: type: object required: - data properties: data: type: object required: - status properties: status: type: string description: Health status (e.g. "ok") ServerInfo: type: object required: - version - commit - buildDate - goVersion - protocolVersion properties: version: type: string description: Server release version commit: type: string description: Git commit the binary was built from buildDate: type: string description: Build timestamp (RFC3339, "unknown" if unset) goVersion: type: string description: Go runtime version the binary was built with protocolVersion: type: string description: Required ledger-protocol-version metadata on Ledger gRPC business RPCs; independent of the release version SegmentType: type: object nullable: true description: | Constraint for a variable segment in an account type pattern. Null means any non-empty string is accepted. The `type` field discriminates the constraint kind; only `regex` carries a value. required: - type properties: type: type: string enum: [regex, uuid, uint64, bytes] description: | regex: custom regular expression (requires `regex`). uuid: RFC 4122 UUID format. uint64: decimal uint64. bytes: hex-encoded bytes (even length). regex: type: string description: Regular expression to match the segment against. Required when `type` is `regex`. example: '[A-Z]{2}[0-9]{14}' AddAccountTypeRequest: type: object required: - name - pattern properties: name: type: string description: Unique name for the account type example: user-checking pattern: type: string description: Account address pattern for validation. Variables use `{name}` segments. example: 'users:{id}:checking' persistence: type: string enum: [NORMAL, EPHEMERAL, TRANSIENT] default: NORMAL description: | How account volumes are stored. NORMAL: fully persisted (default). EPHEMERAL: persisted, purged when zero balance after commit. TRANSIENT: never persisted, must be zero at end of batch. example: EPHEMERAL segmentTypes: type: object description: Maps a pattern variable name to a type constraint. additionalProperties: $ref: '#/components/schemas/SegmentType' example: id: type: uuid AccountTypeInfo: type: object required: - name - pattern - persistence properties: name: type: string description: Account type name pattern: type: string description: Account address pattern persistence: type: string enum: [NORMAL, EPHEMERAL, TRANSIENT] description: How account volumes are stored (NORMAL, EPHEMERAL, or TRANSIENT) segmentTypes: type: object description: Maps a pattern variable name to a type constraint. additionalProperties: $ref: '#/components/schemas/SegmentType' ListAccountTypesResponse: type: object required: - data properties: data: type: object required: - types properties: types: type: array items: $ref: '#/components/schemas/AccountTypeInfo' description: List of account types sorted by name GetAccountTypeResponse: type: object required: - data properties: data: $ref: '#/components/schemas/AccountTypeInfo' SetDefaultEnforcementModeRequest: type: object required: - enforcementMode properties: enforcementMode: type: string enum: - STRICT - AUDIT description: Default enforcement mode for accounts not matching any account type ErrorResponse: type: object required: - errorCode - errorMessage properties: errorCode: type: string description: Error code identifier errorMessage: type: string description: | For local domain errors, a human-readable presentation derived from the stable failure code and facts. Diagnostic Error() text and diagnostic fields are not returned for those errors. INDEX_INCONSISTENT and COVERAGE_MISS use generic public messages. AuditEntry: type: object description: | A single audit trail entry for a proposal (success or failure). Exactly one of `success` / `failure` is set. `items` is populated only by the single-entry lookup, not by the list endpoint. properties: sequence: type: integer format: uint64 description: Global audit sequence number timestamp: type: string format: date-time description: Apply timestamp (RFC3339) proposalId: type: integer format: uint64 description: Identifier of the proposal that produced this entry success: $ref: '#/components/schemas/AuditSuccess' failure: $ref: '#/components/schemas/AuditFailure' orderCount: type: integer format: uint32 description: Number of orders in the proposal items: type: array description: Per-order detail lines. Populated by the single-entry lookup; empty on list. items: $ref: '#/components/schemas/AuditItem' ledgers: type: array description: Distinct ledger names targeted by the proposal's orders items: type: string hash: type: string description: Hex-encoded batch integrity hash chaining audit entries hashVersion: type: integer format: uint32 description: Hash algorithm version callerSnapshot: type: object additionalProperties: true description: Admission-time auth snapshot (protobuf JSON); absent when auth is disabled or for system proposals idempotency: type: object additionalProperties: true description: Batch identity / idempotency information (protobuf JSON) signature: type: object additionalProperties: true description: Client signature over the ApplyBatch (protobuf JSON); absent for unsigned batches AuditItem: type: object description: One order within a proposal. properties: orderIndex: type: integer format: uint32 description: Zero-based position of this order within the proposal serializedOrder: type: string description: Hex-encoded deterministic serialized bytes of the order at apply time logSequence: type: integer format: uint64 description: Sequence of the log produced by this order (0 for idempotent replay or failed proposals) AuditSuccess: type: object description: The inclusive log sequence range created by a successful proposal. properties: minLogSequence: type: integer format: uint64 maxLogSequence: type: integer format: uint64 AuditFailure: type: object description: Stable reason, subcode, and facts for a failed proposal. Presentation text is rendered when read and is not stored in the audit chain. properties: reason: type: string description: Typed error reason identifier (e.g. ERROR_REASON_INSUFFICIENT_FUNDS) code: type: string description: Stable failure subcode facts: type: object additionalProperties: type: string description: Validated facts used to render the failure