Server Path
Lesson 6 of 8
18 min

Lifecycle Hooks & Payment Processing

Learning Objectives

  • Understand the 6 payment lifecycle hooks
  • Add custom validation before verification
  • Log payments to a database
  • Implement recovery logic for failed payments
  • Abort payments based on custom rules

What Are Lifecycle Hooks?

Lifecycle hooks let you run custom code at specific points in the payment flow:

Verification Hooks:

onBeforeVerify - Before verifying payment signature (can abort)
onAfterVerify - After successful verification
onVerifyFailure - When verification fails (can recover)

Settlement Hooks:

onBeforeSettle - Before submitting transaction (can abort)
onAfterSettle - After successful settlement
onSettleFailure - When settlement fails (can recover)

Setting Up Hooks

Add hooks to your resource server using the builder pattern:

typescript
import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server';
import { registerExactEvmScheme } from '@x402/evm/exact/server';

const facilitatorClient = new HTTPFacilitatorClient({
  url: 'https://api.cdp.coinbase.com/platform/v2/x402'
});

const server = new x402ResourceServer(facilitatorClient)
  .register('eip155:84532', new ExactEvmScheme())
  .onBeforeVerify(async (context) => {
    console.log('Before verify hook', context);
    // Return { abort: true, reason: string } to abort
    return undefined;
  })
  .onAfterSettle(async (context) => {
    console.log('After settle hook', context.result.transaction);
    return undefined;
  });

Use Case 1: Custom Validation (Fraud Detection)

Block payments that exceed a maximum amount:

typescript
const server = new x402ResourceServer(facilitatorClient)
  .register('eip155:84532', new ExactEvmScheme())
  .onBeforeVerify(async (context) => {
    // Convert amount from atomic units (e.g., 10000 = 0.01 USDC)
    const amountUSDC = parseInt(context.requirements.amount) / 1e6;

    if (amountUSDC > 1.00) {
      return {
        abort: true,
        reason: 'Payment amount exceeds maximum ($1.00)',
      };
    }

    return undefined; // Continue with verification
  });
When you return { abort: true } from onBeforeVerify, the payment is rejected and the client receives a 402 error.

Use Case 2: Database Logging

Log all successful settlements to your database:

typescript
const server = new x402ResourceServer(facilitatorClient)
  .register('eip155:84532', new ExactEvmScheme())
  .onAfterSettle(async (context) => {
    // Log to database
    await db.payments.create({
      transactionHash: context.result.transaction,
      payer: context.result.payer,
      network: context.result.network,
      amount: context.result.requirements.amount,
      timestamp: new Date(),
    });

    console.log(`✅ Payment logged: ${context.result.transaction}`);
    return undefined;
  });

Use Case 3: Recovery Logic

Recover from settlement failures (e.g., nonce errors):

typescript
const server = new x402ResourceServer(facilitatorClient)
  .register('eip155:84532', new ExactEvmScheme())
  .onSettleFailure(async (context) => {
    console.error('Settlement failed:', context.error.message);

    // If it's a nonce error, we can retry
    if (context.error.message.includes('nonce')) {
      console.log('Nonce error detected, attempting recovery...');

      // Return recovered=true to indicate recovery
      return {
        recovered: true,
        result: {
          success: true,
          transaction: context.signature.payload.txHash || '0x...',
          network: context.requirements.network,
          payer: context.signature.from,
          requirements: context.requirements,
        },
      };
    }

    return undefined; // No recovery
  });
Recovery hooks are powerful - you can retry failed transactions, use alternative settlement methods, or accept payments from backup facilitators.

All Hooks at Once

Here's an example with all hooks:

typescript
const server = new x402ResourceServer(facilitatorClient)
  .register('eip155:84532', new ExactEvmScheme())
  .onBeforeVerify(async (ctx) => {
    console.log('1. Before verification');
    return undefined;
  })
  .onAfterVerify(async (ctx) => {
    console.log('2. After verification ✓');
    return undefined;
  })
  .onVerifyFailure(async (ctx) => {
    console.error('2. Verification failed:', ctx.error);
    return undefined;
  })
  .onBeforeSettle(async (ctx) => {
    console.log('3. Before settlement');
    return undefined;
  })
  .onAfterSettle(async (ctx) => {
    console.log('4. After settlement ✓', ctx.result.transaction);
    return undefined;
  })
  .onSettleFailure(async (ctx) => {
    console.error('4. Settlement failed:', ctx.error);
    return undefined;
  });

Implement Payment Logging with Hooks

Add lifecycle hooks to log payments and implement fraud detection

Requirements:

Rejects high payments

Payments over $0.10 are rejected

Logs settlements

Successful settlements are logged

Handles failures

Settlement failures are caught

Your Solution