Catalog npm
PACKAGE EXPLORERView in registry

555x402-agg

npm

Solana payment aggregation SDK with intelligent facilitator routing and instant USDC settlement

aggregatorcryptofacilitatorpaymentssolanausdcweb3x402
Versions collected1
Direct dependencies4From release 0.1.0
Last observed20 Oct, 20:25 UTC

README

Current package documentation

@555x402/agg

Solana payment aggregation SDK with intelligent facilitator routing and instant USDC settlement

npm version License: MIT

Overview

The AGG (Aggregator) SDK enables developers to accept Solana payments through a unified API that automatically routes to the optimal payment facilitator based on latency, fees, and health. Supports USDC and SOL with instant settlement and webhook notifications.

Features

  • ✅ Intelligent Routing: Automatically selects best facilitator (PayAI, Conduit, Internal)
  • ✅ Instant Settlement: Sub-second transaction confirmation on Solana
  • ✅ Low Fees: 0.5-1% facilitator fees + gasless
  • ✅ Webhook Notifications: HMAC-signed callbacks for payment status
  • ✅ TypeScript: Full type safety with comprehensive type definitions
  • ✅ Framework Agnostic: Works with Next.js, Express, Fastify, vanilla Node
  • ✅ Idempotent: Built-in deduplication via idempotency keys

Installation

npm install @555x402/agg
# or
pnpm add @555x402/agg
# or
yarn add @555x402/agg

Quick Start

Basic Usage

import { AggClient } from '@555x402/agg';

const client = new AggClient(
  'your-api-key',
  'https://agg.rendernet.work/pub/v1' // optional, defaults to production
);

// Verify and settle a payment
const result = await client.verifyAndSettle(
  paymentHeaderB64, // from X-Payment header
  {
    amount: 1.5,  // $1.50 USDC
    mint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'), // USDC
    recipient: new PublicKey('555Tm1cfV52SrBQmnxXiHMUMrpci8miW3CkLP1Qbmtd7')
  }
);

console.log('Payment settled:', result.id);

Express.js Example

import express from 'express';
import { AggClient } from '@555x402/agg';
import { PublicKey } from '@solana/web3.js';

const app = express();
const agg = new AggClient(process.env.AGG_API_KEY!);

app.post('/premium-api', async (req, res) => {
  const paymentHeader = req.headers['x-payment'] as string;
  
  if (!paymentHeader) {
    return res.status(402).json({ 
      error: 'Payment required',
      price: { amount: 0.01, asset: 'USDC' }
    });
  }
  
  try {
    await agg.verifyAndSettle(paymentHeader, {
      amount: 0.01,
      mint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
      recipient: new PublicKey(process.env.TREASURY_WALLET!)
    });
    
    // Payment verified and settled - serve the content
    res.json({ data: 'premium content' });
  } catch (error) {
    res.status(402).json({ error: 'Payment verification failed' });
  }
});

app.listen(3000);

Next.js API Route

// app/api/protected/route.ts
import { AggClient } from '@555x402/agg';
import { PublicKey } from '@solana/web3.js';
import { NextRequest, NextResponse } from 'next/server';

const agg = new AggClient(process.env.AGG_API_KEY!);

export async function GET(request: NextRequest) {
  const paymentHeader = request.headers.get('x-payment');
  
  if (!paymentHeader) {
    return NextResponse.json(
      { error: 'Payment required', price: { amount: 0.05, asset: 'USDC' }},
      { status: 402 }
    );
  }
  
  try {
    const payment = await agg.verifyAndSettle(paymentHeader, {
      amount: 0.05,
      mint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
      recipient: new PublicKey(process.env.TREASURY_WALLET!)
    });
    
    return NextResponse.json({ 
      data: 'protected data',
      paymentId: payment.id 
    });
  } catch {
    return NextResponse.json(
      { error: 'Invalid payment' },
      { status: 402 }
    );
  }
}

API Reference

Class: AggClient

Constructor

new AggClient(apiKey: string, apiBase?: string)

Parameters:

  • apiKey (string, required): Your 555x402 API key from the dashboard
  • apiBase (string, optional): API base URL. Defaults to https://agg.rendernet.work/pub/v1

Example:

const client = new AggClient('pk_live_abc123');

// Or for devnet testing:
const devClient = new AggClient('pk_test_xyz789', 'https://agg-devnet.rendernet.work/pub/v1');

Methods

verifyAndSettle(paymentHeaderB64, expected): Promise<PaymentResult>

