Observed since 20 Oct, 20:25 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Solana payment aggregation SDK with intelligent facilitator routing and instant USDC settlement
Solana payment aggregation SDK with intelligent facilitator routing and instant USDC settlement
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.
npm install @555x402/agg
# or
pnpm add @555x402/agg
# or
yarn add @555x402/agg
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);
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);
// 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 }
);
}
}
AggClientnew AggClient(apiKey: string, apiBase?: string)
Parameters:
apiKey (string, required): Your 555x402 API key from the dashboardapiBase (string, optional): API base URL. Defaults to https://agg.rendernet.work/pub/v1Example:
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');
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 headerexpected (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 fundsReturns: 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 signatureInsufficientAmountError - Payment amount less than expectedNetworkError - API unreachable or timeoutExample:
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 responseReturns: 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...');
}
verifyWebhookSignature(body, timestamp, signature, secret): booleanVerifies 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 headersignature (string): Value from X-555-Signature header (format: sha256=<hex>)secret (string): Your webhook secretReturns: 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..."
}
}
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');
}
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.
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 | Mint Address | Decimals |
|---|---|---|
| USDC (mainnet) | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | 6 |
| USDC (devnet) | 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU | 6 |
| SOL (wrapped) | So11111111111111111111111111111111111111112 | 9 |
USDC uses 6 decimals:
1000000 micro-units10000 micro-unitsHelper (built-in):
import { usdToMicroUsdc, microUsdcToUsd } from '@555x402/agg/utils';
const microUnits = usdToMicroUsdc(2.50); // 2500000
const usd = microUsdcToUsd(2500000); // 2.5
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' });
}
});
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);
}
);
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');
}
// 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
});
# 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
Get your API key from the 555x402 Dashboard.
Key types:
pk_live_* - Production keyspk_test_* - Devnet/testnet keysAlways 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:
X-555-Timestamp is within 5 minutes of current timeFailed webhooks are retried with exponential backoff:
npm test
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();
});
});
"Invalid API key"
"Payment verification failed"
"No healthy facilitator available"
"Amount mismatch"
Enable detailed logging:
const client = new AggClient(apiKey, apiBase, { debug: true });
This logs all API requests/responses to console.
Full TypeScript definitions are included. Import types:
import type {
PaymentResult,
PaymentStatus,
Expected,
WebhookPayload
} from '@555x402/agg';
verifyAndSettle and getStatus methodsContributions welcome! Please read CONTRIBUTING.md first.
MIT © 555x402
Built with ❤️ for the Solana ecosystem
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.0Registry latest | 11 Nov 2025 | 4 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Observed since 20 Oct, 20:25 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:c05d72331c2cbd1b2618f584a946c789098e0bc9f912ce50c44d5a62d650e2f2