Payment Models

Detailed documentation for payment models in the core package.

PaymentRequest

The PaymentRequest class represents a payment request from a server.

Properties

class PaymentRequest {
  maxAmountRequired: string;    // Maximum payment amount required
  assetType: string;            // Asset type (e.g., "SPL")
  assetAddress: string;         // Token mint address or "native" for SOL
  paymentAddress: string;       // Recipient wallet address
  network: string;              // Blockchain network identifier
  expiresAt: Date;              // Payment request expiration time
  nonce: string;                // Unique nonce for this request
  paymentId: string;            // Unique payment identifier
  resource: string;             // Resource path being requested
  description?: string;         // Optional description
}

Creating a Payment Request

import { PaymentRequest } from '@shade402/core';

const request = new PaymentRequest({
  max_amount_required: '0.01',
  asset_type: 'SPL',
  asset_address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
  payment_address: 'RecipientWalletAddress',
  network: 'solana-devnet',
  expires_at: new Date(Date.now() + 600000),
  nonce: crypto.randomUUID(),
  payment_id: crypto.randomUUID(),
  resource: '/api/premium-data',
  description: 'Premium data access',
});

Methods

isExpired()

Check if the payment request has expired:

if (request.isExpired()) {
  console.log('Payment request expired');
}

toDict()

Convert to dictionary format:

const dict = request.toDict();
// {
//   max_amount_required: '0.01',
//   asset_type: 'SPL',
//   ...
// }

toJSON()

Convert to JSON string:

const json = request.toJSON();
// '{"max_amount_required":"0.01",...}'

fromDict()

Create from dictionary:

const request = PaymentRequest.fromDict({
  max_amount_required: '0.01',
  asset_type: 'SPL',
  // ... other fields
});

Validation

The PaymentRequest constructor validates all fields using Zod schemas:

try {
  const request = new PaymentRequest(data);
} catch (error) {
  if (error instanceof InvalidPaymentRequestError) {
    console.error('Invalid payment request:', error.message);
  }
}

PaymentAuthorization

The PaymentAuthorization class represents proof of payment.

Properties

class PaymentAuthorization {
  paymentId: string;            // Links to payment request
  actualAmount: string;         // Amount actually paid
  paymentAddress: string;       // Recipient address
  assetAddress: string;         // Token mint address
  network: string;              // Blockchain network
  timestamp: Date;              // When payment was made
  signature: string;            // Transaction signature
  publicKey: string;            // Payer's public key
  transactionHash?: string;     // Transaction hash (optional)
}

Creating a Payment Authorization

import { PaymentAuthorization } from '@shade402/core';

const authorization = new PaymentAuthorization({
  payment_id: 'unique-payment-id',
  actual_amount: '0.01',
  payment_address: 'RecipientWalletAddress',
  asset_address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
  network: 'solana-devnet',
  timestamp: new Date(),
  signature: 'transaction-signature',
  public_key: 'PayerPublicKey',
  transaction_hash: 'transaction-hash',
});

Methods

toHeaderValue()

Convert to header value (base64-encoded JSON):

const headerValue = authorization.toHeaderValue();
// Use in X-Payment-Authorization header

fromHeader()

Create from header value:

const headerValue = req.headers['x-payment-authorization'];
const authorization = PaymentAuthorization.fromHeader(headerValue);

toDict()

Convert to dictionary:

const dict = authorization.toDict();

toJSON()

Convert to JSON string:

const json = authorization.toJSON();

Validation

The PaymentAuthorization constructor validates all fields:

try {
  const authorization = new PaymentAuthorization(data);
} catch (error) {
  if (error instanceof InvalidPaymentRequestError) {
    console.error('Invalid authorization:', error.message);
  }
}

Usage Examples

Creating Payment Request on Server

import { PaymentRequest } from '@shade402/core';

function createPaymentRequest(
  amount: string,
  paymentAddress: string,
  tokenMint: string,
  resource: string
): PaymentRequest {
  return new PaymentRequest({
    max_amount_required: amount,
    asset_type: 'SPL',
    asset_address: tokenMint,
    payment_address: paymentAddress,
    network: 'solana-devnet',
    expires_at: new Date(Date.now() + 600000), // 10 minutes
    nonce: crypto.randomUUID(),
    payment_id: crypto.randomUUID(),
    resource: resource,
    description: 'Payment for resource access',
  });
}

Parsing Payment Authorization on Server

import { PaymentAuthorization } from '@shade402/core';

function parseAuthorization(req: Request): PaymentAuthorization {
  const headerValue = req.headers['x-payment-authorization'] as string;
  
  if (!headerValue) {
    throw new Error('Missing payment authorization');
  }

  return PaymentAuthorization.fromHeader(headerValue);
}

Validating Payment Authorization

function validateAuthorization(
  request: PaymentRequest,
  authorization: PaymentAuthorization
): boolean {
  // Check payment ID matches
  if (authorization.paymentId !== request.paymentId) {
    return false;
  }

  // Check amount is sufficient
  if (parseFloat(authorization.actualAmount) < parseFloat(request.maxAmountRequired)) {
    return false;
  }

  // Check addresses match
  if (authorization.paymentAddress !== request.paymentAddress) {
    return false;
  }

  // Check token mint matches
  if (authorization.assetAddress !== request.assetAddress) {
    return false;
  }

  // Check network matches
  if (authorization.network !== request.network) {
    return false;
  }

  return true;
}

Type Definitions

interface PaymentRequestData {
  max_amount_required: string;
  asset_type: string;
  asset_address: string;
  payment_address: string;
  network: string;
  expires_at: Date | string;
  nonce: string;
  payment_id: string;
  resource: string;
  description?: string;
}

interface PaymentAuthorizationData {
  payment_id: string;
  actual_amount: string;
  payment_address: string;
  asset_address: string;
  network: string;
  timestamp: Date | string;
  signature: string;
  public_key: string;
  transaction_hash?: string;
}

Next Steps

Last updated