
Research
TeamPCP Compromises Telnyx Python SDK to Deliver Credential-Stealing Malware
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.
@x402/extensions
Advanced tools
x402 Payment Protocol Extensions. This package provides optional extensions that enhance the x402 payment protocol with additional functionality like resource discovery and cataloging.
pnpm install @x402/extensions
Extensions are optional features that can be added to x402 payment flows. They allow servers to provide additional metadata and enable facilitators to offer enhanced services like resource discovery and cataloging.
Currently, this package includes:
The Bazaar Discovery Extension enables facilitators to automatically catalog and index x402-enabled resources by following server-declared discovery instructions. This allows users to discover paid APIs and services through facilitator catalogs.
"GET /weather")Declare endpoint discovery metadata in your payment middleware configuration. This helps facilitators understand how to call your endpoints and what they return.
Note: The HTTP method is automatically inferred from the route key (e.g.,
"GET /weather"→ GET method). You don't need to specify it indeclareDiscoveryExtension.
import { declareDiscoveryExtension } from "@x402/extensions/bazaar";
const resources = {
"GET /weather": {
accepts: {
scheme: "exact",
price: "$0.001",
network: "eip155:84532",
payTo: "0xYourAddress"
},
extensions: {
...declareDiscoveryExtension({
input: { city: "San Francisco" },
inputSchema: {
properties: {
city: { type: "string" },
units: { type: "string", enum: ["celsius", "fahrenheit"] }
},
required: ["city"]
},
output: {
example: {
city: "San Francisco",
weather: "foggy",
temperature: 15,
humidity: 85
}
},
}),
},
},
};
For POST, PUT, and PATCH endpoints, specify bodyType to indicate the request body format:
import { declareDiscoveryExtension } from "@x402/extensions/bazaar";
const resources = {
"POST /api/translate": {
accepts: {
scheme: "exact",
price: "$0.01",
network: "eip155:84532",
payTo: "0xYourAddress"
},
extensions: {
...declareDiscoveryExtension({
input: {
text: "Hello, world!",
targetLanguage: "es"
},
inputSchema: {
properties: {
text: { type: "string" },
targetLanguage: { type: "string", pattern: "^[a-z]{2}$" }
},
required: ["text", "targetLanguage"]
},
bodyType: "json",
output: {
example: {
translatedText: "¡Hola, mundo!",
sourceLanguage: "en",
targetLanguage: "es"
}
},
}),
},
},
};
const resources = {
"PUT /api/user/profile": {
accepts: {
scheme: "exact",
price: "$0.05",
network: "eip155:84532",
payTo: "0xYourAddress"
},
extensions: {
...declareDiscoveryExtension({
input: {
name: "John Doe",
email: "john@example.com",
bio: "Software developer"
},
inputSchema: {
properties: {
name: { type: "string", minLength: 1 },
email: { type: "string", format: "email" },
bio: { type: "string", maxLength: 500 }
},
required: ["name", "email"]
},
bodyType: "form-data",
output: {
example: {
success: true,
userId: "123",
updatedAt: "2024-01-01T00:00:00Z"
}
},
}),
},
},
};
const resources = {
"DELETE /api/data/:id": {
accepts: {
scheme: "exact",
price: "$0.001",
network: "eip155:84532",
payTo: "0xYourAddress"
},
extensions: {
...declareDiscoveryExtension({
input: { id: "123" },
inputSchema: {
properties: {
id: { type: "string" }
},
required: ["id"]
},
output: {
example: {
success: true,
deletedId: "123"
}
},
}),
},
},
};
import { paymentProxy, x402ResourceServer } from "@x402/next";
import { HTTPFacilitatorClient } from "@x402/core/http";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { declareDiscoveryExtension } from "@x402/extensions/bazaar";
const facilitatorClient = new HTTPFacilitatorClient({ url: "https://facilitator.x402.org" });
const resourceServer = new x402ResourceServer(facilitatorClient)
.register("eip155:84532", new ExactEvmScheme());
export const proxy = paymentProxy(
{
"/api/weather": {
accepts: {
scheme: "exact",
price: "$0.001",
network: "eip155:84532",
payTo: "0xYourAddress",
},
extensions: {
...declareDiscoveryExtension({
input: { city: "San Francisco" },
inputSchema: {
properties: { city: { type: "string" } },
required: ["city"],
},
output: {
example: { city: "San Francisco", weather: "foggy" }
},
}),
},
},
},
resourceServer,
);
Extract discovery information from incoming payment requests to catalog resources in the Bazaar.
import { extractDiscoveryInfo } from "@x402/extensions/bazaar";
import type { PaymentPayload, PaymentRequirements } from "@x402/core/types";
async function handlePayment(
paymentPayload: PaymentPayload,
paymentRequirements: PaymentRequirements
) {
// Extract discovery info from the payment
const discovered = extractDiscoveryInfo(paymentPayload, paymentRequirements);
if (discovered) {
// discovered contains:
// {
// resourceUrl: "https://api.example.com/weather",
// method: "GET",
// x402Version: 2,
// discoveryInfo: {
// input: { type: "http", method: "GET", queryParams: { city: "..." } },
// output: { type: "json", example: { ... } }
// }
// }
// Catalog the resource in your Bazaar
await catalogResource({
url: discovered.resourceUrl,
method: discovered.method,
inputSchema: discovered.discoveryInfo.input,
outputExample: discovered.discoveryInfo.output?.example,
});
}
}
import { validateDiscoveryExtension, extractDiscoveryInfo } from "@x402/extensions/bazaar";
function processPayment(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements) {
const discovered = extractDiscoveryInfo(paymentPayload, paymentRequirements);
if (discovered && paymentPayload.extensions?.bazaar) {
// Validate the extension schema
const validation = validateDiscoveryExtension(paymentPayload.extensions.bazaar);
if (!validation.valid) {
console.warn("Invalid discovery extension:", validation.errors);
// Handle invalid extension (log, reject, etc.)
return;
}
// Extension is valid, proceed with cataloging
catalogResource(discovered);
}
}
The bazaarResourceServerExtension automatically enriches discovery extensions with HTTP method information from the request context:
import { bazaarResourceServerExtension } from "@x402/extensions/bazaar";
import { x402ResourceServer } from "@x402/core/server";
// The extension helper automatically extracts discovery info
const resourceServer = new x402ResourceServer(facilitatorClient)
.register("eip155:84532", new ExactEvmScheme())
.registerExtension(bazaarResourceServerExtension);
declareDiscoveryExtension(config)Creates a discovery extension object for resource servers.
Parameters:
config.input (optional): Example input values (query params for GET/HEAD/DELETE, body for POST/PUT/PATCH)config.inputSchema (optional): JSON Schema for input validationconfig.bodyType (required for body methods): For POST/PUT/PATCH, specify "json", "form-data", or "text". This is how TypeScript discriminates between query methods (GET/HEAD/DELETE) and body methods.config.output (optional): Output specification
output.example: Example output dataoutput.schema: JSON Schema for output validationNote: The HTTP method is NOT passed to this function. It is automatically inferred from the route key (e.g.,
"GET /weather") or enriched bybazaarResourceServerExtensionat runtime.
Returns: An object with a bazaar key containing the discovery extension.
Example:
const extension = declareDiscoveryExtension({
input: { query: "search term" },
inputSchema: {
properties: { query: { type: "string" } },
required: ["query"]
},
output: {
example: { results: [] }
}
});
// Returns: { bazaar: { info: {...}, schema: {...} } }
extractDiscoveryInfo(paymentPayload, paymentRequirements, validate?)Extracts discovery information from a payment request (for facilitators).
Parameters:
paymentPayload: The payment payload from the clientpaymentRequirements: The payment requirements from the servervalidate (optional): Whether to validate the extension (default: true)Returns: DiscoveredResource object or null if not found.
interface DiscoveredResource {
resourceUrl: string;
method: string;
x402Version: number;
discoveryInfo: DiscoveryInfo;
}
Example:
const info = extractDiscoveryInfo(paymentPayload, paymentRequirements);
if (info) {
console.log(info.resourceUrl); // "https://api.example.com/endpoint"
console.log(info.method); // "GET"
console.log(info.discoveryInfo); // { input: {...}, output: {...} }
}
validateDiscoveryExtension(extension)Validates a discovery extension's info against its schema.
Parameters:
extension: A discovery extension objectReturns: { valid: boolean, errors?: string[] }
Example:
const result = validateDiscoveryExtension(extension);
if (!result.valid) {
console.error("Validation errors:", result.errors);
}
validateAndExtract(extension)Validates and extracts discovery info in one step.
Parameters:
extension: A discovery extension objectReturns: { valid: boolean, info?: DiscoveryInfo, errors?: string[] }
Example:
const { valid, info, errors } = validateAndExtract(extension);
if (valid && info) {
// Use info
}
bazaarResourceServerExtensionA server extension that automatically enriches discovery extensions with HTTP method information from the request context.
Usage:
import { bazaarResourceServerExtension } from "@x402/extensions/bazaar";
const resourceServer = new x402ResourceServer(facilitatorClient)
.registerExtension(bazaarResourceServerExtension);
BAZAARThe extension identifier constant ("bazaar").
import { BAZAAR } from "@x402/extensions/bazaar";
// BAZAAR === "bazaar"
Enable users to discover paid APIs through facilitator catalogs. Servers declare their endpoints, and facilitators index them for easy discovery.
Build tools that automatically generate API documentation or client SDKs from discovery metadata.
Facilitators can maintain catalogs of available paid resources, making it easier for users to find services.
Use discovery schemas to validate API requests and responses during development.
Problem: extractDiscoveryInfo returns null.
Solutions:
declareDiscoveryExtensionpaymentPayload.extensions.bazaar existsoutputSchema)Problem: validateDiscoveryExtension returns valid: false.
Solutions:
inputSchema matches the structure of inputinputSchema.requiredProblem: Discovery info is incomplete.
Solutions:
input and inputSchema are providedbodyType in the configoutput.example is provided if you want output documentationProblem: The HTTP method is missing from discovery info.
Solutions:
bazaarResourceServerExtension which automatically injects the method"METHOD /path" (e.g., "GET /weather")This package supports both x402 v1 and v2:
PaymentPayload.extensions and PaymentRequired.extensionsPaymentRequirements.outputSchema (automatically converted)The extractDiscoveryInfo function automatically handles both versions.
FAQs
x402 Payment Protocol Extensions
The npm package @x402/extensions receives a total of 20,187 weekly downloads. As such, @x402/extensions popularity was classified as popular.
We found that @x402/extensions demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.

Security News
/Research
Widespread GitHub phishing campaign uses fake Visual Studio Code security alerts in Discussions to trick developers into visiting malicious website.