[MPP 2/3] spike(x402): credit-card verifier seam — buildCardRequirement + Stripe cardSettleFunc#606
Open
bussyjd wants to merge 1 commit into
Open
Conversation
…dSettleFunc
Demonstrate how the MPP credit-card method (Stripe stripe.charge) plugs into
the existing x402 verifier without disturbing the crypto path. Grounded on the
real wire from github.com/cp0x-org/mppx/stripe.
- internal/x402/card.go (new):
- buildCardRequirement(): emits the card option as a 402 accepts[] entry,
mirroring the MPP stripe.charge challenge.request (amount in minor units +
currency/decimals + methodDetails{networkId,paymentMethodTypes}).
- cardSettleFunc + stripeCardSettler: charges a buyer's pre-authorized
Shared Payment Token by creating+confirming a Stripe PaymentIntent
(POST /v1/payment_intents, shared_payment_granted_token, confirm=true,
Basic auth, idempotency key) — adapted from mppx.
- parseCardCredential(): decodes the base64 X-PAYMENT card payload {spt,
externalId} (bare or x402-wrapped).
- serveCardGated(): in-process HandleProxy branch — 402 when unpaid, Stripe
charge then proxy when paid, X-PAYMENT-RESPONSE receipt on success.
- internal/x402/config.go: RouteRule.Card (*CardRoute) marks a card route.
- internal/x402/verifier.go: matchPaidRouteFull + HandleProxy dispatch on
rule.IsCard() to the card path, leaving the crypto path byte-for-byte.
Tests (card_test.go): requirement shape, credential parsing (valid/invalid),
Stripe form body, and the serveCardGated gate (402 unpaid / proxy on paid /
402 on settle failure) with a fake settler.
SPIKE scope — clearly marked inline. Not wired end-to-end:
- RouteRule.Card is not yet populated by the ServiceOffer route source
(serviceoffer_source.go) from spec.payment.card — the integration follow-up.
- Stripe secret key read from STRIPE_SECRET_KEY; production must read a
per-offer k8s Secret.
- Charges before serving (mppx Verify semantics); production should split
authorize-before-serve from capture-after-success and persist references.
Stacked on feat/mpp-card-payment-method (the CRD + --pay-with card flag).
3cf7c0e to
f422bb8
Compare
3d8e4e9 to
7e3df3c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #605 (the CRD +
--pay-with cardflag). Both land inintegration/v0.11.0-rc1. Once #605 merges, this auto-retargets to the integration branch.What
A spike showing how the MPP credit-card method (Stripe
stripe.charge) plugs into the existing x402 verifier without disturbing the crypto path. Grounded on the real wire fromgithub.com/cp0x-org/mppx/stripe(the community Go MPP SDK — verified it does implement Stripe charge).internal/x402/card.go(new):buildCardRequirement()— emits the card option as a 402accepts[]entry mirroring the MPPstripe.chargechallenge.request(amount in minor units + currency/decimals +methodDetails{networkId,paymentMethodTypes}).cardSettleFunc+stripeCardSettler— charges a buyer's pre-authorized Shared Payment Token by creating+confirming a Stripe PaymentIntent (POST /v1/payment_intents,shared_payment_granted_token,confirm=true, Basic auth, idempotency key).parseCardCredential()— decodes the base64X-PAYMENTcard payload{spt, externalId}.serveCardGated()— in-processHandleProxybranch: 402 when unpaid, Stripe charge then proxy when paid,X-PAYMENT-RESPONSEreceipt on success.internal/x402/config.go—RouteRule.Card(*CardRoute) marks a card route.internal/x402/verifier.go—matchPaidRouteFull+HandleProxydispatch onrule.IsCard(), leaving the crypto path byte-for-byte.Tests (
card_test.go): requirement shape, credential parsing, Stripe form body, and theserveCardGatedgate (402 unpaid / proxy on paid / 402 on settle failure) with a fake settler.SPIKE scope — clearly marked inline, NOT production-wired
RouteRule.Cardis not yet populated by the ServiceOffer route source (serviceoffer_source.go) fromspec.payment.card— the integration follow-up.STRIPE_SECRET_KEY; production must read a per-offer Kubernetes Secret.Verifysemantics); production should split authorize-before-serve from capture-after-success, add SPT replay defense, and persist references.Adversarial review: 0 confirmed P0/P1; crypto path unchanged. The Stripe SPT field name (
shared_payment_granted_token) matches the mppx reference — validate against a live Stripe "machine payments" account before productionizing.