Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions typescript/.changeset/tired-days-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@x402/core': patch
---

Added transport context to enrichSettleResponse and enrichPaymentRequiredResponse hooks
1 change: 1 addition & 0 deletions typescript/packages/core/src/http/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export {
x402HTTPResourceServer,
HTTPAdapter,
HTTPRequestContext,
HTTPTransportContext,
HTTPResponseInstructions,
HTTPProcessResult,
PaywallConfig,
Expand Down
18 changes: 18 additions & 0 deletions typescript/packages/core/src/http/x402HTTPResourceServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,16 @@ export interface HTTPRequestContext {
paymentHeader?: string;
}

/**
* HTTP transport context contains both request context and optional response data.
*/
export interface HTTPTransportContext {
/** The HTTP request context */
request: HTTPRequestContext;
/** The response body buffer */
responseBody?: Buffer;
}

/**
* HTTP response instructions for the framework middleware
*/
Expand Down Expand Up @@ -435,11 +445,13 @@ export class x402HTTPResourceServer {
}

// createPaymentRequiredResponse already handles extension enrichment in the core layer
const transportContext: HTTPTransportContext = { request: context };
const paymentRequired = await this.ResourceServer.createPaymentRequiredResponse(
requirements,
resourceInfo,
!paymentPayload ? "Payment required" : undefined,
extensions,
transportContext,
);

// If no payment provided
Expand Down Expand Up @@ -474,6 +486,7 @@ export class x402HTTPResourceServer {
resourceInfo,
"No matching payment requirements",
routeConfig.extensions,
transportContext,
);
return {
type: "payment-error",
Expand All @@ -492,6 +505,7 @@ export class x402HTTPResourceServer {
resourceInfo,
verifyResult.invalidReason,
routeConfig.extensions,
transportContext,
);
return {
type: "payment-error",
Expand All @@ -512,6 +526,7 @@ export class x402HTTPResourceServer {
resourceInfo,
error instanceof Error ? error.message : "Payment verification failed",
routeConfig.extensions,
transportContext,
);
return {
type: "payment-error",
Expand All @@ -526,18 +541,21 @@ export class x402HTTPResourceServer {
* @param paymentPayload - The verified payment payload
* @param requirements - The matching payment requirements
* @param declaredExtensions - Optional declared extensions (for per-key enrichment)
* @param transportContext - Optional HTTP transport context
* @returns ProcessSettleResultResponse - SettleResponse with headers if success or errorReason if failure
*/
async processSettlement(
paymentPayload: PaymentPayload,
requirements: PaymentRequirements,
declaredExtensions?: Record<string, unknown>,
transportContext?: HTTPTransportContext,
): Promise<ProcessSettleResultResponse> {
try {
const settleResponse = await this.ResourceServer.settlePayment(
paymentPayload,
requirements,
declaredExtensions,
transportContext,
);

if (!settleResponse.success) {
Expand Down
1 change: 1 addition & 0 deletions typescript/packages/core/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type { FacilitatorClient, FacilitatorConfig } from "../http/httpFacilitat
export { x402HTTPResourceServer, RouteConfigurationError } from "../http/x402HTTPResourceServer";
export type {
HTTPRequestContext,
HTTPTransportContext,
HTTPResponseInstructions,
HTTPProcessResult,
PaywallConfig,
Expand Down
8 changes: 8 additions & 0 deletions typescript/packages/core/src/server/x402ResourceServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export interface PaymentRequiredContext {
resourceInfo: ResourceInfo;
error?: string;
paymentRequiredResponse: PaymentRequired;
transportContext?: unknown;
}

export interface VerifyContext {
Expand All @@ -65,6 +66,7 @@ export interface SettleContext {

export interface SettleResultContext extends SettleContext {
result: SettleResponse;
transportContext?: unknown;
}

export interface SettleFailureContext extends SettleContext {
Expand Down Expand Up @@ -523,13 +525,15 @@ export class x402ResourceServer {
* @param resourceInfo - Resource information
* @param error - Error message
* @param extensions - Optional declared extensions (for per-key enrichment)
* @param transportContext - Optional transport-specific context (e.g., HTTP request, MCP tool context)
* @returns Payment required response object
*/
async createPaymentRequiredResponse(
requirements: PaymentRequirements[],
resourceInfo: ResourceInfo,
error?: string,
extensions?: Record<string, unknown>,
transportContext?: unknown,
): Promise<PaymentRequired> {
// V2 response with resource at top level
let response: PaymentRequired = {
Expand All @@ -555,6 +559,7 @@ export class x402ResourceServer {
resourceInfo,
error,
paymentRequiredResponse: response,
transportContext,
};
const extensionData = await extension.enrichPaymentRequiredResponse(
declaration,
Expand Down Expand Up @@ -686,12 +691,14 @@ export class x402ResourceServer {
* @param paymentPayload - The payment payload to settle
* @param requirements - The payment requirements
* @param declaredExtensions - Optional declared extensions (for per-key enrichment)
* @param transportContext - Optional transport-specific context (e.g., HTTP request/response, MCP tool context)
* @returns Settlement response
*/
async settlePayment(
paymentPayload: PaymentPayload,
requirements: PaymentRequirements,
declaredExtensions?: Record<string, unknown>,
transportContext?: unknown,
): Promise<SettleResponse> {
const context: SettleContext = {
paymentPayload,
Expand Down Expand Up @@ -762,6 +769,7 @@ export class x402ResourceServer {
const resultContext: SettleResultContext = {
...context,
result: settleResult,
transportContext,
};

for (const hook of this.afterSettleHooks) {
Expand Down
4 changes: 2 additions & 2 deletions typescript/packages/core/src/types/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface ResourceServerExtension {
* Return extension data to add to extensions[key], or undefined to skip.
*
* @param declaration - Extension declaration from route config
* @param context - PaymentRequired context containing response and requirements
* @param context - PaymentRequired context containing response, requirements, and optional transportContext
* @returns Extension data to add to response.extensions[key]
*/
enrichPaymentRequiredResponse?: (
Expand All @@ -30,7 +30,7 @@ export interface ResourceServerExtension {
* Return extension data to add to response.extensions[key], or undefined to skip.
*
* @param declaration - Extension declaration from route config
* @param context - Settlement result context containing payment payload, requirements, and result
* @param context - Settlement result context containing payment payload, requirements, result and optional transportContext
* @returns Extension data to add to response.extensions[key]
*/
enrichSettlementResponse?: (
Expand Down
Loading