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

# Submitting Transactions and Fees with the Walley Python SDK

> Run your dApp's own ledger commands through prepare, sign, and submit — with the network fee quoted before you sign and drawn from a prepaid traffic balance.

This is the core of the SDK: take *any* ledger `Commands` batch — your dApp's own transaction — quote its fee, sign it locally, and submit it. Transfers, preapprovals, and fee payments are all built on this same machinery.

## Execute your dApp's commands

Commands can come from anywhere: your backend, a Walley `/prepare` endpoint, or hand-built against the [Ledger API](/python-sdk/ledger). Pass a dict or the raw JSON string your dApp emits:

```python theme={null}
commands = my_dapp.build_transaction(w.party_id)

result = w.transactions.execute(commands)         # prepare → sign → submit → wait
result.update_id                                  # ledger update id
result.fee                                        # the network fee it incurred

w.transactions.execute(commands, wait=False)      # fire-and-forget
```

In dApp SDK terms, `execute(commands)` is `prepareExecuteAndWait` and `execute(commands, wait=False)` is `prepareExecute` — minus the popup, since your process holds the key.

## Inspect the fee before committing

`execute` is `prepare` + `submit`. Split them to see the fee — or anything else about the prepared transaction — before signing:

```python theme={null}
prepared = w.transactions.prepare(commands)
prepared.fee            # Fee(amount=Decimal("0.03")) — or None if free

result = w.transactions.submit(prepared)   # commit
# ...or just drop `prepared` — nothing was signed, nothing is owed
```

Nothing touches the ledger until `submit`. Under the hood, `submit` signs the prepared transaction's hash with your Ed25519 key and echoes the prepared bytes back — Canton's external-party signing flow, in one call.

## The prepaid traffic model

Walley charges Canton network traffic as a fee in CC (Canton Coin): the ledger's traffic estimate for your transaction is priced in USD and converted at the current CC price. Every prepare quotes it up front; sends inside the daily free allowance quote `fee=None` (check with `w.traffic.free_sends()`).

Fees are **prepaid**. You buy a traffic balance ahead of time, and each charged transaction draws from it automatically — there's no per-transaction settle step:

```python theme={null}
w.traffic.balance()        # TrafficBalance(available=Decimal("142.50"), ...)
w.traffic.purchase("100")  # buy 100 CC of traffic; drawn down as you transact
```

`purchase` is a real on-ledger top-up: it exercises `WalleyRules_BuyTraffic`, paying CC to the operator, and (like any transaction) it's prepared, signed, and submitted for you. Buying traffic is itself fee-exempt. You can also credit someone else's balance:

```python theme={null}
w.traffic.purchase("100", beneficiary="party::1220…")   # you pay, they receive
```

<Note>
  One transaction can be **fronted**: if your traffic balance can't cover a fee, the charge still goes through and the balance goes negative by that one transaction. While it's negative, the next prepare fails with `InsufficientTrafficError` (HTTP 402) until you top up.
</Note>

```python theme={null}
from walley import InsufficientTrafficError

try:
    w.transactions.execute(commands)
except InsufficientTrafficError:
    w.traffic.purchase("100")          # top up, then retry
    w.transactions.execute(commands)
```

Charged fees appear in history with `tx_kind="fee"` — filter with `w.transactions.list(tx_kind="fees")` or exclude with `"non_fees"`. Inspect the traffic ledgers directly with `w.traffic.usage()` (what each transaction was charged) and `w.traffic.purchases()` (your top-ups).

## Transaction history

History is cursor-paginated and scoped to your party:

```python theme={null}
page = w.transactions.list(page_size=50)
page.transactions[0].event          # TransferEvent | MergeEvent
page.next_cursor                    # pass back as cursor=... for the next page

for tx in w.transactions.iter():    # or walk all pages
    ...
```
