> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modo.link/llms.txt
> Use this file to discover all available pages before exploring further.

# Transaction flow

> Two-phase prepare → sign → execute model

Every state-changing operation in the Modo Ledger service uses a **two-phase** transaction model. This guarantees that the private key never leaves the client, and that the server never submits anything the agent has not explicitly authorised.

## Phases

<Steps>
  <Step title="Prepare">
    The client calls `PrepareTransaction` with a [`TransactionOperation`](#transactionoperation) enum value and a matching `params` oneof. The server builds the Canton transaction, returns its hash (`prepared_transaction_hash`), the serialized `prepared_transaction`, a `transaction_id`, and a `TrafficEstimate`.
  </Step>

  <Step title="Sign">
    The client signs `prepared_transaction_hash` with the agent's Ed25519 private key — see [Authentication](/agentic-api/authentication) for details on how signatures are carried.
  </Step>

  <Step title="Execute">
    The client calls `ExecuteTransaction` with `transaction_id` and the hex-encoded signature. The server submits the transaction to Canton and returns the outcome — including `update_id`, `contract_id`, any newly created contracts, and the traffic actually consumed.
  </Step>
</Steps>

## TransactionOperation

The enum selects which sub-operation the server should build in phase 1:

```proto theme={null}
enum TransactionOperation {
  TRANSACTION_OPERATION_UNSPECIFIED = 0;

  // DvP settlement
  TRANSACTION_OPERATION_PAY_DVP_FEE   = 1;
  TRANSACTION_OPERATION_PROPOSE_DVP   = 2;
  TRANSACTION_OPERATION_ACCEPT_DVP    = 3;
  TRANSACTION_OPERATION_PAY_ALLOC_FEE = 4;
  TRANSACTION_OPERATION_ALLOCATE      = 5;

  // Canton Coin transfers
  TRANSACTION_OPERATION_TRANSFER_CC = 6;

  // Preapproval
  TRANSACTION_OPERATION_REQUEST_PREAPPROVAL = 7;

  // Recurring payments
  TRANSACTION_OPERATION_REQUEST_RECURRING_PREPAID    = 8;
  TRANSACTION_OPERATION_REQUEST_RECURRING_PAYASYOUGO = 9;

  // User service
  TRANSACTION_OPERATION_REQUEST_USER_SERVICE = 10;

  // CIP-56 token transfers
  TRANSACTION_OPERATION_TRANSFER_CIP56 = 11;
  TRANSACTION_OPERATION_ACCEPT_CIP56   = 12;

  // CC merge-split
  TRANSACTION_OPERATION_SPLIT_CC = 13;

  // Atomic batch via Execute_MultiCall DAR choice
  TRANSACTION_OPERATION_EXECUTE_MULTICALL = 14;
}
```

### Operations reference

Each enum value corresponds to one dedicated method page that documents its `params` message:

| Operation | `params` field | Page |
| - | - | - |
| `PAY_DVP_FEE` | `pay_fee` | [PayDvpFee](/agentic-api/dvp/pay-dvp-fee) |
| `PROPOSE_DVP` | `propose_dvp` | [ProposeDvp](/agentic-api/dvp/propose-dvp) |
| `ACCEPT_DVP` | `accept_dvp` | [AcceptDvp](/agentic-api/dvp/accept-dvp) |
| `PAY_ALLOC_FEE` | `pay_fee` | [PayAllocFee](/agentic-api/dvp/pay-alloc-fee) |
| `ALLOCATE` | `allocate` | [Allocate](/agentic-api/dvp/allocate) |
| `TRANSFER_CC` | `transfer_cc` | [TransferCc](/agentic-api/transfer/transfer-cc) |
| `SPLIT_CC` | `split_cc` | [SplitCc](/agentic-api/transfer/split-cc) |
| `REQUEST_PREAPPROVAL` | `request_preapproval` | [RequestPreapproval](/agentic-api/preapproval/request-preapproval) |
| `TRANSFER_CIP56` | `transfer_cip56` | [TransferCip56](/agentic-api/cip56/transfer-cip56) |
| `ACCEPT_CIP56` | `accept_cip56` | [AcceptCip56](/agentic-api/cip56/accept-cip56) |
| `REQUEST_RECURRING_PREPAID` | `request_recurring_prepaid` | [RequestRecurringPrepaid](/agentic-api/recurring/request-recurring-prepaid) |
| `REQUEST_RECURRING_PAYASYOUGO` | `request_recurring_payasyougo` | [RequestRecurringPayasyougo](/agentic-api/recurring/request-recurring-payasyougo) |
| `REQUEST_USER_SERVICE` | `request_user_service` | [RequestUserService](/agentic-api/user-service/request-user-service) |
| `EXECUTE_MULTICALL` | `execute_multicall` | [ExecuteMultiCall](/agentic-api/multicall/execute-multicall) |

## PrepareTransactionRequest

```proto theme={null}
message PrepareTransactionRequest {
  TransactionOperation operation = 1;

  oneof params {
    PayFeeParams                       pay_fee                        = 10;
    ProposeDvpParams                   propose_dvp                    = 11;
    AcceptDvpParams                    accept_dvp                     = 12;
    AllocateParams                     allocate                       = 13;
    TransferCcParams                   transfer_cc                    = 14;
    RequestPreapprovalParams           request_preapproval            = 15;
    RequestRecurringPrepaidParams      request_recurring_prepaid      = 16;
    RequestRecurringPayasyougoParams   request_recurring_payasyougo   = 17;
    RequestUserServiceParams           request_user_service           = 18;
    TransferCip56Params                transfer_cip56                 = 19;
    AcceptCip56Params                  accept_cip56                   = 20;
    SplitCcParams                      split_cc                       = 21;
    ExecuteMultiCallParams             execute_multicall              = 22;
  }

  MessageSignature request_signature = 30;
}
```

## PrepareTransactionResponse

<ParamField path="transaction_id" type="string">
  Opaque server-assigned ID. Pass this into `ExecuteTransaction`.
</ParamField>

<ParamField path="prepared_transaction_hash" type="string">
  Hex-encoded Canton transaction hash. **This is what the agent must sign.**
</ParamField>

<ParamField path="command_id" type="string">
  Canton command ID used for idempotency.
</ParamField>

<ParamField path="prepared_transaction" type="bytes">
  Serialised prepared transaction (for deterministic re-hashing if desired).
</ParamField>

<ParamField path="hashing_scheme_version" type="string">
  Canton hashing scheme version used to compute the hash.
</ParamField>

<ParamField path="traffic_estimate" type="TrafficEstimate">
  Estimated Canton traffic (`read_cost`, `write_cost`, `total_cost`) the transaction will consume.
</ParamField>

<ParamField path="response_signature" type="MessageSignature">
  Provider signature over the response payload — see [Authentication](/agentic-api/authentication#messagesignature).
</ParamField>

<ParamField path="transaction_status" type="TransactionStatus">
  Always `PENDING` after prepare.
</ParamField>

## ExecuteTransactionRequest

<ParamField path="transaction_id" type="string" required>
  Value returned from `PrepareTransaction`.
</ParamField>

<ParamField path="signature" type="string" required>
  Hex-encoded Ed25519 signature over `prepared_transaction_hash`.
</ParamField>

<ParamField path="request_signature" type="MessageSignature" required>
  Message-level signature from the cloud agent — see [Authentication](/agentic-api/authentication#messagesignature).
</ParamField>

## ExecuteTransactionResponse

<ParamField path="success" type="bool">
  `true` if the transaction was submitted and committed successfully.
</ParamField>

<ParamField path="update_id" type="string">
  Canton update ID of the committed transaction.
</ParamField>

<ParamField path="contract_id" type="string (optional)">
  Primary contract created by the transaction (if any).
</ParamField>

<ParamField path="created_contracts" type="CreatedContractInfo[]">
  All contracts created by the transaction — useful for tracking new amulets from change/split.
</ParamField>

<ParamField path="traffic" type="TrafficEstimate">
  Actual traffic consumed.
</ParamField>

<ParamField path="rewards_amount" type="string (optional)">
  Featured-app rewards earned, if applicable.
</ParamField>

<ParamField path="rewards_round" type="uint64 (optional)">
  Mining round in which rewards were earned.
</ParamField>

<ParamField path="error_message" type="string (optional)">
  Human-readable error.
</ParamField>

<ParamField path="provider_error" type="ProviderError (optional)">
  Structured error (`ProviderRpcError`) when `success = false`.
</ParamField>

<ParamField path="transaction_status" type="TransactionStatus">
  `EXECUTED` on success, `FAILED` on error.
</ParamField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.