---
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 uses a Nano or verified-email owner Bearer session. Owner Bearer/v1 purchases, tips and x402 payments retain the selected owner. Anonymous website checkout separately supports full login from 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.

## Native purchase sessions

```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. 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

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

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.me/v1/api/overview).

## 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.me/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.
