Skip to content

Harden Stripe limited-preview checkout and reconciliation#109

Merged
dirtybits merged 4 commits into
mainfrom
ops/stripe-test-listing
Jul 17, 2026
Merged

Harden Stripe limited-preview checkout and reconciliation#109
dirtybits merged 4 commits into
mainfrom
ops/stripe-test-listing

Conversation

@dirtybits

@dirtybits dirtybits commented Jul 16, 2026

Copy link
Copy Markdown
Owner

What changed

  • separates Stripe Checkout session creation from webhook processing with an explicit server activation gate
  • requires a production edge-rate-limit acknowledgement and adds per-instance IP/wallet throttles as defense in depth
  • persists Stripe webhook outcomes and operator-review items without storing raw payloads or customer email
  • adds read-only stripe:ops preflight/monitor commands
  • documents the walletless buyer-account and Base off-chain access-grant direction

Why

The wallet-bound Stripe test flow worked end to end, including refund revocation, but production activation still lacked an explicit server gate, durable reconciliation, and checkout abuse controls. Base-listed skills also cannot safely redeem the legacy wallet-pubkey entitlement, so the route continues to reject them until a chain-neutral access-grant seam exists.

Verification

  • npm run format:check
  • npm run lint --workspace @agentvouch/web
  • npm run typecheck --workspace @agentvouch/web
  • npm run test --workspace @agentvouch/web — 107 files / 717 tests
  • npm exec --workspace @agentvouch/web -- next build --webpack
  • npm run stripe:ops --workspace @agentvouch/web -- preflight with placeholder configured values
  • branch-scoped preview reached Ready with both public and server checkout flags enabled for preview only
  • unauthenticated live checkout probe returned the expected wallet-auth 401, proving the server checkout gate was active
  • invalid-signature live webhook probe was rejected with 400
  • post-payment read-only monitor: zero blockers, zero open review items, zero alerts
  • successful $1 Stripe sandbox payment: session cs_test_a1FXhQqfS6rTcdaWg5TnODCP8FvZvl4JafYwY7x2qisD61p72V3jOa5JSn, payment intent pi_3Tu4lNA2jEYsGvGP01cbtB2C
  • buyer raw access changed from 402 to 200; returned content matched SHA-256 99dfd32607fe61c12aeea6ec1c3c59434ab450da5b16f86a93056fbe71cee148
  • receipt and entitlement matched the Stripe payment, amount, buyer, and stripe-mpp-offchain flow; protocol purchase, settlement, EVM, and x402 fields stayed null
  • duplicate checkout returned 409; unrelated wallet remained 402
  • full test refund re_3Tu4lNA2jEYsGvGP0DKG17jv returned buyer access from 200 to 402, set revoked_reason=stripe-refund, and preserved exactly one append-only receipt
  • post-refund monitor remained at zero blockers, zero open review items, and zero alerts
  • no error-level logs for the exact deployment during the smoke window

Live preview

The first read-only monitor found that a new environment has no stripe_webhook_outcomes relation until the first valid webhook bootstraps it. Commit 590efbe makes that read-only pre-first-event state an empty queue without performing DDL. Deployment dpl_4GQ9FUKYq7m2jT543LdzLmjQpuzz passed the full monitor/payment/entitlement/download/refund smoke, and https://agentvouch-stripe-test-listing.vercel.app now points to that verified preview artifact. Commits ceecff4 and 0aa6438 record the evidence in the plan.

Not activated

  • no production Stripe checkout flag change
  • no Vercel Firewall/WAF rule claim
  • no Base mainnet enablement
  • no walletless identity schema migration

Note

Medium Risk
Touches payment checkout, webhook fulfillment/revocation, and entitlement writes; changes are gated and well-tested but errors in persistence or activation could block checkout or delay operator visibility until retries succeed.

Overview
Hardens the wallet-bound Stripe limited preview so checkout activation, fulfillment audit, and operator checks are explicit without turning card sales into protocol purchases.

Checkout vs webhooks: Session creation now requires AGENTVOUCH_STRIPE_CHECKOUT_ENABLED (and in production, AGENTVOUCH_STRIPE_EDGE_RATE_LIMIT_READY as an acknowledgement that edge/WAF rate limiting exists). Webhooks still run when only secrets are set, so refunds, disputes, and retries can converge after checkout is turned off.

Abuse controls: POST /api/stripe/checkout adds per-IP and per-wallet in-memory rate limits (429 + Retry-After) before DB work, as defense in depth beside the production gate.

Durable reconciliation: New stripe_webhook_outcomes table and recordStripeWebhookOutcome persist fulfillment, revocation, ignored, and needs-review outcomes (idempotent on Stripe event_id, no raw payloads). The webhook path records outcomes before ACKing unprocessable events; failure to persist returns 500 so Stripe retries. Partial refunds and unmatched revocations queue for review.

Operator tooling: Read-only npm run stripe:ops (preflight / monitor) reports activation blockers and open review items; monitor treats a missing table as empty (no DDL).

Docs: Stripe policy, test rollout, and feasibility docs updated for the new flags, queue, monitor, and design-only direction for walletless buyer accounts and Base off-chain access grants (not implemented here).

Reviewed by Cursor Bugbot for commit 0aa6438. Bugbot is set up for automated code reviews on this repo. Configure here.

@dirtybits
dirtybits marked this pull request as ready for review July 17, 2026 06:45
@cursor

cursor Bot commented Jul 17, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_7ef81c6b-033b-4d83-a08e-e67aca32189e)

@dirtybits
dirtybits merged commit 2b088b2 into main Jul 17, 2026
4 checks passed
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