@agent-score/commerce (top-level: the 2.0 high-level surface) | Checkout orchestrator + CheckoutContext + CheckoutGateConfig + CheckoutValidationError + DiscoveryProbeConfig + MountUcpRoutesOptions + SettleOutcome + MppxComposeOutcome + PricingResult (one config object, hooks for preValidate/computePricing/onSettled/mintRecipients/composeMppx, auto-derived x402+mppx servers, per-framework adapters handleHono/handleExpress/handleFastify/handleNextjs/handleWeb, signed UCP routes via mountUcpRoutes{Hono,Express,Fastify}). Plus computeFirstCheckout — variable-cost pay-per-result helper (compute-first + exact-x402) that works on every exact-mode rail without upto / Permit2 / Settlement-Overrides. createQuoteCache — content-hash quote cache used by the compute-first helper (in-memory default; pass redisUrl for distributed deployments). createDefaultOnDenied({merchantName, supportEmail, supportContext?, walletNotTrustedMessage?, paymentRequiredMessage?}) — canonical onDenied(reason) => {status, body, headers?} factory matching Checkout’s gate hook (handles wallet_signer_mismatch, wallet_not_trusted unfixable fallback, payment_required, token_expired/invalid_credential/api_error). `hasPaymentHeader(req | headers) — discriminator that splits discovery legs (no payment credential → 402) from settle legs (payment-signature/x-payment/Authorization: Payment JWT-BYTES); hasX402Header/hasMppxHeader— granular dispatch helpers (x402 vs MPP credential present).defaultReadOnlyOnDenied(reason)— canonicalonDenied for read-only resource gates (GET /orders/:id): collapses every denial to 401 unauthorized+Cache-Control: no-storewhile still spreadingdenialReasonToBody. extractOwnerScope(headers)(returns optionalwalletAddress+ optionaloperatorTokenHash) — pull canonical owner identity from X-Wallet-Address/X-Operator-Tokenwith safe token hashing. Plus factories:pricingResult(cents → typed PricingResult with optionaldecimalsfor sub-cent precision),validationResponse(4xx envelope per framework),Receipt/ReceiptNextSteps/ProductInfo/ShippingAddress` (canonical 200-receipt shape — universal across goods + API merchants). |
@agent-score/commerce/identity/{hono,express,fastify} | Trust gate middleware: KYC, age, sanctions (account name + signer wallet), jurisdiction. Context-getter pattern: agentscoreGate(opts) middleware + getAgentScoreData(ctx) / getGateDegradedState(ctx) / getGateQuotaInfo(ctx) / getSignerVerdict(ctx) accessors, captureWallet(...). | |
@agent-score/commerce/identity/policy | Per-product compliance helpers: PolicyBlock, buildGateFromPolicy, runGateWithEnforcement, shippingCountryAllowed, shippingStateAllowed, validateShippingAgainstPolicy (one-call country+state validator raising CheckoutValidationError with the canonical envelope on miss). All five are also re-exported at @agent-score/commerce top-level. | |
@agent-score/commerce/identity/{nextjs,web} | Same gate, wrapper pattern: withAgentScoreGate(opts, handler) / createAgentScoreGate(opts) => guard(req). The data + degraded + infraReason fields land directly on the handler arg / guard result (no separate getter). Plus shared captureWallet, getSignerVerdict. | |
@agent-score/commerce/payment | networks, USDC, rails registries; paymentDirective, buildPaymentHeaders (one-call WWW-Authenticate + PAYMENT-REQUIRED bundle), wwwAuthenticateHeader, paymentRequiredHeader, aliasAmountFields (v1↔v2 amount field shim for v1-only x402 parser compat), settlementOverrideHeader, dispatchSettlementByNetwork, extractPaymentSigner (recovers signer from a Request: x402 EIP-3009 payload.authorization.from OR MPP Authorization: Payment BASE64 did:pkh:eip155:CHAIN:ADDR / did:pkh:solana:GENESIS:ADDR source DID, including Solana TransferChecked authority fallback when @solana/kit is installed), extractPaymentSignerFromAuth (header-string variant for callers that already have the Authorization value in hand), detectRailFromHeaders (returns "x402" / "mpp" / null from inbound headers), buildIdempotencyKey; createX402Server, buildX402AcceptsFor402 (one-call helper for the 402-emit path; derives extra.name from the registered scheme so EIP-712 domain matches the on-chain USDC contract), createMppxServer, buildDefaultCheckoutRails({tempo?, x402Base?, solanaMpp?, stripe?}) (canonical 4-rail rails dict factory: flipping network alone derives the right token + chainId — Base Sepolia → Sepolia USDC + chainId 84532, Solana devnet → devnet USDC mint. Solana’s network accepts both CAIP-2 and the raw @solana/mpp form mainnet-beta / devnet / localnet. Explicit overrides always win), buildMppxComposeRails({amountUsd, tempoRecipient?, solanaRecipient?, ...}) (per-call intent factory replacing the hand-rolled [['tempo/charge',{...}],['solana/charge',{...}],['stripe/charge',{...}]] array; auto-handles USD→atomic conversion for Solana; auto-drops stripe/charge when amountUsd < 0.50 since Stripe’s fixed ~0.30feemakessub−50−centchargesunprofitable—sub−50−centAPIspass‘includeStripe:false‘explicitly),‘composeMppxRequest‘(typedwrapperaround‘mppx.compose(...intents)(request)‘returninganarrowed‘MppxComposeResult‘union;replacesthe‘(mppxasany).compose(...)‘castincustom‘composeMppx‘hooks),‘mppxChallengeHeaders‘(one−call‘Object.fromEntries(challenge.headers)‘forthe402path);drop−inx402helpers:‘validateX402NetworkConfig‘(boot−timeguard),‘verifyX402Request‘(parse+validateinboundX−Payment),‘processX402Settle‘(verify−then−settleinonecall),‘classifyX402SettleResult‘(mapsthetaggedsettleresulttoarecommendedHTTPstatus/code/nextstepssomerchantsgetacontrolledenvelopewithoutcouplingtofacilitator−specificerrortext),‘classifyOrchestrationError‘(same‘ClassifiedX402Error‘shapebutforuncaughtexceptionsthrownelsewhereintheorchestration;conservativesubstringfallbackreturns‘null‘forunknownerrorssomerchantsrethrowinsteadofswallowing);‘zeroAmountCarveOut‘(skipCDP/mppxupstreamverify+settlefor0 settles where the upstream rejects value=0 payloads; parses the credential, lifts signer + network, returns a ZeroSettleResult shaped identically to the success path so callers branch on rail, not on result shape); usdToAtomic (BigInt-based USD → atomic value, ROUND_HALF_UP, rejects NaN / negative / infinite — for Tempo / Solana / Base USDC amount construction). | |
@agent-score/commerce/discovery | isDiscoveryProbeRequest, buildDiscoveryProbeResponse (with optional x402Sample for x402-aware crawlers), sampleX402AcceptForNetwork, buildWellKnownMpp, buildWellKnownX402 (x402scan v1 /.well-known/x402 shape: {version: 1, resources: ["METHOD /path"]}), buildLlmsTxt, buildSkillMd (Claude-Skill-compatible /skill.md agent-discovery manifest: strictly agent-facing data only, no internal posture), buildRedemptionSkillMd (delivery-neutral redemption-code template — printed mailers, emailed codes, API trial credits all covered; endpointPath/deliveryIntro/bodyShape/bodyRules/extraRecoveryRows overrides for non-goods shapes), buildMerchantIndexJson + standardEndpointDescriptions({kind}) (canonical / discovery body for goods vs api merchants), buildSuccessNextSteps (universal Passport-active success block), buildAgentscoreOnboardingSteps, agentscoreOpenApiSnippets, siwxSecurityScheme + xPaymentInfoExtension + xGuidanceExtension per the x402scan OpenAPI spec, createBazaarDiscovery; noindexNonDiscoveryPaths (Hono middleware) + noindexNonDiscoveryPathsExpress + noindexNonDiscoveryPathsFastify + wrapNoindexResponse / applyNoindexHeader (Web Fetch + Next.js): emits X-Robots-Tag: noindex on every path except the agent-discovery surfaces. Plus the UCP/JWKS publish surface: buildSignedUcpResponse, buildSignedJwksResponse, wellKnownPreflightResponse, defaultA2aServices, bootstrapUcpSigningKey, framework-neutral SignedDiscoveryResponse + per-framework wrappers signedResponse{Hono,Express,Fastify,Nextjs,Web}. | |
@agent-score/commerce/challenge | buildAcceptedMethods, buildIdentityMetadata (auto-attached by Checkout when wallet header present), buildHowToPay, buildAgentInstructions (auto-emits per-rail compatible_clients; pure helper compatibleClientsByRails(rails) returns the same map for vendors building custom 402s), build402Body, buildPricingBlock (cents → dollar-string; optional shippingCents + discountCents — pass discountCents for redemption codes / coupons so the 402 body surfaces discount alongside subtotal / total for agent-renderable savings; optional decimals for sub-cent precision so per-token / per-byte unit pricing advertises real amounts instead of rounding to two decimals), firstEncounterAgentMemory, Receipt/ReceiptNextSteps/ProductInfo/ShippingAddress types (canonical 200-receipt shape); respond402: drop-in 402 emit that preserves mppx’s WWW-Authenticate and layers x402’s PAYMENT-REQUIRED. buildValidationError: structured 4xx body builder ({error: {code, message}, required_fields?, example_body?, next_steps?, ...extra}) so vendors compose body shapes by name instead of inlining at every validation site. | |
@agent-score/commerce/middleware/{hono,express,fastify,nextjs,web} | Framework-specific rate-limit middleware. Hono / Express / Fastify expose middleware factories (rateLimitHono, rateLimitExpress, rateLimitFastify); Next.js exposes withRateLimit(opts, handler); Web Fetch exposes createRateLimit(opts) => guard(req). Shared options: windowSeconds (default 60), maxRequests (default 60), keyResolver (default first hop of x-forwarded-for), redisUrl (lazy-imports ioredis when set, in-memory Map fallback otherwise), keyPrefix. ioredis is an optional peer dep — install it only for distributed limiting. | |
@agent-score/commerce/stripe-multichain | createMultichainPaymentIntent (returns { paymentIntentId, depositAddresses }; read depositAddresses[network] directly), createPayToAddressFromStripePI({request, amountCents, stripe, piCache, networks?, staticRecipients?, metadata?, orderId?, preferredNetwork?}) — per-order payTo resolver matching Checkout.mintRecipients: on the settle leg, reuses the buyer’s signed-against payTo from the MPP credential (after piCache.hasAddress check OR a staticRecipients match — the static address is always-accepted because the merchant owns it); on the discovery leg, mints a fresh PI for the rails NOT covered by staticRecipients, caches the merged map, registers static addresses with piCache.cacheAddress so verify-leg lookups pass. mintMultichainRecipients({...same opts}) — structured variant returning { recipients, paymentIntentId?, reusedFromCredential } for the full per-rail map (typical multi-rail merchant hook). Use staticRecipients: { solana: '<wallet>' } for low-margin endpoints where Solana per-call ATA rent (~0.50againstMPPspec§13.6)dominatesrevenue—theSDKskipsStripemintingonthatnetwork,reusesthestaticrecipientforever,and(whenpairedwithaone−timeexternalpre−fundingoftherecipient′sUSDCATA)letseverysettlepayonlythe 0.001 per-tx fee. simulateCryptoDeposit, createMppxStripe; createPiCache (TTL’d PI / deposit-address cache, Redis-backed when redisUrl set), simulateDepositIfTestMode (gates on sk_test_ and looks up the PI for you), STRIPE_TEST_TX_HASH_SUCCESS / STRIPE_TEST_TX_HASH_FAILED constants. | |
@agent-score/commerce/api | Everything from @agent-score/sdk re-exported in one place: AgentScore + AgentScoreError, AGENTSCORE_TEST_ADDRESSES + isAgentScoreTestAddress. Don’t add @agent-score/sdk as a separate dep: the two can drift versions. | |
@agent-score/commerce (top-level: publishers + key/token helpers) | Identity-publishing helpers for cross-vendor standards: buildA2AAgentCard (Google A2A v1.0 Signed Agent Card, served at /.well-known/agent-card.json), buildUCPProfile (Google Universal Commerce Protocol, served at /.well-known/ucp). Both return unsigned payloads: vendor signs + publishes. Key + token helpers: loadUCPSigningKeyFromEnv + LoadUCPSigningKeyOptions (cached env-driven loader: reads UCP_SIGNING_KEY_JWK_PRIVATE JSON JWK, detects alg from shape, falls back to ephemeral when unset, sanitizes errors so key bytes never reach logs, concurrent-safe via Promise-pinned cache); hashOperatorToken (sha256 hex of plaintext opc_... — for merchants persisting operator_token_id to their own DB without ever storing the plaintext); extractOwnerScope(headers) (returns optional walletAddress + optional operatorTokenHash) (canonical owner-identity extractor for caller-scoped resource queries — reads X-Wallet-Address / X-Operator-Token, hashes the token so plaintext never leaves the request). | |