Skip to content

feat: Allow uploading OpenAPI spec to register x402 resources (#97)#795

Open
tarai-dl wants to merge 1 commit into
Merit-Systems:mainfrom
tarai-dl:rn/openapi-spec-upload
Open

feat: Allow uploading OpenAPI spec to register x402 resources (#97)#795
tarai-dl wants to merge 1 commit into
Merit-Systems:mainfrom
tarai-dl:rn/openapi-spec-upload

Conversation

@tarai-dl
Copy link
Copy Markdown

Summary

This PR implements the ability to register x402 resources from an OpenAPI specification with x-402 extensions, as an alternative to probing endpoints directly.

Closes #97

Changes

New API Endpoint

  • POST /api/x402/registry/register-openapi
    • Accepts an OpenAPI spec (JSON string or parsed object) with x-402 extensions
    • Optional baseUrl parameter to override the spec's servers array
    • Returns registration results with per-endpoint success/failure details

New UI Component

  • OpenAPI Spec tab on the register page (/resources/register)
    • File upload support for .json, .yaml, .yml files
    • Textarea for pasting JSON directly
    • Preview of detected x-402 endpoints before registration
    • Real-time validation of JSON format
    • Results display with per-endpoint success/failure indicators

OpenAPI Parsing

  • Extracts endpoints with x-402 or x402 extension fields
  • Converts OpenAPI parameters/requestBody to x402scan's v1 schema format
  • Supports enabled, price.amount, price.network, price.asset fields

How to Use

Add x-402 extensions to your OpenAPI spec operations:

{
  "paths": {
    "/api/premium-data": {
      "post": {
        "x-402": {
          "enabled": true,
          "price": {
            "amount": "1000",
            "network": "base"
          }
        },
        "requestBody": { ... },
        "responses": { ... }
      }
    }
  }
}

See docs/examples/openapi-x402-example.json for a complete example.

Test Plan

  • Upload an OpenAPI spec with x-402 extensions
  • Verify detected endpoints match spec
  • Register endpoints and verify they appear in resources
  • Test with baseUrl override
  • Test error handling for invalid JSON

Relates to Algora bounty #97 ($100)

Adds ability to register x402 resources from an OpenAPI specification
with x-402 extensions, as an alternative to probing endpoints.

- New API endpoint: POST /api/x402/registry/register-openapi
  Accepts an OpenAPI spec (JSON) with x-402 extensions and registers
  all matching endpoints as x402 resources.
- New UI: OpenAPI Spec tab on the register page
  Users can paste or upload an OpenAPI spec file, preview detected
  endpoints, and register them in bulk.
- Supports x-402 and x402 extension fields on operations
- Extracts input/output schemas from OpenAPI parameters and requestBody
- Docs: Example OpenAPI spec with x-402 extensions

Implements Merit-Systems#97
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 21, 2026

Someone is attempting to deploy a commit to the Merit Systems Team on Vercel.

A member of the Team first needs to authorize it.

@@ -1,40 +1,64 @@
import { Body, Heading } from '@/app/_components/layout/page-utils';
import Link from 'next/link';
'use client';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Page marked as 'use client' but removed metadata export, causing loss of SEO metadata (title and description) for the register page

Fix on Vercel

const op = operation as OpenApiOperation;
const x402Config = op['x-402'] ?? op['x402'];

if (!x402Config?.enabled && !x402Config?.paymentRequirements) continue;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!x402Config?.enabled && !x402Config?.paymentRequirements) continue;
if (!x402Config?.enabled) continue;

Overly permissive condition for detecting x402 resources allows inclusion of endpoints with only paymentRequirements but without enabled: true

Fix on Vercel

if (method.startsWith('x-') || method === 'parameters') continue;
const operation = op as Record<string, unknown>;
const x402 = operation['x-402'] ?? operation['x402'];
if (x402) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (x402) {
const x402Config = x402 as Record<string, unknown> | undefined;
if (x402Config?.enabled || x402Config?.paymentRequirements) {

Form preview and registration handler have inconsistent filtering logic for x-402 endpoints, causing disabled endpoints to appear in preview but fail during registration

Fix on Vercel

const paymentOption = {
protocol: 'x402' as const,
scheme: 'exact' as const,
network: price.network ?? 'base',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x402-enabled endpoints can silently default to 0 payment when price amount is not specified

Fix on Vercel

network: price.network ?? 'base',
amount: String(price.amount ?? '0'),
maxAmountRequired: String(price.amount ?? '0'),
payTo: '',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The payTo field is hardcoded to empty string in OpenAPI x402 handler, preventing payment routing and ownership verification

Fix on Vercel

Comment on lines +81 to +83
const fullUrl = serverUrl
? `${serverUrl.replace(/\/$/, '')}${path}`
: path;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const fullUrl = serverUrl
? `${serverUrl.replace(/\/$/, '')}${path}`
: path;
// Ensure path starts with / for correct URL construction
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
const fullUrl = serverUrl
? `${serverUrl.replace(/\/$/, '')}${normalizedPath}`
: normalizedPath;

URL concatenation assumes paths always start with /, causing malformed URLs when a path lacks the leading slash

Fix on Vercel

'Register x402 resources from an OpenAPI specification with x-402 extensions'
)
.handler(({ body }) =>
handleRegistryRegisterOpenApi(body.spec as string, body.baseUrl)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
handleRegistryRegisterOpenApi(body.spec as string, body.baseUrl)
handleRegistryRegisterOpenApi(body.spec, body.baseUrl)

Incorrect type cast loses type safety when passing body.spec to handler that accepts union type

Fix on Vercel

@@ -0,0 +1,270 @@
import { jsonResponse } from '@/app/api/x402/_lib/utils';
import { registerResource } from '@/lib/resources';
import { convertOpenApiSchemaToV1 } from '@/lib/openapi-to-v1';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { convertOpenApiSchemaToV1 } from '@/lib/openapi-to-v1';

Unused import convertOpenApiSchemaToV1 should be removed from registry-register-openapi.ts

Fix on Vercel

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow uploading of openapi spec for resources

1 participant