---
name: bsv-actions
description: "Implement the wallet actions behind any BSV payment or on-chain write: createAction with descriptions a person can read, two-step signing with signAction and abortAction, and reporting what happened without a confirmation counter. Use when asked to 'create a transaction', 'call createAction', 'sign a transaction', 'cancel a pending transaction', 'show transaction status', 'list a user's transactions', or anything about building and tracking BSV transactions through a wallet."
---

> Start from [bitcoinsv-design](../bitcoinsv-design/SKILL.md). Shared states, labels, errors, amounts and fees: [shared patterns](../bitcoinsv-design/references/shared-patterns.md).

# Create, sign and report BSV actions

**Scope:** The transaction lifecycle as an app sees it through BRC-100: describing an action, signing it, cancelling it, and reporting its state.

**Does NOT cover:**

- Who to pay and the review screen: see [bsv-payments](../bsv-payments/SKILL.md)
- Time locks and multi-key conditions: see [bsv-script-conditions](../bsv-script-conditions/SKILL.md)
- Writing data on chain: see [bsv-on-chain-data](../bsv-on-chain-data/SKILL.md)

**Cross-references:** [bsv-payments](../bsv-payments/SKILL.md), [bsv-script-conditions](../bsv-script-conditions/SKILL.md), [shared patterns](../bitcoinsv-design/references/shared-patterns.md).

An action is a transaction the wallet builds, signs and tracks on the app's behalf. The design work is in two places: the description, which is what the user sees in their wallet's prompt and in its activity, and the state, which on BSV is decided mostly by acceptance rather than by counting blocks. Miners follow a first-seen rule and there is no replace-by-fee, so accepting an everyday payment before it is mined is reasonable, and a confirmation counter tells the user your "Paid" was provisional.

## ALWAYS

