Skip to content

Commit 0cacd67

Browse files
fix: dual-scheme UX — dynamic auth hints and body descriptions
- auth_hint now lists all active payment schemes instead of hardcoding L402 - L402 body includes scheme='L402' + description='Buy credits' - IETF Payment body includes scheme='Payment' + description='Pay per request' - Single-rail deployments get a string hint; multi-rail get an array
1 parent ea25671 commit 0cacd67

4 files changed

Lines changed: 23 additions & 4 deletions

File tree

‎src/core/ietf-payment.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ export function createIETFPaymentRail(config: IETFPaymentRailConfig): PaymentRai
225225
},
226226
body: {
227227
ietf_payment: {
228+
scheme: 'Payment',
229+
description: 'Pay per request (IETF standard, stateless)',
228230
method: 'lightning',
229231
intent: 'charge',
230232
payment_hash: invoice.paymentHash,

‎src/core/l402-rail.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export function createL402Rail(config: L402RailConfig): PaymentRail {
5252
},
5353
body: {
5454
l402: {
55+
scheme: 'L402',
56+
description: 'Buy credits \u2014 pay once, reuse for multiple requests',
5557
invoice: bolt11,
5658
macaroon,
5759
payment_hash: paymentHash,

‎src/core/toll-booth.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ describe('agent-friendly 402 body', () => {
829829
description: 'Network intelligence and channel suggestions',
830830
})
831831
expect(body.auth_hint).toBe(
832-
'Pay the invoice, then send header \u2014 Authorization: L402 <macaroon>:<preimage>',
832+
'L402: Pay the invoice, then send \u2014 Authorization: L402 <macaroon>:<preimage>',
833833
)
834834
})
835835

@@ -844,7 +844,7 @@ describe('agent-friendly 402 body', () => {
844844
const body = result.body as Record<string, unknown>
845845
expect(body.booth).toEqual({ name: 'Simple API' })
846846
expect(body.auth_hint).toBe(
847-
'Pay the invoice, then send header \u2014 Authorization: L402 <macaroon>:<preimage>',
847+
'L402: Pay the invoice, then send \u2014 Authorization: L402 <macaroon>:<preimage>',
848848
)
849849
})
850850

‎src/core/toll-booth.ts‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,28 @@ export function createTollBooth(config: TollBoothCoreConfig): TollBoothEngine {
138138
}
139139

140140
// Agent-friendly service metadata (only when serviceName is configured).
141-
// auth_hint is L402-specific; x402/xcashu have different auth mechanisms.
142141
if (config.serviceName) {
143142
challengeBody.booth = {
144143
name: config.serviceName,
145144
...(config.description && { description: config.description }),
146145
}
147-
challengeBody.auth_hint = 'Pay the invoice, then send header \u2014 Authorization: L402 <macaroon>:<preimage>'
146+
147+
// Build auth hints based on active rails
148+
const activeTypes = rails.filter(r => !r.canChallenge || r.canChallenge(normalisedPrice)).map(r => r.type)
149+
const hints: string[] = []
150+
if (activeTypes.includes('l402')) {
151+
hints.push('L402: Pay the invoice, then send \u2014 Authorization: L402 <macaroon>:<preimage>')
152+
}
153+
if (activeTypes.includes('ietf-payment')) {
154+
hints.push('IETF Payment: Pay the invoice, then send \u2014 Authorization: Payment <base64url credential>')
155+
}
156+
if (activeTypes.includes('x402')) {
157+
hints.push('x402: Sign the payment, then send \u2014 PAYMENT-SIGNATURE header')
158+
}
159+
if (activeTypes.includes('xcashu')) {
160+
hints.push('Cashu: Send token via \u2014 X-Cashu header')
161+
}
162+
challengeBody.auth_hint = hints.length === 1 ? hints[0] : hints
148163
}
149164

150165
// Store invoice data from L402 rail if present

0 commit comments

Comments
 (0)