Ghost 的 Machine Payments:面向 AI Agent 的按次付费 Markdown 访问机制详解
Ghost 的 Machine Payments面向 AI Agent 的按次付费 Markdown 访问机制详解【免费下载链接】GhostIndependent technology for modern publishing, memberships, subscriptions and newsletters.项目地址: https://gitcode.com/GitHub_Trending/gh/GhostAI Agent 在抓取网页时会受到内容会员门槛的阻隔而传统订阅制又无法覆盖单个 Agent 单次请求一小块内容的场景。Ghost本仓库 README在核心服务中引入了Machine Payments服务通过 Stripe 的 Machine Payments 等源码与配置实现讲解这一功能的协议选择、产品边界、x402 配置方式、发布者前置条件以及适配器驱动的内部架构帮助你理解如何在 Ghost 站点上安全开放机器可付费内容。Machine Payments 要解决什么问题在默认情况下Ghost 的 HTML 主题视图与 Content API 都受会员门槛保护。当 AI Agent爬虫、LLM 数据采集器请求一篇付费文章时只能收到 402/403 一类拒绝信号站点也拿不到任何收益。Machine Payments 的目标是在不动摇会员体系与内容门槛的前提下把单篇付费文章的纯 Markdown 正文作为可售卖资源开放给符合协议的机器客户端。值得注意的是正文明确指出该能力对接的是 Stripe Machine PaymentsMachine Payments ProtocolMPP代码实现位于ghost/core/core/server/services/machine-payments/目录内部按适配器模式拆分为 mpp-adapter.ts 与 x402-adapter.ts 两个支付通道。v1 产品围栏Product FencesREADME 用一组产品围栏精确划定了 v1 的能力边界理解它们是配置与排查的前提。Protocol协议栈主协议为MPPMachine Payments Protocol支持Tempo USDC稳定币与Shared Payment TokensSPT卡 / Link Agent Wallet两类通道。x402Base 上的 USDC经由 ExactEvmScheme作为第二个适配器挂在同一支付授权边界之后不识别该协议的 Agent 直接忽略即可。两条通道都不会改变会员状态。Access model访问模型单次请求的一次性解锁只为这一次请求返回 Markdown 字节。不产生会员会话、不授予层级tier、不影响content-gating与 Portal。Surface暴露面只暴露显式的.mdURL。规范化 HTML URL 永远返回 HTML忽略 Accept 头HTML 主题视图与 Content API 依旧保持会员门槛。Pricing定价全站统一金额。SPT 通道按配置的法币fiat计费需遵守 Stripe 卡片最小金额Tempo 通道以同一最小货币单位金额收取 USDC。对发布者而言crypto 通道应视为USDC而不是链上自有货币。从源码可见定价逻辑在 pricing.ts默认金额DEFAULT_AMOUNT 100最小单位、默认币种DEFAULT_CURRENCY USD实际值由设置项machine_payments_amount与machine_payments_currency决定币种缺省时回退到活动付费 tier 的货币见getDefaultTiersCurrency。forSpt/forTempoUsdc两个方法把最小单位金额换算为majorAmountamount / 100供各自通道使用而assertValidAmount要求金额必须是大于 0 的安全整数。Eligibility内容准入只有满足下述条件的内容可售visibility: paid或visibility: tiers且所有关联 tier 均为付费 tier。仅限免费会员visibility: members的内容不在范围内。这一规则对应共享模块 ghost/core/core/shared/machine-payments.ts 中的isPurchasableEntryvisibility paid直接放行visibility tiers时需要非空的 tiers 数组且每个 tier 的type均为paid。服务在 service.ts 的isPurchasable()中把启用检查与条目准入合并返回。Enablement功能开关Machine Payments 只有在以下条件同时满足时才生效Labs 实验开关machinePayments开启llms_enabled保持开启Agent 发现与.md路由依赖它设置项machine_payments_enabled为trueStripe 已连接。完整判断见isMachinePaymentsEnabledlabs.isSet(machinePayments) settingsCache.get(machine_payments_enabled) true settingsCache.get(llms_enabled) ! false isStripeConnected()。MachinePaymentsService.isEnabled()在每次请求处理入口都会调用它。发布者前置条件Publisher Prerequisites要真正接受机器支付站点需要在站点上配置Stripe Connect或直连密钥。若走SPT / 卡通道发布者需为美国或加拿大法律实体并配置 Stripe 商业档案networkId/ profile id。若走Tempo 稳定币通道需在 Stripe 中获批 Stablecoins and Crypto 支付方式。纽约州企业不可用其他地区可能需要 Stripe 开启访问权限。若走x402Base USDC通道同样需要获批 Stablecoins and Crypto 支付方式Base 存款地址与其他 crypto 通道一致。llms.txt必须保持开启——Agent 发现内容与.md路由都依赖它。从适配器实现看SPT/Tempo 的资金接收依赖 deposit-address-store.ts 的getOrCreateAddress({ network })网络为tempo或base见 mpp-adapter.ts 的config.get(machinePayments:mpp:stripeNetwork)。Stripe 客户端选项集中在 stripe-client-options.ts而 mpp 适配器使用STRIPE_MACHINE_PAYMENTS_API_VERSION对应的 API 版本构造客户端。x402 配置说明x402 通道的默认值瞄准Base 主网eip155:8453通过公共 xpay facilitator 完成真实 USDC 结算——无需账号或 API Key。可通过machinePayments.x402.facilitatorUrl覆盖为其他提供方例如 Coinbase CDP具备托管合规筛查能力但需要 API KeysGhost 目前尚未接入。启动时校验的配置项README 列出的可取值在服务启动时就会被校验x402-adapter.ts 中init()前的配置解析即为此逻辑enabled默认true——只要 Machine Payments 开启x402 通道就随之生效。设为false可在 MPP 保持开启的同时关掉 x402 通道并把x402/*模块请出进程。networkeip155:8453Base 主网或eip155:84532Base Sepolia 测试网。源码校验其必须是 CAIP-2 形式的 EVM 网络eip155:chainId且只允许上述两个值。stripeNetworkbase。facilitatorUrlHTTPS URL主网不能使用 x402.org 的 testnet facilitator源码会校验 URL 必须为 HTTPS并在 Base 主网上拒绝 testnet facilitator 地址。需要留意的是x402/*运行时模块是懒加载的——只在第一次真实 x402 challenge 时载入而不是启动时。这意味着从未收到 x402 支付的站点永远不会承担其 import 成本运行时切换 Machine Payments 开关也无需重启而一旦配置无效x402 通道会在启动时被禁用MPP 仍正常工作。本地开发对接 x402.org 测试网在config.local.json中覆盖为 Base Sepolia testnet facilitator{ machinePayments: { x402: { network: eip155:84532, facilitatorUrl: https://x402.org/facilitator } } }生产环境替换主网 facilitator{ machinePayments: { x402: { facilitatorUrl: https://your-mainnet-facilitator.example/facilitator } } }故障排查如果在 MPP 正常工作时402 响应中却看不到 x402 challenge请检查 Ghost 日志里的 x402 警告——网络或 facilitator 不匹配是最常见原因。这与上述校验逻辑呼应Base 主网eip155:8453搭配公共测试网 facilitator、或 network 值拼错都会在启动/初始化时被标记为无效配置从而静默关闭 x402 通道只保留 MPP。架构边界与协议无关编排器README 的收尾部分交代了最重要的架构原则会员体系与内容门槛保持冻结frozen。适配器只需实现canHandle/challenge/fulfill三个方法。编排器只在一次成功的fulfill之后才加载完整帖子 HTML 并写入machine_payment_events。这套边界在源码中有非常清晰的落地。目录入口 index.js 组装MppAdapterMPP与可选的X402Adapter并注入内容加载器、事件仓库、支付记录器与 Stripe 连接状态仅在服务启用时才在请求路径之外预生成 Tempo/Base 存款地址符合 Stripe 指引失败只退化为仅 SPTchallenge。统一的 PaymentAdapter 契约核心契约定义在 types.tsexport type PaymentAdapter { name?: string; canHandle: (request: Request) boolean; challenge: (request: Request, terms: PaymentTerms) PromiseResponse | null | undefined; fulfill: (request: Request, terms: PaymentTerms) PromiseFulfillment; };PaymentTerms在金额/币种之外携带description、method、mimeType默认text/markdown与urlFulfillment携带结算后的method、reference稳定结算引用由MachinePaymentEvent.create()强制要求、可选的protocol/amount/currency/stripePaymentIntentId/receiptHeaders。以 MPP 适配器为例canHandle通过检查Authorization头是否以Payment开头来识别携带机器支付凭据的请求challenge内部执行tempo.chargeUSDCTEMPO_USDC合约、6 位小数与stripe.chargeSPT卡/Link2 位小数两者都有则用compose同时发起fulfill成功后解析Payment-Receipt头base64url 编码的{method, reference, status, timestamp}JSON见parseReceipt把reference作为幂等键返回并在method stripe时把引用记为stripePaymentIntentId。编排器的请求处理流程MachinePaymentsService.challengeOrFulfill 是主入口处理顺序如下isEnabled()失败 → 404payment-unavailableproblemjson。无可用适配器 → 503payment-unavailable。通过ContentLoader.isPurchasable()做原始模型级别的准入检查不依赖 Content API 序列化避免其剥离免费 tier 导致混合内容的错误 402/403——不可售 → 403payment-forbidden。计算支付条款getTerms→Pricing。找出能处理该凭据的适配器canHandle命中则走#handleFulfill否则对所有适配器并行challengePromise.allSettled把各自返回的 challenge 响应合并为 402 响应保留每个WWW-Authenticate头保证多协议可同时协商。先验证、再结算、后加载的内容交付路径#handleFulfillservice.ts#L203-L292刻意设计了付费不可逆、交付必可达的顺序先调用ContentLoader.loadFullEntry加载完整帖子/页面含作者、标签、tiers确认可交付后再结算避免先扣 Agent 的钱、加载却失败再执行adapter.fulfill凭据被拒403→ 403payment-forbidden随后写入账本machine_payment_events仓库保存{postId, amount, currency, protocol, method, stripePaymentIntentId, reference}。由于 Stripe 幂等键约 24h 过期事件仓库的协议 reference持久检查成为重放请求上创建 PaymentIntent 的闸门若事件已存在created false→ 403凭据已使用仓库写入失败 → 503PaymentRecorder把结算同步到 Stripe 记录最终返回 200Content-Type: text/markdown; charsetutf-8、Cache-Control: private, no-storePAID_MARKDOWN_CACHE_CONTROL、Content-Location并附上适配器返回的收据头。内容加载器 content-loader.ts 是特权解锁路径它直接基于模型查询仅published的 post/page有意绕过 Content API 的会员门槛——因为机器支付解锁的是单次 Markdown 字节交付而不是授予会员身份。同时它包含 URL 可交付性门禁当解析出的绝对 URL 为空或以/404/结尾时判定为不可售杜绝无法送达却发起 challenge/计费。运行时装配与事件模型服务装配见 index.js默认adapters [new MppAdapter(...)]若X402Adapter.init()成功配置有效则追加 x402 适配器MachinePaymentEventRepository与 machine-payment-event.ts 负责事件持久化。事件通过设置缓存读取machine_payments_amount/machine_payments_currency、读取 Stripe profilemachine_payments_stripe_profile_id或machinePayments:mpp:networkId以及machine_payments_secret/machinePayments:mpp:secretKey完成完整计费闭环。小结与适用边界能力边界仅限显式.mdURL 的一次性解锁只针对paid/全付费 tier 内容HTML 页面与 Content API 依旧保持会员门槛支付不改变会员状态、不触碰 Portal。通道选择MPPTempo USDC SPT 卡/Link与 x402Base USDC并存均实现同一canHandle/challenge/fulfill契约x402 可用machinePayments.x402配置独立开/关与切换网络、facilitator。开关与依赖LabsmachinePaymentsllms_enabledmachine_payments_enabled Stripe 已连接四者缺一不可付费 tier 的货币与全站machine_payments_currency决定计费币种。安全与一致先验可交付、再fulfill结算、后写machine_payment_events账本、用协议 reference防重放返回内容一律private, no-store。若你在自建 Ghost 站点上为 AI 内容消费开启按次计费可将以上配置与源码路径README、service.ts、pricing.ts、共享准入逻辑作为第一手依据按本仓库当前实现进行验证与排障。【免费下载链接】GhostIndependent technology for modern publishing, memberships, subscriptions and newsletters.项目地址: https://gitcode.com/GitHub_Trending/gh/Ghost创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考