- Make the recipient and the amount unmistakable on the review screen. Once accepted, a payment cannot be cancelled. _([costs money](https://www.bitcoinsv.design/guide/rule/d44d6f8652/))_
- Warn when a user pastes an address rather than choosing a handle or contact, and offer handles and contacts first everywhere you can. See Wrong-network payments. _([costs money](https://www.bitcoinsv.design/guide/rule/435cfa246c/))_
- Treat confirmation as a risk setting, not a blanket rule. For coffee, articles, tips and most in-person sales, treat a payment as complete once the recipient's wallet has accepted it. For large amounts, show the payment as Settling until it is mined, and let businesses set their own threshold. _([costs trust](https://www.bitcoinsv.design/guide/rule/338e7363b6/))_
- Absorb the fee into your price where you can. If you show the network fee, put it in the payment's details as "less than 1p", not on the review screen. _([rule](https://www.bitcoinsv.design/guide/rule/c8bbcdfe72/))_
- Lead with the person or the app. A user scanning for "that payment to the café" is looking for the café, not for an amount. _([rule](https://www.bitcoinsv.design/guide/rule/4029686f48/))_
- Group by source and period: "The Satoshi Vision, 47 articles, 940 sats today" as one row that expands. _([rule](https://www.bitcoinsv.design/guide/rule/c0d3b2d827/))_

## NEVER

- Make an explorer the answer to "where is my money". If a wallet cannot explain the state of its own payment, that is a gap in the wallet. See Nodes and verification. _([costs trust](https://www.bitcoinsv.design/guide/rule/250ffdfe50/))_
- Trust a single service's word that a payment is confirmed. The merkle proof is the evidence; verify it against headers rather than displaying whatever the API returned. _([costs trust](https://www.bitcoinsv.design/guide/rule/a093cf784f/))_
- Show a transaction id in the list. It identifies nothing a person recognises. Keep it in the details, for support, as in the example below. _([rule](https://www.bitcoinsv.design/guide/rule/64290699ff/))_
- Show change returned to the wallet as a separate entry. One payment is one row. _([rule](https://www.bitcoinsv.design/guide/rule/55606940cb/))_
- Hide small payments behind a filter that is off by default. The user agreed an allowance and is entitled to see where it went without hunting. See Permissions and allowances. _([rule](https://www.bitcoinsv.design/guide/rule/ba8797f501/))_
- Group payments from different apps together. The grouping is per relationship; merging them loses the only thing that made it readable. _([rule](https://www.bitcoinsv.design/guide/rule/2ef405333c/))_

## Patterns

_Design guidance in each pattern comes from the guide page it cites. Method names, arguments and code are implementation notes checked against `@bsv/sdk` 4.0.0._

### 1. Describe the action as the user would

**When:** Every `createAction` call.

**How:**

1. `description` is 5 to 50 bytes and is what the wallet shows when it asks the user and in their activity afterwards. Write what it is for, from the user's side: "Lunch with Anna", "The Satoshi Vision article", not "tx" or an order id.
2. Give each output an `outputDescription` (also 5 to 50 bytes) for the same reason, and put an app's own outputs in a named `basket`.
3. Add `labels` that let you find the action again with `listActions({ labels })`, such as the order id or the agent task.

```ts
import { WalletClient } from "@bsv/sdk";

const wallet = new WalletClient("auto", "example.com");
declare const lockingScript: string; // hex

const result = await wallet.createAction({
  description: "Lunch with Anna",
  outputs: [
    { lockingScript, satoshis: 12_500, outputDescription: "Payment to Anna" },
  ],
  labels: ["order-4821"],
});
```

_Source: [Permissions and allowances](https://www.bitcoinsv.design/guide/patterns/permissions-and-allowances/)_

### 2. Sign in two steps, and cancel cleanly

**When:** The app needs to inspect or add to the transaction before it is signed, or the user may still back out.

**How:**

1. Call `createAction` with `options: { signAndProcess: false }`. The result carries a `signableTransaction` with a `reference`.
2. To finish, call `signAction({ reference, spends })` with the unlocking scripts for the inputs the app supplied.
3. To back out, call `abortAction({ reference })`, so nothing is left reserved.
4. Show a pending two-step action as waiting on whoever it is waiting on, never as "Sending". Nothing has been sent.

**Error states:**

- **The user cancels between the two steps:** "You cancelled the payment. Nothing was sent." Return to the previous screen with everything still filled in.

_Source: [Shared wallet](https://www.bitcoinsv.design/guide/wallet-patterns/shared-wallet/)_

### 3. Report the state that matters

**When:** After any action, and in any activity list.

**How:**

1. For a payment handed to a recipient, the main event is their wallet accepting it: show **Paid** or **Received** then, and stop there for everyday amounts.
2. Use **Settling** only for amounts large enough to matter, while the transaction is broadcast and not yet mined. Show **Complete** quietly once mined.
3. With the default `acceptDelayedBroadcast: true` the wallet broadcasts in the background. With `false`, problems come back as a `WERR_REVIEW_ACTIONS` error whose `reviewActionResults` carry a `status` of `doubleSpend`, `invalidTx` or `serviceError`.
4. Build activity from `listActions({ labels, includeLabels: true })`, leading each row with who, then how much, then why, then when. Never show change as a second payment.

**Error states:**

- **`WERR_REVIEW_ACTIONS` with status `doubleSpend`:** This payment did not go through: the same money was spent elsewhere first, and nothing left the wallet for it. Suggest checking recent activity.
- **`invalidTx`:** The network rejected it. Give the reason in a sentence and say that nothing was sent; that is what the user wants to know first.
- **`serviceError`:** Not a rejection: the network could not be reached and the wallet will keep trying. Say it is waiting to go through, show it as pending, and do not invite the user to pay again.

_Source: [Activity](https://www.bitcoinsv.design/guide/daily-spending-wallet/activity/)_

## All the rules

`references/rules.md`: 24 rules from 3 pages, 5 of them costly, most costly first.
Every rule in the guide, most costly first: https://www.bitcoinsv.design/api/rules.json

## Implementation resources

- **[@bsv/sdk](https://bsv-blockchain.github.io/ts-sdk/)**: The TypeScript SDK: `WalletClient` for every BRC-100 call, `AuthFetch` for HTTP 402, transactions, scripts and BEEF. Source at github.com/bsv-blockchain/ts-sdk.
- **[Wallet Toolbox](https://github.com/bsv-blockchain/wallet-toolbox)**: The wallet side of the interface: storage, signing and `WalletPermissionsManager`. Start here if you are building a wallet rather than an app.
- **[BRCs](https://github.com/bsv-blockchain/BRCs)**: Every proposal the skills cite, by number.

---

_Generated from https://www.bitcoinsv.design/, Open BSV License Version 6. Rules are extracted from the guide's pages and cannot be out of date about what it says; the patterns may still need updating._
