Skip to content

Stripe web2 payments: feasibility note + Tier 1 prototype (WIP)#9

Open
dirtybits wants to merge 6 commits into
mainfrom
claude/stripe-integration-feasibility-FVSUA
Open

Stripe web2 payments: feasibility note + Tier 1 prototype (WIP)#9
dirtybits wants to merge 6 commits into
mainfrom
claude/stripe-integration-feasibility-FVSUA

Conversation

@dirtybits

Copy link
Copy Markdown
Owner

Summary

Exploratory work assessing how hard it would be to accept "web2-style" card
payments (Stripe) alongside the existing USDC-native, on-chain purchase flow.
Splits the problem into two tiers and ships a prototype for the easy one.

  • docs/STRIPE_FEASIBILITY.md — analysis: an easy entitlement-only tier
    vs. the hard tiers that preserve on-chain economics (author proceeds escrow
    • 60/40 author/voucher split, disputes, refunds). Includes effort
      estimates, the three core obstacles, and open product questions.
  • Tier 1 prototype (feature-flagged, off-chain entitlement only):
    • web/lib/stripe.ts — Stripe REST API + node:crypto webhook signature
      verification. No new npm dependency, so the lockfile/build are
      untouched.
    • POST /api/stripe/checkout — creates a Checkout Session from the
      listing's price_usdc_micros.
    • POST /api/stripe/webhook — mints an entitlement via the existing
      recordUsdcPurchaseReceipt on checkout.session.completed.

Deliberately out of scope (documented in the note)

No fiat→USDC conversion, no on-chain settlement, no author proceeds / voucher
reward funding, no real buyer identity (synthetic stripe:<id> placeholder),
no refund/chargeback handling or reconciliation. These are the Tier 2/3 hard
parts the note specifies.

Verification

  • tsc --noEmit is clean for all four added files. (The single reported
    error is pre-existing and unrelated: @/app/favicon.png in
    AppNavbar.tsx.)
  • Full next build could not complete in the sandbox only because it cannot
    reach Google Fonts — an environment limitation, not a code issue.

WIP / exploratory — intended for implementation and review agents to evaluate.


Generated by Claude Code

dirtybits added 2 commits May 31, 2026 20:57
Adds docs/STRIPE_FEASIBILITY.md analyzing the effort to accept card
payments alongside the USDC-native on-chain flow, split into an easy
entitlement-only tier and the hard on-chain-economics tiers.

Ships a feature-flagged Tier 1 prototype (off-chain entitlement only,
no on-chain settlement or author/voucher payout):
- web/lib/stripe.ts: REST + node:crypto webhook verification, no new deps
- POST /api/stripe/checkout: create a Checkout Session from listing price
- POST /api/stripe/webhook: mint entitlement on checkout.session.completed

WIP / exploratory; identity, refunds, reconciliation and on-chain
settlement are explicitly out of scope and documented as such.
Correctness:
- Bind the exact USDC-micros amount into the signed checkout message so a
  price change between page load and checkout invalidates the auth instead
  of silently charging the new price.
- Reject non-finite auth timestamps in verifyWalletSignature (a string
  timestamp NaN'd the age check and bypassed the 5-minute replay window).
- Webhook now ACKs (200 + logged reason) permanently-unprocessable events
  instead of returning 4xx/5xx that Stripe retries for ~3 days; unpaid
  `checkout.session.completed` (async payment ordering) is acked too.
- Webhook never overwrites an existing entitlement: late/duplicate Stripe
  deliveries ack `alreadyEntitled` instead of nulling on-chain purchase
  provenance through the last-receipt-wins upsert.
- Exclude Stripe receipts from the public activity feed (protocol metrics
  must exclude stripe-mpp-offchain).
- buyerHasPurchased on skill detail also checks the DB entitlement for
  on-chain-listed skills, so card buyers stop seeing purchase buttons.
- Refuse card checkout for Base protocol listings (their download gate only
  honors chain-qualified purchase state — the pubkey-keyed entitlement was
  unredeemable) and for prices below Stripe's $0.50 minimum.
- Keep off-chain sentinels out of chain-qualified address columns:
  recordUsdcPurchaseReceipt only writes buyer/recipient/asset addresses
  when the matching chain context is known.
- Gate all card-checkout UI/copy on a server-provided stripeCheckoutEnabled
  flag; Stripe-less deployments show the original honest listing-required
  messaging instead of a button that always 501s.
- Stripe success redirect handling is one-shot (strips the query param) and
  retries the entitlement refresh to cover webhook lag.

Cleanup:
- Verify checkout auth before any DB round trip on the public endpoint.
- Extract the triplicated Pay by Card button; drop dead guards.
- Replace hand-rolled form encoding with URLSearchParams; base-URL fallback
  reuses NEXT_PUBLIC_APP_URL before the request origin.

Docs: sync skill.md, ROADMAP (payment-rail sequencing 2026-07-01, Base
canonical frontrunner), STRIPE_FEASIBILITY, and the test-mode rollout
checklist with the new behavior. Tests updated and extended.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Step 1 of the live-money hardening: make card-funded entitlements revocable
so operator-covered refunds/disputes have a real off-switch.

- Schema: usdc_purchase_entitlements gains revoked_at / revoked_reason.
- Entitlement gates (hasUsdcPurchaseEntitlement, chain-qualified variant)
  exclude revoked rows, so Sign & Download and buyerHasPurchased stop
  honoring refunded purchases everywhere.
- Webhook handles charge.refunded (full) and charge.dispute.created by
  revoking the entitlement whose current backing receipt is that payment;
  partial refunds are logged only, and a refund landing after a newer
  purchase (different payment ref) deliberately leaves it untouched.
- Replay safety: a redelivered checkout.session.completed for a refunded
  payment stays revoked; a genuinely new payment (new payment intent)
  re-mints, and any newer receipt clears revoked_at in the upsert.
- Docs: rollout checklist (webhook event subscriptions, refund negative
  tests), MPP policy, and feasibility note updated to the shipped behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant