> For the complete documentation index, see [llms.txt](https://bsv.brc.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bsv.brc.dev/tokens/0165.md).

# P1Sat Permission Scheme for Basket 1sat

David Case (<david.case@shruggr.cloud>)\
Brandon Cryderman / HandCash (<brandongcryderman@gmail.com>)

## Abstract

This BRC defines the **P1Sat** basket permission scheme for [BRC-100](/wallet/0100.md) wallets: scheme id **`1sat`** under [BRC-99](/wallet/0099.md) / [BRC-116](/wallet/0116.md).

Storage of collectables remains the plain basket **`1sat`** ([BRC-147](/tokens/0147.md)). Applications request **view** access with a [BRC-99](/wallet/0099.md) basket `p 1sat <scope>` (scope names the **permission axis**; filter **values** ride ordinary `tags`). Applications request **spend** authorization by labeling `createAction` with `p 1sat input id <key>`, where `<key>` is the bare [BRC-164](/wallet/0164.md) list key for the held row. Conforming wallets route those requests to a scheme module, normalize storage to `1sat` where needed, apply view grants and per-action spend approval as specified below, and MUST NOT treat payment / auto-pay grants as item access.

This document does **not** redefine 1Sat chain theory, inscriptions, collections, or provenance proofs. It does **not** replace [BRC-147](/tokens/0147.md) or retarget [BRC-150](/tokens/0150.md).

## Motivation

Plain [BRC-46](/wallet/0046.md) baskets only support coarse grant/deny. Collectables need finer app access — one collection, one app, one creator, or the full inventory — without inventing a storage basket per filter and without forcing inventory to live under a `p …` name.

[BRC-99](/wallet/0099.md) reserves `p <scheme> …` for richer permission modules. This BRC defines scheme id `1sat` and separates storage from permission routing:

| Layer          | Law                                                                                                |
| -------------- | -------------------------------------------------------------------------------------------------- |
| Storage basket | `1sat` ([BRC-147](/tokens/0147.md))                                                                |
| View (list)    | basket `p 1sat <scope>` ([Scopes](#scopes)); axis values in `tags`; other tags only narrow further |
| Spend          | `createAction` labels `p 1sat input id <key>` ([BRC-164](/wallet/0164.md))                         |
| Provenance     | [BRC-150](/tokens/0150.md) on storage `1sat`                                                       |

## Basket Namespace

1. **Scheme ID:** `1sat` (no spaces; [BRC-99](/wallet/0099.md))
2. **Basket name format:** `p 1sat <scope>` where `<scope>` is a fixed axis token from [Scopes](#scopes) (required). Basket names use only `[a-z0-9 ]` per [BRC-100](/wallet/0100.md). Filter **values** are not part of the basket name.
3. **Wallet capability:** Must implement storage basket `1sat` per [BRC-147](/tokens/0147.md); must route `p 1sat …` basket operations and `p 1sat input id …` labels to this scheme’s module; must enforce view grants on list and per-action spend approval on labeled spends
4. **Permission semantics:** See [View](#view-listoutputs) and [Spend](#spend-createaction)

Module **presence detection** uses the [BRC-98](/wallet/0098.md) protocol **`p 1sat probe`** (security level **0**); see [Module detection](#module-detection). Wallets route by scheme id `1sat` ([BRC-116](/wallet/0116.md)). That probe is not the default key-derivation protocol for new inventory tips. New tip key derivation SHOULD follow [BRC-147](/tokens/0147.md) / wallet policy (e.g. plain protocol names such as `onesat`).

[BRC-123](/wallet/0123.md) registry listing for this scheme is deferred (current §3.1 letter-first scheme ids do not admit `1sat`).

## Specification

### Scheme identifier

* **Scheme id:** `1sat` (no spaces; [BRC-99](/wallet/0099.md))
* **BRC-98 probe protocol:** `[0, "p 1sat probe"]` (level 0; see [Module detection](#module-detection))
* **BRC-99 basket form (view):** `p 1sat <scope>` (scope required; see [Scopes](#scopes))
* **BRC-111 label form (spend):** `p 1sat input id <key>` (`<key>` = bare [BRC-164](/wallet/0164.md) list key)

Wallets that do not implement this scheme MUST reject operations under these identifiers per [BRC-99](/wallet/0099.md) / [BRC-98](/wallet/0098.md).

### Module detection

Applications MAY detect whether scheme `1sat` is available by probing a [BRC-98](/wallet/0098.md) protocol under this scheme. Per BRC-98, protocol names are `p <scheme-id> <rest>`; the rest token for this probe is **`probe`**.

**Probe (application behavior):** call BRC-100 `getPublicKey` with:

```json
{
  "protocolID": [0, "p 1sat probe"],
  "keyID": "1sat-module-probe",
  "counterparty": "self",
  "seekPermission": false
}
```

Notes:

* **Protocol claim:** security level **0**, protocol name **`p 1sat probe`**. Level 0 keeps the probe outside ordinary Level 1/2 protocol-permission UX when the wallet routes it to this scheme’s module ([BRC-43](/key-derivation/0043.md), [BRC-116](/wallet/0116.md)).
* **Wallet behavior** for supported vs unsupported `p …` protocols and baskets is already defined by [BRC-98](/wallet/0098.md), [BRC-99](/wallet/0099.md), and [BRC-116](/wallet/0116.md) (route to a registered module by scheme id `1sat`, or reject if the scheme is not supported). This BRC does not alter those rules.
* **Conforming module:** when the wallet routes this `getPublicKey` to the `1sat` module, the module SHOULD pass the request through (return a public key) so the probe succeeds without a user prompt.
* **`keyID`:** `1sat-module-probe` is RECOMMENDED for interoperability among probers; it is not a special wallet-reserved id beyond ordinary BRC-43 key-id rules.
* **`seekPermission: false`:** RECOMMENDED so capability detection does not open a permission UI.
* **Interpretation:** applications treat probe **success** (on a wallet that uses P-module routing) as evidence that scheme `1sat` is registered, and a **BRC-98/99 unsupported-scheme rejection** as evidence it is not. Bare wallets without a permissions manager may not give a reliable signal; applications SHOULD only enable module-mediated labels/baskets when they expect P-module routing.

This probe does **not** grant view or spend rights. It does not change [BRC-111](/wallet/0111.md) label rules; spend labels under this scheme still follow BRC-111’s `p <scheme> <payload>` form as specified in [Spend](#spend-createaction).

### Storage vs permissions

1. Conforming wallets MUST file collectables in storage basket **`1sat`** ([BRC-147](/tokens/0147.md)).
2. Permission basket ids are **`p 1sat <scope>`** only (scope required). They are routing names only; held tips remain in `1sat`.
3. When a request uses a basket beginning with `p 1sat` (after BRC-46 trim/lowercase), the wallet MUST:
   * treat the request as scheme `1sat`;
   * parse [scope](#scopes) from the basket name (reject if missing or unknown; values are not in the basket name);
   * require axis tag value(s) on the request when the scope is not `all`;
   * **normalize** the storage target to basket `1sat`;
   * apply view permission for that scope and value(s) (prompt or prior grant) before returning outputs;
   * enforce axis tags as a mandatory filter; other caller tags only narrow further.

### View (`listOutputs`)

#### Scopes

After the scheme prefix `p 1sat`, a **scope is required**. The scope names a **permission axis** only. Filter values are not part of the basket name; they use ordinary output **tags**. The full basket name MUST stay within [BRC-100](/wallet/0100.md) `[a-z0-9 ]`.

| Basket form         | Scope          | Meaning                                                                 |
| ------------------- | -------------- | ----------------------------------------------------------------------- |
| `p 1sat all`        | **all**        | Entire storage `1sat`                                                   |
| `p 1sat collection` | **collection** | Collection-scoped view; values from `collection:…` tags                 |
| `p 1sat app`        | **app**        | App-scoped view; values from `app:…` tags                               |
| `p 1sat creator`    | **creator**    | Creator-scoped view; values from `creator:…` tags                       |
| `p 1sat id`         | **id**         | Single-row lookup; values from `id:…` tags ([BRC-164](/wallet/0164.md)) |

Rules:

1. Bare `p 1sat` (no scope token) MUST be rejected. Full inventory uses **`p 1sat all`** only.
2. Scope is exactly one token after `p 1sat` (`all`, `collection`, `app`, `creator`, or `id`). Extra tokens in the basket name MUST be rejected.
3. Unknown scope tokens MUST be rejected with a clear error (fail closed). Future axes are added by revising this table.
4. For scopes **collection**, **app**, **creator**, and **id**, the request MUST include at least one tag with the matching prefix (`collection:`, `app:`, `creator:`, `id:`). The tag **value** (after the prefix) is the filter id. For **collection**, the value is a **collection id** per [BRC-147](/tokens/0147.md).
5. For scope **all**, no axis tag is required. Caller tags are optional further filters only.
6. Matching tags follow [BRC-147](/tokens/0147.md) / [BRC-164](/wallet/0164.md). Exact tag equality after normal wallet tag normalization.
7. Scope **id** is a **targeted lookup**, not full-inventory access. It MUST NOT require grant **all**. Conforming wallets MUST allow `p 1sat id` + `id:<key>` through the module without a prior collection/app/creator/**all** grant (auto-allow this narrow query, or an equivalent one-shot / id-scoped grant). Results MUST still be limited to the requested `id:…` value(s). Spend targeting remains [Spend](#spend-createaction) (`p 1sat input id <key>`), not this scope alone.

#### Request shape

```json
{
  "basket": "p 1sat collection",
  "tags": [
    "collection:a1b2c3d4e5f6070890abcdef1234567890abcdef1234567890abcdef12345678_0",
    "type:image/png"
  ],
  "tagQueryMode": "all",
  "includeTags": true,
  "includeCustomInstructions": true
}
```

* **`basket`:** `p 1sat <scope>` as in [Scopes](#scopes) (axis only; scope required).
* **`tags`:** for non-`all` scopes, MUST include the axis tag(s) carrying the filter value(s). Additional tags (e.g. `type:`) only narrow further.
* **`tagQueryMode`:** applies to the caller’s tag set as constrained by [Scope ceiling](#scope-ceiling-and-tag-query).
* Apps MAY still call `listOutputs` with plain basket `1sat`. That path is ordinary basket access ([BRC-46](/wallet/0046.md) / [BRC-116](/wallet/0116.md)), not this scheme, unless the wallet elects to route plain `1sat` through the same module as local policy.

#### Normalization

On `listOutputs` with basket `p 1sat <scope>`, conforming wallets MUST:

1. Parse the scope ([Scopes](#scopes)); reject bare `p 1sat`, unknown scopes, and basket names that embed values after the scope token.
2. For non-`all` scopes, require at least one matching axis tag on the request; reject if missing.
3. Require a **view** grant covering that scope and the requested axis value(s) (or prompt to create one) — see [View grants](#view-grants).
4. Rewrite the storage query basket to `1sat`.
5. Enforce the granted axis tag value(s) as a **mandatory** filter on results (`tagQueryMode: "any"` MUST NOT drop them).
6. Apply any additional non-axis caller tags only inside that ceiling.
7. Return only outputs that satisfy the grant and the effective tag query.

How the wallet enforces (4)–(6) (query rewrite, post-filter, or equivalent) is an implementation choice.

Denial SHOULD use a distinct error so apps can distinguish “user denied item view” from generic basket denial.

#### View grants

Item view is **not** covered by ordinary payment / auto-pay grants.

Each list request has one **scope**. The scope maps to a tag prefix (or to no prefix for `all`):

| Scope        | Required tag(s) on the request |
| ------------ | ------------------------------ |
| `all`        | none                           |
| `collection` | one or more `collection:…`     |
| `app`        | one or more `app:…`            |
| `creator`    | one or more `creator:…`        |
| `id`         | one or more `id:…`             |

The wallet queries storage basket `1sat` with those tags (plus any optional extra tags the caller adds). Grant check is on **this request’s scope and tag values**, not a multi-axis matrix.

* **`p 1sat all`** — requires a standing grant for full inventory (or a prompt that creates one).
* **`p 1sat collection` / `app` / `creator`** — requires a standing grant that covers the requested tag value(s) for that scope (or a prompt). Grant **all** also covers these.
* **`p 1sat id`** — no standing inventory grant; knowing `id:<key>` is enough to look up that row (see [Scopes](#scopes)).

When the user approves a collection/app/creator/all request, the wallet SHOULD persist a grant for that scope and those tag values (or upgrade to **all**). Storage layout is local.

A later request MAY skip a new prompt when its scope and tag values are already covered by a stored grant (including grant **all** covering narrower scopes). Otherwise prompt or deny.

**Scope ceiling and tag query**

The scope’s required tags are mandatory on the result set. Optional extra tags (e.g. `type:image/png`) only narrow further. `tagQueryMode: "any"` MUST NOT drop the scope’s required tags.

### Spend (`createAction`)

Spend targeting under this scheme is built on [BRC-164](/wallet/0164.md) output identity tags. The held row MUST carry an `id:<key>` tag stamped by the holding wallet. The spend label names that key explicitly; the module resolves it back to the row with tag `id:<key>` under storage basket `1sat`.

#### Label form

**Held row (normative):**

```
p 1sat input id <key>
```

Rules:

1. [BRC-111](/wallet/0111.md)-style P-label: scheme id `1sat`, payload `input id <key>`.
2. **`<key>`** is the [BRC-164](/wallet/0164.md) list key — the substring after `id:` on the held output’s tags. Non-empty, no spaces, no `id:` prefix in the label.
3. Storage basket is implied by the scheme: **`1sat`**.

Example (row tagged `id:a1b2c3d4e5f60708`):

```
p 1sat input id a1b2c3d4e5f60708
```

Multiple such labels MAY appear when the action spends multiple tracked rows. Rows without a BRC-164 `id:` tag cannot use this form.

**Other `input` payloads.** A label `p 1sat input <outpoint>` whose single payload outpoint is not the keyword `id` is outside this scheme’s permission model (e.g. naming a beefed external input). It is not a BRC-164 list key and is not further specified here. The normative spend path for wallet-held tips remains `p 1sat input id <key>`.

#### Module behavior

When `createAction` carries one or more `p 1sat input id <key>` labels, conforming wallets MUST:

1. Route the call to the `1sat` permission module ([BRC-116](/wallet/0116.md)).
2. Resolve each `<key>` to a held output in storage basket `1sat` via [BRC-164](/wallet/0164.md) (`id:<key>`).
3. Obtain **user approval for this action’s spend** before spending those outputs. Payment / auto-pay MUST NOT satisfy this. Send approval is **per action** (inline prompt); this BRC does not define a standing/persisted “can send items” grant.
4. On approval, authorize **only** the spend set the user approved. A later `createSignature` (or equivalent) MUST NOT expand that set without a new approval.

Once an action is classified as a held-tip spend under this scheme (via `input id <key>` and successful resolution), payment auto-approve MUST NOT apply.

#### Outpoint spend without labels

Apps MAY still spend by outpoint without a `p 1sat input` label. That path does **not** enter this scheme via labels. Wallets SHOULD still refuse to spend storage `1sat` outputs under ordinary payment grants ([BRC-147](/tokens/0147.md) payment separation). Interoperable module-mediated spend targeting uses the input label form above.

### Capabilities (summary)

| Capability | Wire                                      | Covers                                                                |
| ---------- | ----------------------------------------- | --------------------------------------------------------------------- |
| **View**   | `listOutputs` basket `p 1sat <scope>`     | Listing storage `1sat` under the module                               |
| **Send**   | `createAction` labels `p 1sat input id …` | Per-action approval to spend labeled held rows (not a standing grant) |

**Receive** / `internalizeAction` insertion into `1sat` remains ordinary basket insertion under [BRC-147](/tokens/0147.md) and wallet basket-access policy. Fine-grained receive grants are out of scope for this BRC.

### Relationship to plain basket `1sat`

| Operation       | Plain `1sat`            | `p 1sat …` / input labels                            |
| --------------- | ----------------------- | ---------------------------------------------------- |
| Storage of tips | Yes (normative)         | Never                                                |
| `listOutputs`   | Ordinary basket access  | Module view + scope grants                           |
| Spend targeting | Outpoint / local policy | `p 1sat input id <key>` ([BRC-164](/wallet/0164.md)) |

### Out of scope

* Origin / sat-ordering / transfer consensus rules
* Inscription envelope bytes
* Collection membership proofs
* BSV-21 fungible storage and permissions
* Marketplace lock templates
* Labels other than `p 1sat input …` under scheme `1sat`
* Fine-grained receive / `internalizeAction` grants

## Security considerations

* **Tag / grant spoofing** — View matching on tags is only as trustworthy as the holding wallet’s own stamps. Tags are claims; tip→origin proof is [BRC-150](/tokens/0150.md).
* **Scheme bypass** — Filing collectables only in a non-`1sat` basket loses this profile’s storage contract.
* **Payment separation** — Pay / auto-pay MUST NOT cover view under `p 1sat …` or spends authorized via `p 1sat input id …`.
* **Scope ceiling** — Extra caller tags MUST NOT widen past the granted axis values.
* **Approval binding** — After a spend is approved, signatures MUST NOT authorize a different spend set without a new approval.

## Implementations

* **1sat-sdk** — scheme module, input labels, scoped view
* **HandCash Desktop / Mobile** — prior art for item view/send separation (storage `1sat`)

## References

1. [BRC-99: P Baskets](/wallet/0099.md)
2. [BRC-98: P Protocols](/wallet/0098.md)
3. [BRC-100: Wallet Interface](/wallet/0100.md)
4. [BRC-111: Transaction Labels](/wallet/0111.md)
5. [BRC-116: Wallet Permissions and Counterparty Trust](/wallet/0116.md)
6. [BRC-147: 1Sat Ordinals Basket Profile](/tokens/0147.md)
7. [BRC-150: 1Sat Provenance Remittance](/tokens/0150.md)
8. [BRC-164: Output Identity Tags](/wallet/0164.md)
9. [BRC-123: Basket Permission Scheme Registry](/wallet/0123.md) (registry listing deferred; see [Basket Namespace](#basket-namespace))


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://bsv.brc.dev/tokens/0165.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
