Skip to content

x402Serve(): let routes declare the Bazaar discovery extension #217

Closed

Description

@Eras256

Problem

x402Serve() has no way to declare the extensions.bazaar field on a route. Every route it builds is just { description?, accepts } - there's no extensions key anywhere in X402ServeConfig or in the per-route spec, and no passthrough for one.

Consequence: a seller using x402Serve() as documented cannot get their endpoint listed in any x402 Bazaar - not 57Blocks' (reserved, not built yet), not Rail402's (live on testnet today, testnet.rail402.dev/discovery/resources), not Coinbase's CDP Bazaar when that applies here. This isn't specific to one Bazaar implementation - the SDK just never emits the key any of them key off of.

Reference - the correct shape already exists in this repo

packages/agent/src/middleware/x402.ts does this right today, on its own 3 Premium routes (not through x402Serve()):

'GET /signals': {
    description: 'Nirium premium arbitrage signals (x402)',
    mimeType: 'application/json',
    accepts: { scheme: 'exact', price: '$0.02', network, payTo },
    extensions: declareDiscoveryExtension({
        input: { count: 20 },
        inputSchema: { properties: { count: { type: 'integer', maximum: 100 } } },
        output: { example: { signals: [...], meta: {...} } },
    }),
},

declareDiscoveryExtension() comes from @x402/extensions/bazaar and already returns the extension in the right shape ({ bazaar: {...} }) - it's spread into extensions as-is, same level as description/accepts, never nested inside accepts.

Minimal change

In packages/sdk/src/index.ts's x402Serve():

  • Let each route's spec object in X402ServeConfig.routes accept optional input, inputSchema, and output.
  • Load @x402/extensions/bazaar the same way the other @x402/* packages are already lazily loaded (dynamic import(), not require - see the existing load() helper and its ESM/CJS note).
  • When any of input/inputSchema/output is present on a route, call declareDiscoveryExtension({ input, inputSchema, output, bodyType? }) and set the result as that route's extensions.
  • Without those fields, behavior must not change at all - routes that don't opt in stay exactly as they are today (no extensions key, no new required dependency, no behavior change for existing callers).

Done when

  • Tests cover both cases: a route with discovery fields (gets extensions.bazaar) and a route without them (no extensions key, unchanged behavior from today).
  • A real testnet run against Rail402's facilitator (testnet.rail402.dev) where the route actually appears in GET https://testnet.rail402.dev/discovery/resources after a settled payment, with the payment's tx hash included in the PR.
  • The test endpoint for that run uses x402Serve() itself (the fix under test) - not a hand-rolled @x402/express middleware bypassing it. Proving the fix means proving x402Serve() can do this, not that Nirium's internal middleware already could.

Order

After packages/sdk 0.17.0 ships (#213, currently open - don't stack this on top of an unpublished version).

🤖 Generated with Claude Code

Activity

  1. grantfox-oss commented on Nov 7, 2026

    @grantfox-oss

    🎉 This issue has been marked as completed on GrantFox!

    @M0nsxx's PR #262 was approved and merged by @Eras256.

    🏆 @M0nsxx: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (468 total points). Track your full progress on GrantFox.

    👏 Great work, @M0nsxx! Keep contributing to nirium-protocol.

  2. grantfox-oss commented on Nov 7, 2026

    @grantfox-oss

    🎉 This issue has been marked as completed on GrantFox!

    @M0nsxx's PR #267 was approved and merged by @Eras256.

    🏆 @M0nsxx: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (573 total points). Track your full progress on GrantFox.

    👏 Great work, @M0nsxx! Keep contributing to nirium-protocol.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions