Core Package Overview
The @shade402/core package provides the foundational models, schemas, and utilities for the X402 payment protocol.
Installation
pnpm add @shade402/core @solana/web3.js @solana/spl-token zodOverview
The core package includes:
Payment models (
PaymentRequest,PaymentAuthorization)Validation schemas (Zod schemas)
Error classes
Solana payment processor
Encryption utilities
Type definitions
Payment Models
PaymentRequest
Represents a payment request from a server:
import { PaymentRequest } from '@shade402/core';
const paymentRequest = 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), // 10 minutes
nonce: 'unique-nonce',
payment_id: 'unique-payment-id',
resource: '/api/premium-data',
description: 'Premium data access',
});
// Check if expired
if (paymentRequest.isExpired()) {
console.log('Payment request expired');
}
// Convert to dictionary
const dict = paymentRequest.toDict();
// Convert to JSON
const json = paymentRequest.toJSON();
// Create from dictionary
const fromDict = PaymentRequest.fromDict(dict);PaymentAuthorization
Represents proof of payment:
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',
});
// Convert to header value (base64-encoded JSON)
const headerValue = authorization.toHeaderValue();
// Create from header value
const fromHeader = PaymentAuthorization.fromHeader(headerValue);
// Convert to dictionary
const dict = authorization.toDict();
// Convert to JSON
const json = authorization.toJSON();Validation Schemas
Zod schemas for validating payment data:
import {
PaymentRequestDataSchema,
PaymentAuthorizationDataSchema,
} from '@shade402/core';
// Validate payment request data
const result = PaymentRequestDataSchema.safeParse(data);
if (!result.success) {
console.error('Validation errors:', result.error.errors);
} else {
const validData = result.data;
}
// Validate payment authorization data
const authResult = PaymentAuthorizationDataSchema.safeParse(authData);
if (!authResult.success) {
console.error('Validation errors:', authResult.error.errors);
}Error Classes
Shade402 defines specific error types:
import {
PaymentRequiredError,
PaymentExpiredError,
InsufficientFundsError,
PaymentVerificationError,
TransactionBroadcastError,
InvalidPaymentRequestError,
ERROR_CODES,
} from '@shade402/core';
// Error codes reference
console.log(ERROR_CODES.PAYMENT_REQUIRED);
// {
// code: "PAYMENT_REQUIRED",
// message: "Payment is required to access this resource",
// retry: true,
// user_action: "Ensure wallet has sufficient funds and retry"
// }
// Catch specific errors
try {
// Payment operation
} catch (error) {
if (error instanceof PaymentExpiredError) {
console.log('Payment expired:', error.paymentRequest);
} else if (error instanceof InsufficientFundsError) {
console.log('Insufficient funds:', error.requiredAmount);
}
}Solana Payment Processor
Handles Solana blockchain operations:
import { SolanaPaymentProcessor } from '@shade402/core';
import { Keypair } from '@solana/web3.js';
const processor = new SolanaPaymentProcessor(
'https://api.devnet.solana.com',
walletKeypair,
{
defaultDecimals: 6,
memo: 'X402 payment',
}
);
// Create payment transaction
const transaction = await processor.createPaymentTransaction(
paymentRequest,
'0.01',
walletKeypair
);
// Sign and send transaction
const txHash = await processor.signAndSendTransaction(
transaction,
walletKeypair
);
// Verify payment
const isValid = await processor.verifyPayment(
paymentRequest,
authorization
);
// Get token balance
const balance = await processor.getTokenBalance(
walletPublicKey,
tokenMint
);
// Cleanup
await processor.close();Encryption Utilities
RSA encryption for resource field privacy:
import {
encryptResource,
decryptResource,
generateKeyPair,
} from '@shade402/core';
// Generate key pair
const { publicKey, privateKey } = generateKeyPair();
// Encrypt resource
const encrypted = encryptResource('/api/premium-data', publicKey);
// Decrypt resource
const decrypted = decryptResource(encrypted, privateKey);Type Definitions
TypeScript types for all data structures:
import type {
PaymentRequestData,
PaymentAuthorizationData,
SolanaPaymentProcessorOptions,
ErrorDetails,
} from '@shade402/core';Usage Examples
Creating a Payment Request
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),
nonce: crypto.randomUUID(),
payment_id: crypto.randomUUID(),
resource: resource,
description: 'Payment for resource access',
});
}Verifying Payment Authorization
import { PaymentAuthorization, PaymentRequest } from '@shade402/core';
function verifyAuthorization(
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;
}Next Steps
Learn about Payment Models in detail
Explore Solana Processor features
Check out Encryption utilities
Last updated
