> ## 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>