Verifies a payment header and settles the transaction through the optimal facilitator.

Parameters:

  • paymentHeaderB64 (string): Base64-encoded payment header from X-Payment HTTP header
  • expected (object):
    • amount (number): Expected payment amount in token units (e.g., 1.5 for $1.50 USDC)
    • mint (PublicKey): Token mint address (USDC, SOL, etc.)
    • recipient (PublicKey): Wallet address to receive funds

Returns: Promise

interface PaymentResult {
  id: string;              // Payment order ID
  status: string;          // 'pending' | 'confirmed' | 'failed'
  txSignature?: string;    // Solana transaction signature (if confirmed)
  facilitator?: string;    // Which facilitator processed the payment
}

Throws:

  • PaymentVerificationError - Invalid payment header or signature
  • InsufficientAmountError - Payment amount less than expected
  • NetworkError - API unreachable or timeout

Example:

try {
  const result = await client.verifyAndSettle(
    'eyJhbGc...', // from req.headers['x-payment']
    {
      amount: 2.50,
      mint: new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
      recipient: new PublicKey('555Tm1cfV52SrBQmnxXiHMUMrpci8miW3CkLP1Qbmtd7')
    }
  );
  
  console.log(`Payment ${result.id} settled via ${result.facilitator}`);
  console.log(`Tx: ${result.txSignature}`);
} catch (error) {
  if (error instanceof InsufficientAmountError) {
    console.error('Payment too low:', error.message);
  }
}
getStatus(paymentId): Promise<PaymentStatus>

Retrieves the current status of a payment.

Parameters:

  • paymentId (string): Payment order ID from verifyAndSettle response

Returns: Promise

interface PaymentStatus {
  id: string;
  status: 'pending' | 'confirmed' | 'failed';
  amount: number;
  mint: string;
  recipient: string;
  sender: string;
  txSignature?: string;
  createdAt: string;      // ISO 8601 timestamp
  settledAt?: string;     // ISO 8601 timestamp
}

Example:

const status = await client.getStatus('pay_abc123xyz');

if (status.status === 'confirmed') {
  console.log(`Payment confirmed in tx: ${status.txSignature}`);
} else if (status.status === 'pending') {
  console.log('Waiting for confirmation...');
}

Webhook Verification

verifyWebhookSignature(body, timestamp, signature, secret): boolean

Verifies HMAC signature of webhook payloads from the AGG service.

Parameters:

  • body (any): Raw request body (string or object)
  • timestamp (string): Value from X-555-Timestamp header
  • signature (string): Value from X-555-Signature header (format: sha256=<hex>)
  • secret (string): Your webhook secret

Returns: boolean - true if signature valid, false otherwise

Example (Express):

import { verifyWebhookSignature } from '@555x402/agg';

