---
title: Reader Payments and Gift Access
description: Buy and tip using native HTTP sessions or resource-bound x402 proofs with private wallet signing.
navigationTitle: Reader Payments and Gift Access
---

# Reader payments and gift access

A reader can use a Nano, explicit Base SIWX or verified-email owner Bearer session. Owner Bearer/v1 purchases, tips and x402 payments retain the selected owner. First USDC purchases in the browser can use a [cookie-only guest checkout](#guest-usdc-checkout), without a separate login signature; verified payment admits a payment-grade renewable owner session. Explicit owner API and native MCP buyers log in through SIWX and use an owner Bearer; standard USDC x402 buyers can use the wallet-only flow below. Anonymous website Nano checkout also recognizes the confirmed paying wallet. Publishing keys cannot buy, tip, claim or manage gift links. Signing happens in the reader's wallet; Subnano never receives a seed or private key. 1 XNO = 10^30 raw; 1 USDC = 10^6 micro-units. Keep every amount as an exact integer string in its own asset/network.

## Purchase agreement, delivery consent and confirmation

`GET /api/legal/purchase-terms` returns the current version, full Terms, consent text and public marketplace operator. Every new original Purchase saves its complete agreement, original creator beneficiary, asset/network, integer price and commission. Later Terms, Post edits, guest promotion and recovery cannot rewrite it. The creator is the seller; Subnano is the marketplace. An order confirmation is not a VAT invoice or verified creator legal identity.

For express buyer consent to immediate digital delivery and acknowledgement of losing the applicable withdrawal right when delivery begins, send `X-Subnano-Purchase-Consent: <original terms version>` when issuing the quote or preparing its original signing guard. General login Terms, wallet connection, a spending grant or payment signature do not provide this consent. A stale version conflicts; review the **original** agreement rather than today's Terms for an old operation. Consent cannot be added after submission/payment.

The custom header is optional for ordinary owner-Bearer API/x402 clients. Stock `@x402/fetch` can still pay without a separate legal handshake; Subnano does **not** claim loss of withdrawal rights where valid consent/confirmation is missing. The optional `subnano-purchase-contract` extension uses x402's `info`/`schema` shape to advertise the original purchase ID, version, SHA-256 and document location. It does not change `accepts`, EIP-3009 or financial `Payment-Response`. It is Subnano metadata, not the official signed Offer and Receipt extension; a payment signature does not cryptographically sign the Terms.

Browser checkout uses an unchecked per-purchase choice. MCP stops before signing until the buyer expressly authorizes `accept_immediate_delivery: true`. Neither adds a wallet login signature. Original recovery, signed operations and previous purchased reads never require new consent or an enabled issuance gate.

```http
GET /api/v1/purchases/<original purchaseId>/receipt
Authorization: Bearer <original ownerAccessToken>
```

JSON returns `documentText`/`sha256`, `termsVersion`, `consentText`, `consentAcceptedAt` and, once canonically paid, `receiptText`/`receiptSha256`. Save those exact UTF-8 bytes. Hashes detect changed bytes; they are not server signatures. `?format=pdf` returns an inline `application/pdf` containing the original financial details, consent and full saved Terms, with the exact UTF-8 records embedded. **View receipt** opens it and **Save receipt** downloads it after an explicit click, both after purchase and under **Settings → Purchases**. No file is downloaded automatically during payment or recovery. The legacy `?format=html` attachment remains available. MCP saves the structured documents in its existing private operation store and returns them through purchase status. A current Terms link alone is not a confirmation; availability of a receipt is not evidence that a buyer retained a copy.

Receipt access uses existing original-owner/private-browser-checkout authority. Public hashes, copied proofs/documents or order IDs cannot grant access. Historical paid orders without evidenced Terms return 404 rather than fabricated consent; content and payment recovery still work. Legal copy retrieval can retry independently of the paid order and never creates another charge.

For questions, complaints or an applicable withdrawal request, contact `hello@subnano.me` with the original order ID. There is no in-app withdrawal/refund workflow. Cookie writes require exact website origin. Documents remain available during an issuance pause.

## Native purchase sessions

This family issues Nano sessions. For USDC use the [Base x402 flow](#base-usdc-purchases) or [guest checkout](#guest-usdc-checkout) below.

```http
POST /api/v1/purchases/create
Authorization: Bearer <ownerAccessToken>
Idempotency-Key: <persisted request identity>
Content-Type: application/json

{"postId":"<published Post UUID>"}
```

Success returns `{purchase,statusUrl,ephemeral_address:{id,ephemeral_address},reused}`. Save the native purchase ID and quote before paying. New Nano allocations last five minutes, including converted offers on USDC-anchored Posts; originals retain their saved expiry. The `purchase` projection includes native `amount`/status, expiry, buyer, incoming/receive hashes and safe settlement metadata; it excludes private financial snapshots. Exact final `amount_paid_raw` appears when confirmed. `statusUrl` is the existing `/api/purchases/:purchaseId`, which accepts the same owner session.

V1 issuance requires an `Idempotency-Key` of 1–255 trimmed nonwhitespace characters. The native request identity and payment allocation commit together. An exact replay returns the same persisted allocation and re-registers its monitor address even after an earlier registration response was lost. Reuse with different intent returns `409`; do not issue another payment after an uncertain response. Existing pending allocations also retain their original amount/routing. New allocations require actual-beneficiary receiving readiness and payment monitor availability.

`GET /api/v1/purchases/:purchaseId` reads only the owned purchase. `POST .../:purchaseId/cancel` cancels a pending session and returns `{message,purchase:{id,status}}`. It retains allocated context and monitoring because already broadcast funds can arrive later. `POST .../:purchaseId/claim` on a paid/swept registered-owned purchase returns `{session:null,purchase}`; it cannot switch to another wallet-recognized identity.

Purchase `status=paid` establishes the entitlement; `receive_status` and `receive_block_hash` track platform receipt. Creator earnings/payout are read separately. Never charge again because payout is blocked or the creator's wallet has not received its send.

The anonymous website uses `/api/purchases/session` with `{purchaseId}` and its original checkout cookie. Confirmed payer evidence can promote that guest or select an existing Nano account, returning a browser wallet projection and an HttpOnly refresh cookie. Sharing the QR deliberately permits that payer account to become the checkout browser owner. Explicit Bearer/v1 callers retain their selected identity and receive `session:null`. Owner agents can complete the entire normal journey through the v1 family.

## Post and Comment tips

Tips remain Nano-only. A Base-only creator without Nano payout setup cannot receive Nano tips.

| Action       | Post path                            | Comment path                                             |
| ------------ | ------------------------------------ | -------------------------------------------------------- |
| POST issue   | `/api/v1/posts/:postId/tips/session` | `/api/v1/posts/:postId/comments/:commentId/tips/session` |
| GET state    | `.../tips/:sessionId`                | `.../tips/:sessionId`                                    |
| PATCH cancel | `.../tips/:sessionId`                | `.../tips/:sessionId`                                    |
| POST claim   | `.../tips/session-claim`             | `.../tips/session-claim`                                 |

Issue uses the owner and a required persisted request key. Post body is `{amountNano,amountMode?}`: `preset` is default, positive XNO rounded to six decimal places with at least 0.000001 XNO; `custom` stores no fixed suggested amount and may omit `amountNano`. Comment body is `{amountNano,recipientKind?}` with `post_author` default or `comment_author`. Tipping the Post author through a Comment requires that you authored that Comment; tipping the Comment author cannot tip yourself or a deleted Comment. Existing access/visibility restrictions remain.

A new session checks the actual beneficiary's saved address. A ready Comment author can receive a tip even when an unrelated legacy Post author needs setup. Replays recover the original session before today's address/publication check; they never reroute an allocation.

Issue/read returns `{session,...}`; the complete session is `{id,status,postId,commentId?,statusUrl,tipperProfileId,authorProfileId,tipRecipientKind?,amountMode?,suggestedAmountRaw,ephemeralAddress,amountReceivedRaw,authorAmountRaw,platformFeeRaw,expiresAt,paidAt,cancelledAt,expiredAt,receiveBlockHash,authorTransferHash,platformTransferHash,meta}`. Amounts/hashes/times remain null when unproven. The canonical status URL is the existing unversioned tip read path. `paidAt` is incoming tip acceptance, not creator send completion; author/commission transfer hashes and owner earnings show the separate legs.

`meta.receipt_continuation_completed=false` means incoming money is accepted while receipt activity is still being completed or retried. Keep polling the same status URL until it becomes `true`, then inspect or claim that same checkout receipt. Never send again because this continuation is pending. Legacy receipts may omit the marker.

Cancel PATCH accepts `{status:"cancelled"}` and returns `{session:{id,status,cancelledAt}}`; noncancellable/foreign session returns `404`. Late payments remain accounted after cancel/expiry. Claim POST accepts `{tipId}`; a paid registered-owned tip returns `{session:null,tip}`. For browser cookies, the canonical anonymous `.../tips/session-claim` atomically logs the browser into the confirmed paying wallet and returns a browser wallet projection; its refresh credential stays in an HttpOnly cookie. Sharing a QR therefore allows the payer account to become the browser owner. An explicit Bearer/v1 caller retains its own account and receives `session:null`. No caller can provide a target owner ID.

## x402 protected reads and assets

Use the existing public `GET /.well-known/x402`, `/.well-known/x402/posts`, `/.well-known/railhint.json` and `/llms.txt`. Browse `GET /api/posts` first. `OPTIONS /api/posts/:postId/access` and `/api/assets/:assetId` describe payment-header/CORS behavior. These discovery routes require no Publishing key.

`GET /api/posts/:postId/access` returns free/owned/entitled content or HTTP `402` plus base64 JSON `Payment-Required`. Inspect scheme `exact`, network `nano:mainnet`, asset `XNO`, raw amount, destination, resource and expiry against your wallet policy before signing. A registered owner's first valid payment proof is evaluated under that same owner even before entitlement exists. A quote tied to another caller is rejected before broadcast.

The `Payment-Signature` JSON uses `x402Version:2`, the original `resource`, the exact `accepted` offer and `payload.block`. Set `block.link` to the accepted `payTo` address's 64-hex public key, as in a canonical signed Nano state block. The server derives the destination from this signed field. `block.link_as_account` is optional; if supplied, it must encode the same destination (either `nano_` or `xrb_` prefix). A conflicting or malformed address is rejected. Do not put an address in `block.link`: SDKs may accept an address while constructing a block, but the signed wire block must contain hexadecimal `link`. Signature, work, exact amount, original quote and confirmed replay checks still apply. See the [exact payload schema](https://docs.subnano.ai/openapi/agent-platform-v1.json) and [Nano block specification](https://docs.nano.org/integration-guides/the-basics/#block-format).

Retry the exact resource with base64 JSON `Payment-Signature`; `X-Payment` is an identical compatibility alias. Read `post.content.paid.markdown` or `.tiptap`; protected `/api/assets/:assetId` belonging to the same Post accepts the same settled proof, without another purchase. Decode `Payment-Response` and compare success, transaction, payer, amount and network with the accepted quote. Read failures do not prove a send was not broadcast: replay the same proof/reconcile the wallet frontier before signing again. An expired unbroadcast quote can be re-quoted under the same spending policy. Server invalid work/proof returns `400` and must not broadcast.

Existing owner `/api/posts/:postId/purchased-content` and `/api/posts/by-identifier/:handle/:postId/purchased-content` expose the same entitlement rather than a separate purchase engine. Public Profile/summary/activity/follow reads stay on canonical discovery paths listed in [overview](https://docs.subnano.ai/v1/api/overview).

[Private ZIP attachments](https://docs.subnano.ai/v1/api/attachments) expose ready-file metadata before payment. ZIP `402` responses quote the original `/api/posts/:postId/access` resource: settle that endpoint first, then replay the identical proof for all matching files. An unsettled asset proof returns `403 post-payment-unsettled` and performs no settlement. Verify each file's SHA-256 and length. After withdrawal, existing native buyers and already-settled proofs retain saved ZIP downloads; free/gift access and new purchases close. The runnable ZIP example covers creator recovery and purchase-once/download.

## Base USDC purchases

A first stateless x402 purchase needs no Subnano login or account credential. GET `/api/posts/:postId/access?rail=usdc` with an ordinary x402 client, inspect the `402` quote, sign the native USDC authorization locally and resubmit `Payment-Signature` to that same resource. Neither cookies, a custom checkout header, an `Idempotency-Key` nor a prepare-signing call is mandatory. An optional request key replays the initial quote within its original IP/resource scope. Save the original quote and exact signed proof before submission; after uncertainty, retry that same proof rather than creating another payment. Confirmed anonymous proofs replay only their original Post; later Post/ZIP access can use the resource-only SIWX extension below. No account session or cookie is issued by this payment.

USDC quotes include the standard `extensions.bazaar` declaration for `GET /api/posts/:postId/access`: query `rail=usdc`, a concrete public Post ID, and a JSON output schema for `post.content.paid.markdown`. `routeTemplate` consolidates concrete Post URLs into one endpoint catalog entry. Service name, description and topical tags are server-declared; buyer-supplied metadata cannot change the declaration sent to the facilitator. Worker retries rebuild it from the same frozen Post/resource. A Bazaar-capable facilitator catalogs the endpoint after successful payment; deployment and a real catalog lookup must verify the live listing. No private account/asset route, credentials or actual paid content are included in the discovery example.

A pending anonymous submission returns `409 usdc-settlement-pending` with `retryUrl`; replay the exact original `Payment-Signature` there. Explicit owner submissions retain their owned `statusUrl`. If the signature was saved before quote expiry but a provider/request failure prevented the first disclosure checkpoint, the same held anonymous authorization can obtain that checkpoint until its original `validBefore`. No new signature, quote extension or account login is needed.

For an authenticated purchase, use an existing owner session or obtain one through [explicit SIWX login](https://docs.subnano.ai/v1/api/wallet-signatures#base-siwx-login-and-wallet-linking). The wallet paying USDC must be a proved Base identity of that same owner. Explicit owner API purchases retain their selected owner; stateless first purchases use the wallet-only flow above. Login, payment authorization and returning resource-read proof are distinct. The browser adapter uses the same owner, original purchase and entitlement as this Bearer API. Browser availability depends on the separate admission and new-issuance gates; payment remains EOA-only.

```http
GET /api/posts/<postId>/access?rail=usdc
Authorization: Bearer <owner accessToken>
Idempotency-Key: <saved purchase request identity>
```

An eligible new purchase returns `402` with `Payment-Required`: x402 v2 `exact`, `network:"eip155:8453"`, native Circle token `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`, integer micro-unit `amount`, frozen `payTo`, resource and `extra:{name:"USD Coin",version:"2",quoteId}`. New quotes last five minutes (300 seconds). Browser and MCP prepared guards fix EIP-3009 `validBefore` to that quote expiry. The stock `@x402/evm` 2.28.0 exact client uses its actual signing time plus 300 seconds and does not require a prepare-signing call. Retain that original signed deadline for recovery; older originals keep their saved validity. Enforce the exact network/token, maximum budget, destination, resource and expiry before signing. Discovery prices are indicative; the saved quote is payable truth. Failed reference-rate refreshes retain the last good rates and provider timestamps; converted offers require both timestamps at most 60 minutes old, with operator incidents after 30 minutes. New USDC offers require 0.25 USDC when the Post has a pending or ready ZIP, and 0.10 USDC for text. This includes USDC amounts derived from an XNO anchor; Nano has no monetary floor. The offer’s `minimumAtomic` and `reason` explain an unavailable rail. Removing all pending and ready ZIPs restores the text minimum. Existing quotes, purchases, ZIP reservations and financial snapshots keep their original terms. Off, stale conversion, below-floor or missing payout setup does not silently raise a creator's price.

Use the installed `@x402/core`, `@x402/evm` exact client and `@x402/fetch` with the same owner's Bearer and stable `Idempotency-Key`. Sign EIP-3009 `TransferWithAuthorization` locally. Save the original quote ID and exact base64 JSON `Payment-Signature` before sending it to the quoted Post endpoint. The payer, native-token EIP-712 domain, amount, authorization nonce and saved quote must match. The server persists the original authorization before facilitator settlement. The stock SIWX hook can try resource-read proof before payment; it cannot establish owner login for you.

Successful incoming receipt verification returns the Post and `Payment-Response`. Inspect the original `/api/purchases/<quoteId>` with the same owner Bearer. Buyer `status:"paid"` grants Post/attachment access independently of `payout.state`. A 0.10 USDC sale owes the creator 85,000 micro-units; Subnano's 15% commission pays its own operating costs. Creator amounts round up to the next micro-unit where necessary and the platform receives the exact remainder.

`409 usdc-settlement-pending` supplies `purchaseId`, original `statusUrl` and `retry:"original"`; retry that status or the identical authorization. Provider timeout, a lost reply, quote expiry or Post withdrawal can still lead to original receipt acceptance. Never sign another payment while the original may have succeeded. A hash is a receipt candidate until the two configured RPCs agree on sealed canonical inclusion and exact token/authorization evidence. Safe and finalized progression are separate. `410 usdc-quote-expired` means an unclaimed quote expired or the original authorization was safely closed; deliberately obtain a new quote with a new Idempotency-Key under the same spending policy. A closed status has `settlement.state:"expired"` and `retry:null`. Merely reaching the quote deadline, or seeing no transaction hash, does not establish safe closure.

Attempt closure depends on what Subnano holds. An unprepared quote closes at expiry. A prepared guard whose signature Subnano never received closes from database facts at quote expiry plus 60 seconds; choosing Nano closes either of these unsigned tiers immediately and proceeds. A held or forwarded signature closes only after both configured RPCs prove it unused at an agreed finalized block beyond its original `validBefore` plus the 60-second margin, or after receipt acceptance. Subnano checkpoints the observation block before facilitator verification or settlement. Quote expiry alone never closes a held signature. Provider absence or disagreement cannot prove nonpayment or a reorganization; the closed original remains recorded.

`USDC_NEW_ISSUANCE_ENABLED` controls new USDC quotes (`503 usdc-issuance-disabled`); `USDC_BROWSER_ADMISSION_ENABLED` independently controls browser login/link and eligibility for a new browser checkout. Both default on; an explicit false pauses the corresponding capability. Missing receiving address, either Base RPC URL or facilitator credentials forces both gates off. Valid provider/payment configuration and the database rollout are still required. Original saved recovery, creator payouts and purchased reads remain available to the existing owner even when both are off. Base Sepolia is an isolated validation configuration: network `eip155:84532`, token `0x036CbD53842c5426634e7929541eC2318f3dCF7e`, EIP-712 name `USDC`, version `2`. Never reuse mainnet terms/signatures for it.

## Guest USDC checkout

The browser retains cookie-only guest checkout. A verified payment resolves the network-qualified paying wallet and saves the purchase to its existing or newly admitted account without a separate login signature. An already selected durable owner keeps that account; payment cannot link a wallet or merge accounts.

Same-origin `POST /api/usdc/guest-checkout` with `{postId}` installs an HttpOnly checkout cookie. The browser quotes, prepares, submits and recovers through same-origin `POST /api/posts/:postId/usdc-checkout`. Acceptance installs the HttpOnly wallet-refresh cookie and returns only the browser session projection, never a refresh secret. Source-bound session claim/recovery has five-minute windows; `sessionRecovery:"login-required"` means log in with the same wallet to read the saved purchase, without paying again.

Browser guest credentials remain cookie-only. Stateless API purchases use the ordinary x402 exact scheme and a server-private checkout binding, with no custom guest header or headless session pair. The native MCP buyer retains explicit owner login. Explicit SIWX login and ordinary owner refresh still return their documented private token pairs. A copied proof, wallet address or transaction hash cannot claim another checkout's account.

Payment-derived owner sessions support reading, purchasing, history, publishing and account settings without another wallet confirmation. Mutations retain active owner/session checks, new-wallet signatures, mailbox verification and deletion freshness/handle checks. See [session assurance](https://docs.subnano.ai/v1/api/authentication#session-assurance).

## Browser checkout and interrupted signing

Browser cookie owners and private guest checkouts use same-origin `POST /api/posts/:postId/usdc-checkout` with `action:"lookup"`, `"quote"`, `"prepare-signing"` or `"submit"`. Quote uses a saved `Idempotency-Key`; prepare supplies only the original purchase ID and payer. An existing owner needs a proved linked payer; a guest proves the payer through the verified payment. Submit supplies only that ID and the 65-byte payment signature. The server derives the canonical GET resource and reconstructs the exact original authorization. Explicit invalid Bearers never fall back to a browser cookie, and legacy cookie-authorized GET paths cannot allocate or settle payments. Owned GET reads remain available.

Before the browser requests a spendable signature, Subnano saves the exact non-spendable payer, token/network, nonce, amount, destination and validity in the existing original incoming operation. A lost preparation response, wallet callback, reload or missing local storage therefore retains the same purchase and terms. Owner/Post lookup finds the selected Nano or USDC purchase on another device. A pending Nano selection prevents switching to a new USDC intent.

Wallet connection and rail selection do not prepare a guard; preparation happens only on explicit Pay. The wallet prompt waits until the original authorization deadline. An unsigned guard can close from database facts at quote expiry plus 60 seconds, or immediately when choosing Nano. Restart applies the same unsigned closure rule and allocates nothing. Once Subnano holds the signature, only receipt acceptance or paired finalized unused proof beyond its original validity plus margin permits closure. Browser storage holds correlation metadata only; it does not store payment signatures. Login, connection and payment are separate approvals, and rejecting payment does not log the owner out.

## Returning owner and SIWX reads

After a confirmed purchase, use the owner Bearer for the Post and every saved attachment URL. No new payment proof or charge is needed. Protected asset routes cannot submit or settle a USDC purchase; return to the original Post resource to recover payment. After withdrawal, the existing buyer and author retain saved content/ZIP access while free/gift access and new purchases close.

Without a current owner token, request the exact saved read URI with `siwx=read` added, preserving its other query parameters. `401` with `data.code:"siwx-read-required"` contains `data.extensions["sign-in-with-x"]` (`info`, `supportedChains`, `schema`). Generate a stock `createSIWxPayload`/`encodeSIWxHeader` EIP-191 proof for that exact URI and retry it with the `Sign-In-With-X` header. Its nonce lasts five minutes and is consumed once; a failed/lost content response needs a fresh challenge. This proves the entitled wallet for that resource and creates no account session or cookie. Invalid explicit Bearers fail even alongside a valid read proof. Public transaction hashes and published payment authorizations cannot retrieve private bytes.

Legitimate repeat reads remain free. Process-local burst limits are 120 deliveries per IP and 60 per owner per minute; honor `429` and `Retry-After`. These limits reset across instances and do not represent a lifetime quota or a global cost cap. Verify every ZIP's saved SHA-256 and length.

## Author Gift Links

The owner of a Post can `GET`, `POST` or `DELETE /api/v1/posts/:postId/gift-link`. POST requires a published paywalled Post and gets or creates one saved active link; repeated POST returns the same token. GET returns `{status,active,eligible,url,createdAt,disabledAt}` with `none`, `disabled`, `active` or `dormant`. A saved link is dormant while its Post is ineligible. POST active result omits `eligible`. DELETE returns `{status,active:false,disabledAt}`.

Read protected content through `/api/posts/:postId/access?gift=<token>`; pass the same grant to allowed assets/identifier content routes. Gift access is temporary, resource-bound and revocable; it does not create a permanent purchase entitlement. Disabled/dormant/foreign tokens cannot grant access. Tokens/URLs are secrets: these responses use private no-store, and clients must exclude them from telemetry.

## Financial completion

Incoming acceptance, platform receive, reader entitlement, creator confirmed send and creator spendability are different outcomes. [Owner financial history](https://docs.subnano.ai/v1/api/finance) shows every accepted source even if no outgoing row exists. Prepared signed blocks and expected hashes support safe same-block recovery; `paid` proves a creator send confirmation, not the creator's receive. Local fault tests mock Nano; documentation and local HTTP tests alone are not real-chain settlement proof.

## Browser continuation across official and retained hosts

When the authenticated owner encounters an unresolved native Purchase on the other application host, browser checkout shows safe status and an explicit continuation to the original host. That encounter does not restart, expire, reconcile, sign, settle or replace the Purchase. Authenticate independently on the original host and continue its exact saved operation. A guest keeps only the original browser and host capability; public branding does not transfer it. Existing receipts, resources, quote terms and signed authorizations retain their original destinations.