app.post('/webhooks/agg', express.json(), (req, res) => {
  const timestamp = req.headers['x-555-timestamp'] as string;
  const signature = req.headers['x-555-signature'] as string;
  const secret = process.env.WEBHOOK_SECRET!;
  
  if (!verifyWebhookSignature(req.body, timestamp, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process webhook
  const { event, data } = req.body;
  
  if (event === 'agg.payment.settled') {
    console.log(`Payment ${data.id} settled to ${data.to}`);
    // Update your database, send confirmation email, etc.
  }
  
  res.sendStatus(200);
});

Webhook Payload Format:

{
  "event": "agg.payment.pending | agg.payment.settled | agg.payment.failed",
  "data": {
    "id": "pay_abc123",
    "status": "settled",
    "amount": 1500000,
    "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "to": "555Tm1cfV52SrBQmnxXiHMUMrpci8miW3CkLP1Qbmtd7",
    "from": "sender_wallet_address",
    "txSignature": "4vJ9J..."
  }
}

Advanced Usage

Polling for Settlement

async function waitForSettlement(paymentId: string, maxWaitMs = 30000): Promise<PaymentStatus> {
  const start = Date.now();
  
  while (Date.now() - start < maxWaitMs) {
    const status = await client.getStatus(paymentId);
    
    if (status.status === 'confirmed') {
      return status;
    }
    
    if (status.status === 'failed') {
      throw new Error('Payment failed');
    }
    
    await new Promise(r => setTimeout(r, 1000)); // Poll every second
  }
  
  throw new Error('Settlement timeout');
}

Custom Facilitator Selection

The AGG router automatically selects the optimal facilitator, but you can influence routing by registering preferred facilitators for your recipient wallet.

Contact support to configure facilitator preferences.

Error Handling

import { AggClient, PaymentError } from '@555x402/agg';

try {
  await client.verifyAndSettle(...);
} catch (error) {
  if (error instanceof PaymentError) {
    switch (error.code) {
      case 'INVALID_SIGNATURE':
        // Payment header signature doesn't match
        break;
      case 'INSUFFICIENT_AMOUNT':
        // Payment amount < expected
        break;
      case 'INVALID_RECIPIENT':
        // Recipient mismatch
        break;
      case 'FACILITATOR_UNAVAILABLE':
        // All facilitators down (rare)
        break;
      case 'NETWORK_ERROR':
        // Solana RPC or API unreachable
        break;
    }
  }
}

Token Support

Supported Tokens

TokenMint AddressDecimals
USDC (mainnet)EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v6
USDC (devnet)4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU6
SOL (wrapped)So111111111111111111111111111111111111111129

Amount Conversion

USDC uses 6 decimals:

  • $1.00 = 1000000 micro-units
  • $0.01 = 10000 micro-units

Helper (built-in):

import { usdToMicroUsdc, microUsdcToUsd } from '@555x402/agg/utils';

const microUnits = usdToMicroUsdc(2.50);  // 2500000
const usd = microUsdcToUsd(2500000);      // 2.5

Examples

1. Pay-Per-Request API

import { AggClient } from '@555x402/agg';
import { PublicKey } from '@solana/web3.js';

const agg = new AggClient(process.env.AGG_API_KEY!);
const USDC_MINT = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');

app.get('/api/premium-data', async (req, res) => {
  const payment = req.headers['x-payment'] as string;
  
  if (!payment) {
    return res.status(402).json({
      error: 'Payment required',
      price: { amount: 0.10, asset: 'USDC' }
    });
  }
  
  try {
    const result = await agg.verifyAndSettle(payment, {
      amount: 0.10,
      mint: USDC_MINT,
      recipient: new PublicKey(process.env.TREASURY!)
    });
    
    // Log for analytics
    console.log(`Payment ${result.id} from ${result.sender}`);
    
    // Serve premium content
    const data = await fetchPremiumData();
    res.json({ data });
  } catch (error) {
    res.status(402).json({ error: 'Invalid payment' });
  }
});

2. Webhook Handler (Async Settlement Notification)

import express from 'express';
import { verifyWebhookSignature } from '@555x402/agg';

const app = express();

app.post('/webhooks/payments', 
  express.raw({ type: 'application/json' }), 
  async (req, res) => {
    const signature = req.headers['x-555-signature'] as string;
    const timestamp = req.headers['x-555-timestamp'] as string;
    const body = req.body.toString();
    
    // Verify signature
    if (!verifyWebhookSignature(
      body, 
      timestamp, 
      signature, 
      process.env.WEBHOOK_SECRET!
    )) {
      return res.status(401).send('Invalid signature');
    }
    
    const payload = JSON.parse(body);
    
    // Handle events
    switch (payload.event) {
      case 'agg.payment.pending':
        console.log(`Payment ${payload.data.id} pending...`);
        break;
        
      case 'agg.payment.settled':
        console.log(`Payment ${payload.data.id} confirmed!`);
        console.log(`Tx: ${payload.data.txSignature}`);
        
        // Update your database
        await db.payments.update({
          where: { id: payload.data.id },
          data: { 
            status: 'settled',
            txSignature: payload.data.txSignature 
          }
        });
        
        // Send confirmation email
        await sendEmail(payload.data.to, 'Payment received!');
        break;
        
      case 'agg.payment.failed':
        console.error(`Payment ${payload.data.id} failed`);
        // Handle failure (refund, notify user, etc.)
        break;
    }
    
    res.sendStatus(200);
  }
);

3. Polling Pattern (No Webhooks)

async function processPaymentWithPolling(paymentHeader: string) {
  // Initiate settlement
  const result = await agg.verifyAndSettle(paymentHeader, {
    amount: 1.00,
    mint: USDC_MINT,
    recipient: TREASURY
  });
  
  console.log(`Payment ${result.id} initiated...`);
  
  // Poll for confirmation
  for (let i = 0; i < 30; i++) {
    await new Promise(r => setTimeout(r, 1000)); // Wait 1s
    
    const status = await agg.getStatus(result.id);
    
    if (status.status === 'confirmed') {
      console.log(`Confirmed! Tx: ${status.txSignature}`);
      return status;
    }
    
    if (status.status === 'failed') {
      throw new Error('Payment failed');
    }
  }
  
  throw new Error('Timeout waiting for confirmation');
}

4. Username-Based Payments

// Pay to a username instead of wallet address
const result = await agg.verifyAndSettle(paymentHeader, {
  amount: 5.00,
  mint: USDC_MINT,
  recipient: '@alice'  // AGG resolves username to wallet
});

Configuration

Environment Variables

# Required
AGG_API_KEY=pk_live_your_api_key_here

# Optional
AGG_API_BASE=https://agg.rendernet.work/pub/v1  # defaults to prod
WEBHOOK_SECRET=whsec_your_webhook_secret         # for webhook verification

API Keys

Get your API key from the 555x402 Dashboard.

Key types:

  • pk_live_* - Production keys
  • pk_test_* - Devnet/testnet keys

Rate Limits

  • Default: 20 requests/second per API key
  • Burst: 40 requests
  • Contact support for higher limits

Webhook Configuration

Setting Up Webhooks

  1. Go to Dashboard → Settings → Webhooks
  2. Add your endpoint URL
  3. Copy the webhook secret
  4. Test with the webhook tester

Webhook Security

Always verify signatures:

import crypto from 'crypto';

function verifyWebhook(body: string, timestamp: string, signature: string, secret: string): boolean {
  const sig = signature.replace(/^sha256=/, '');
  const hash = crypto.createHash('sha256').update(body).digest();
  const mac = crypto.createHmac('sha256', secret)
    .update(timestamp)
    .update('.')
    .update(hash)
    .digest('hex');
  
  try {
    return crypto.timingSafeEqual(
      Buffer.from(mac, 'hex'),
      Buffer.from(sig, 'hex')
    );
  } catch {
    return false;
  }
}

Replay attack protection:

  • Check X-555-Timestamp is within 5 minutes of current time
  • Store processed webhook IDs to prevent duplicates

Webhook Retry Logic

Failed webhooks are retried with exponential backoff:

  • Attempt 1: Immediate
  • Attempt 2: 60s later
  • Attempt 3: 5min later
  • Attempt 4: 15min later
  • Attempt 5: 1hr later
  • Attempt 6: 6hr later
  • After 6 attempts: moved to dead-letter queue

Testing

Unit Tests

npm test

Integration Tests

Set up a test recipient wallet and API key:

import { AggClient } from '@555x402/agg';

describe('AGG Integration', () => {
  const client = new AggClient(
    process.env.AGG_TEST_API_KEY!,
    'https://agg-devnet.rendernet.work/pub/v1'
  );
  
  it('should settle USDC payment', async () => {
    const result = await client.verifyAndSettle(mockPaymentHeader, {
      amount: 0.01,
      mint: DEVNET_USDC_MINT,
      recipient: TEST_WALLET
    });
    
    expect(result.status).toBe('pending');
    expect(result.id).toBeDefined();
  });
});

Troubleshooting

Common Errors

"Invalid API key"

  • Verify your API key is correct
  • Check you're using the right environment (live vs test keys)

"Payment verification failed"

  • Ensure payment header is base64-encoded
  • Check the signature matches the payment data
  • Verify sender has sufficient balance

"No healthy facilitator available"

  • Rare; indicates all payment facilitators are down
  • Retry after 30 seconds
  • Check status page

"Amount mismatch"

  • Payment amount doesn't match expected amount
  • Ensure you're using correct decimal places (USDC = 6, SOL = 9)

Debug Mode

Enable detailed logging:

const client = new AggClient(apiKey, apiBase, { debug: true });

This logs all API requests/responses to console.

Type Definitions

Full TypeScript definitions are included. Import types:

import type { 
  PaymentResult, 
  PaymentStatus, 
  Expected,
  WebhookPayload 
} from '@555x402/agg';

Changelog

v0.1.0 (2025-11-11)

  • Initial release
  • verifyAndSettle and getStatus methods
  • Webhook signature verification
  • TypeScript support

Contributing

Contributions welcome! Please read CONTRIBUTING.md first.

License

MIT © 555x402

Support


Built with ❤️ for the Solana ecosystem

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.0Registry latest11 Nov 20254

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
render-network-os/555x402-agg-sdk

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 20:25 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:c05d72331c2cbd1b2618f584a946c789098e0bc9f912ce50c44d5a62d650e2f2