paegents
v2.5.0
Published
Official TypeScript/JavaScript SDK for Paegents - Payment infrastructure for AI agents with Service Catalog and Usage Escrow
Maintainers
Readme
Paegents TypeScript/JavaScript SDK
The official TypeScript/JavaScript SDK for Paegents - Payment infrastructure for AI agents.
Installation
npm install paegents
# or
yarn add paegentsQuick Start
import { PaegentsSDK } from 'paegents';
// Initialize the SDK
const paegents = new PaegentsSDK({
apiUrl: 'https://api.paegents.com',
agentId: 'my_ai_agent',
apiKey: 'ak_live_your_api_key_here'
});
// Make an A2A payment to a supplier
const response = await paegents.paySupplier(
'acme-corp.com',
2500, // $25.00 in cents
'GPU compute credits'
);
console.log(`Payment ${response.status}: ${response.txnId}`);
// Check payment status
const status = await paegents.checkA2AStatus(response.txnId);
console.log(`Current status: ${status.status}`);AP2 Mandates & Stablecoin (x402)
Create intent/cart mandates and execute card or stablecoin payments with a few lines of code.
import {
buildCardPaymentMethod,
buildStablecoinPaymentMethod,
} from 'paegents';
const intent = await paegents.createAp2IntentMandate({
policy: {
max_amount: { value: 25_00 },
currency: 'usd',
},
});
const cart = await paegents.createAp2CartMandate({
intentMandateId: intent.id,
cart: {
total: 12_50,
currency: 'usd',
description: 'Monthly agent hosting',
},
});
// Card rail (Stripe/Braintree)
const cardPayment = await paegents.ap2Pay({
intentMandateId: intent.id,
cartMandateId: cart.id,
paymentMethod: buildCardPaymentMethod({ provider: 'stripe' }),
});
console.log(cardPayment.status);
// Stablecoin rail via Coinbase x402 (secure client-side signing)
const stablecoinPayment = await paegents.ap2Pay({
intentMandateId: intent.id,
cartMandateId: cart.id,
paymentMethod: await buildStablecoinPaymentMethod({
payerPrivateKey: process.env.STABLE_COIN_PRIVATE_KEY!,
destinationWallet: '0xSellerWallet...',
amountCents: 1250, // $12.50
resourceId: `cart:${cart.id}`,
description: 'Monthly agent hosting',
network: 'base-sepolia', // or 'base' for mainnet
}),
});
console.log(stablecoinPayment.onchainTxid);Security Note: buildStablecoinPaymentMethod signs the payment CLIENT-SIDE. Your private key never leaves your environment - only the signed authorization is sent to the server.
Advanced: Direct X402 Signing
For custom integrations, you can use the low-level signing function:
// Import from the stablecoin subpath to opt-in to viem/x402 helpers
import { createSignedX402Payment } from 'paegents/stablecoin';
// Sign a payment authorization locally
const paymentHeader = await createSignedX402Payment({
payerPrivateKey: process.env.AGENT_PRIVATE_KEY!,
destinationWallet: '0xSeller...',
amountCents: 500,
resourceId: 'custom:payment:123',
description: 'Custom payment',
network: 'base-sepolia'
});
// Send only the signature to your API
const paymentMethod = {
rail: 'stablecoin',
provider: 'coinbase',
wallet_address: '0xSeller...',
payment_header: paymentHeader // Signed authorization (secure!)
};Browser with injected provider (viem)
import { createSignedX402Payment } from 'paegents/stablecoin';
// Request accounts then sign via provider (no private key in code)
const [signer] = await window.ethereum.request({ method: 'eth_requestAccounts' });
const paymentHeader = await createSignedX402Payment({
provider: window.ethereum,
signerAddress: signer,
destinationWallet: '0xRecipient...',
amountCents: 1250,
resourceId: `cart:${cart.id}`,
network: 'base-sepolia',
});
await sdk.ap2Pay({
intentMandateId: intent.id,
cartMandateId: cart.id,
paymentMethod: {
rail: 'stablecoin',
provider: 'coinbase',
wallet_address: '0xRecipient...',
payment_header: paymentHeader,
},
});Supported Networks:
base-sepolia- Base Sepolia testnet (default)baseorbase-mainnet- Base mainnet
The stablecoin helper requires a funded private key and the amount/resource ID for signing. You can override the network, timeout, or description via the helper options.
A2A (Agent-to-Agent) Payments
The core feature of Paegents is seamless agent-to-agent payments using domain-based supplier resolution.
Making a Payment
// Pay a supplier by domain
const response = await paegents.paySupplier(
'software-company.io',
5000, // $50.00 in cents
'API usage charges',
'usd' // Optional currency
);
// Handle different response statuses
switch (response.status) {
case 'paid':
console.log(`✅ Payment successful! Transaction: ${response.txnId}`);
break;
case 'processing':
console.log(`⏳ Payment processing... Transaction: ${response.txnId}`);
break;
case 'supplier_onboarding':
console.log(`📧 Supplier needs onboarding: ${response.nextActionUrl}`);
break;
case 'failed':
console.log(`❌ Payment failed: ${response.error}`);
break;
}Checking Payment Status
// Poll for status updates
const status = await paegents.checkA2AStatus('agt_txn_123abc456def');
console.log(`Status: ${status.status}`);
console.log(`Events:`, status.events);TypeScript Types
The SDK is fully typed for excellent developer experience:
import { A2APaymentResponse, A2AStatusResponse } from 'paegents';
// Response types are automatically inferred
const payment: A2APaymentResponse = await paegents.paySupplier(
'example.com',
1000,
'Test payment'
);
const status: A2AStatusResponse = await paegents.checkA2AStatus(payment.txnId);Traditional MCP Payments
For payments to specific accounts (legacy method):
Stripe Payments
import { PaymentRequest } from 'paegents';
// Pay a Stripe account
const payment: PaymentRequest = {
agentId: 'my_agent',
amount: 1000, // $10.00 in cents
currency: 'usd',
description: 'Service payment',
paymentMethod: 'stripe',
recipientAccountId: 'acct_stripe_account_id'
};
const response = await paegents.createPayment(payment);
console.log(`Payment intent: ${response.paymentIntentId}`);PayPal Payments
import { PayPalPaymentRequest } from 'paegents';
// Pay via PayPal email
const paypalPayment: PayPalPaymentRequest = {
agentId: 'my_agent',
recipientEmail: '[email protected]',
amount: 25.00, // PayPal uses dollars
description: 'Consulting services'
};
const response = await paegents.createPayPalPayment(paypalPayment);
console.log(`PayPal payment: ${response.paymentIntentId}`);Account Management
Check Spending Limits
const limits = await paegents.checkBalance();
console.log(`Daily remaining: $${limits.dailyRemaining / 100}`);
console.log(`Monthly remaining: $${limits.monthlyRemaining / 100}`);Discover Recipients
// Search for payment recipients
const results = await paegents.searchRecipients('acme', 'all');
results.results.forEach(result => {
console.log(`Found: ${result.businessName} (${result.paymentMethod})`);
});
// Check if email can receive PayPal
const discovery = await paegents.discoverPayPalEmail('[email protected]');
if (discovery.canReceivePaypal) {
console.log(`✅ ${discovery.email} can receive PayPal payments`);
}Verify Receipts
// Verify payment receipt authenticity
const verification = await paegents.verifyReceipt('receipt_id_here');
if (verification.valid) {
console.log('✅ Receipt is authentic');
console.log(`Amount: $${verification.receipt?.amount / 100}`);
} else {
console.log('❌ Receipt verification failed');
}Error Handling
try {
const response = await paegents.paySupplier(
'unknown-company.com',
1000,
'Test payment'
);
} catch (error) {
console.error('Payment failed:', error.message);
}Policies and Approvals (Owner JWT)
Some endpoints require the human owner (JWT) rather than an agent API key. You can pass a JWT per call or at construction time via ownerJwt.
import { PaegentsSDK } from 'paegents';
const sdk = new PaegentsSDK({ apiUrl, agentId, apiKey, ownerJwt: process.env.OWNER_JWT });
// Fetch and update policies
const current = await sdk.getAgentPolicies('my-agent');
await sdk.updateAgentPolicies({
rails: { allowed: ['card', 'stablecoin'] },
approvals: { threshold_cents: 2000 },
recipients: { whitelist: ['0x1111...'] },
schedule: { days: ['Mon','Tue'], allowed_hours: ['09:00-17:00'] },
}, 'my-agent');
// Approvals queue (e.g., after AP2 approval_required)
const { approvals } = await sdk.listApprovals({ status: 'pending', limit: 20, agentId: 'my-agent' });
if (approvals.length) {
await sdk.approveApproval(approvals[0].id, 'my-agent');
}AP2 Approval Handling
When a payment requires approval, the API returns approval_required rather than an error. The SDK surfaces this without throwing:
const res = await sdk.ap2Pay({
intentMandateId: intent.id,
cartMandateId: cart.id,
paymentMethod: buildCardPaymentMethod({ provider: 'stripe' })
});
if ('approvalRequired' in res && res.approvalRequired) {
console.log(`Approval requested: ${res.requestId}`);
// Owner approves in dashboard/UI or via SDK listApprovals/approveApproval
}Usage Agreements: Cart Itemization and Suggestions
Add optional cart line items to the agreement; sellers can reject with suggestions:
const agreement = await sdk.createUsageAgreement({
sellerAgentId: 'seller-123',
quantity: 1000,
unit: 'api_calls',
pricePerUnitCents: 10,
paymentMethod: { rail: 'card', provider: 'stripe' },
cartItems: [
{ description: 'Requests bundle', quantity: 1, amount_cents: 10_000 }
],
clientProposalId: 'agree_demo_001',
});
// Seller suggestion on reject
await sdk.rejectUsageAgreement(agreement.agreementId, {
reason: 'Offer 2k calls at a discount',
suggested_total_cents: 18_000,
});Owner Spending Limits (JWT)
Get and update the human account’s daily/monthly spending limits:
const limits = await sdk.getSpendingLimits(process.env.OWNER_JWT);
await sdk.updateSpendingLimits({ daily_limit: 50, monthly_limit: 200 }, process.env.OWNER_JWT);Webhooks Operations
Programmatically manage webhooks and deliveries:
await sdk.createWebhook({ url: 'https://example.com/hooks', eventTypes: ['agreement.*'] }, 'my-agent', process.env.OWNER_JWT);
const { webhooks } = await sdk.listWebhooks('my-agent', process.env.OWNER_JWT);
await sdk.rotateWebhookSecret(webhooks[0].id, 'my-agent', process.env.OWNER_JWT);
const { deliveries } = await sdk.listDeliveries({ status: 'failed', limit: 10, agentId: 'my-agent' }, process.env.OWNER_JWT);
if (deliveries.length) {
await sdk.replayDelivery(deliveries[0].id, 'my-agent', process.env.OWNER_JWT);
}Typed Errors
The SDK throws PolicyDeniedError for policy enforcement failures (e.g., outside schedule) and ApiError for other HTTP errors:
import { PolicyDeniedError } from 'paegents';
try {
await sdk.ap2Pay({ intentMandateId: 'i', cartMandateId: 'c', paymentMethod: buildCardPaymentMethod() });
} catch (err) {
if (err instanceof PolicyDeniedError) {
console.error('Policy blocked payment:', err.message);
}
}Marketplace: Usage Agreements
Create prepaid usage agreements between buyer and seller agents via the SDK. The dashboard remains monitoring-first; creation and acceptance happen via code. Use clientProposalId to ensure idempotency across retries.
import { PaegentsSDK, buildCardPaymentMethod } from 'paegents';
const sdk = new PaegentsSDK({ apiUrl, agentId, apiKey });
// Buyer proposes an agreement
const proposal = await sdk.createUsageAgreement({
sellerAgentId: 'seller-agent-123',
quantity: 1000,
unit: 'api_calls',
pricePerUnitCents: 10,
paymentMethod: buildCardPaymentMethod({ provider: 'stripe' }),
clientProposalId: 'agree_demo_001', // optional but recommended
expiresInHours: 24,
});
// Seller lists incoming proposals
const incoming = await sdk.listUsageAgreements({ role: 'seller', status: 'proposed', limit: 50 });
// Seller accepts (idempotent)
const accepted = await sdk.acceptUsageAgreement(proposal.agreementId);
// Or reject
await sdk.rejectUsageAgreement(proposal.agreementId);
// Fetch agreement details
const details = await sdk.getUsageAgreement(proposal.agreementId);Notes
- The SDK sets
Idempotency-Keyheaders for propose/accept/reject automatically; provide a stableclientProposalIdto dedupe across process restarts. - Listing uses your configured
agentIdwith an optionalrolefilter (buyerorseller).
Pollable Inbox
Agents can poll for events (e.g., agreement.proposed, agreement.accepted) without webhooks. This is useful for serverless agents or environments where exposing a webhook isn’t feasible.
// List most recent events for this agent
const events = await sdk.listAgentEvents({ types: ['agreement.proposed', 'agreement.accepted'], limit: 50 });
// Process and ack
for (const evt of events) {
if (evt.type === 'agreement.proposed') {
// Inspect payload.agreement_id, payload.quantity, etc.
}
await sdk.ackAgentEvent(evt.eventId);
}Notes
- Use the
aftercursor with the last seeneventIdto paginate. - Acknowledgement is idempotent and safe to retry.
Webhook Verification
Verify webhook events sent by Paegents using HMAC-SHA256 over the raw request body.
import { verifyWebhookSignature } from 'paegents';
// In your express/fastify handler, ensure you read the raw body string
const signature = req.headers['paegents-signature'] as string;
const rawBody = req.rawBody.toString('utf8');
const secret = process.env.PAEGENTS_WEBHOOK_SECRET!;
try {
verifyWebhookSignature(signature, rawBody, secret);
// proceed to parse JSON and handle event
const event = JSON.parse(rawBody);
} catch (err) {
res.status(400).send('Invalid signature');
}Header format: Paegents-Signature: t=<unix>, v1=<hex(hmac_sha256(secret, ${t}.${body}))>.
Configuration
Environment Variables
// Use environment variables for configuration
const paegents = new PaegentsSDK({
apiUrl: process.env.PAEGENTS_API_URL || 'https://api.paegents.com',
agentId: process.env.PAEGENTS_AGENT_ID!,
apiKey: process.env.PAEGENTS_API_KEY!
});Browser Usage
The SDK works in both Node.js and browser environments:
<!DOCTYPE html>
<html>
<head>
<script type="module">
import { PaegentsSDK } from 'https://unpkg.com/paegents@latest/dist/index.esm.js';
const paegents = new PaegentsSDK({
apiUrl: 'https://api.paegents.com',
agentId: 'browser_agent',
apiKey: 'ak_live_your_key_here'
});
// Make payments from the browser
document.getElementById('payButton').onclick = async () => {
const response = await paegents.paySupplier(
'supplier.com',
1000,
'Browser payment'
);
console.log('Payment result:', response);
};
</script>
</head>
<body>
<button id="payButton">Pay Supplier</button>
</body>
</html>Note: To use the stablecoin helpers in the browser, install peer deps in your app and bundle them (viem and x402). The CDN-only build does not include the paegents/stablecoin subpath.
React/Vue/Angular Integration
React Hook Example
import { useEffect, useState } from 'react';
import { PaegentsSDK, A2APaymentResponse } from 'paegents';
const paegents = new PaegentsSDK({
apiUrl: process.env.REACT_APP_PAEGENTS_API_URL!,
agentId: 'react_agent',
apiKey: process.env.REACT_APP_PAEGENTS_API_KEY!
});
export function usePayment() {
const [loading, setLoading] = useState(false);
const paySupplier = async (
supplier: string,
amount: number,
description: string
): Promise<A2APaymentResponse> => {
setLoading(true);
try {
return await paegents.paySupplier(supplier, amount, description);
} finally {
setLoading(false);
}
};
return { paySupplier, loading };
}
// Usage in component
function PaymentButton() {
const { paySupplier, loading } = usePayment();
const handlePay = async () => {
const result = await paySupplier('acme-corp.com', 1000, 'React payment');
alert(`Payment ${result.status}: ${result.txnId}`);
};
return (
<button onClick={handlePay} disabled={loading}>
{loading ? 'Processing...' : 'Pay Supplier'}
</button>
);
}Service Catalog (Gap 2)
Discover and register services in the Paegents marketplace.
Register a Service
import { ServiceRegistration } from 'paegents';
// Register a service as a seller
const service: ServiceRegistration = {
serviceName: 'GPT-4 Inference API',
description: 'High-quality AI text generation',
category: 'ai_inference',
priceModel: 'per_unit',
basePriceCents: 10, // $0.10 per token
unit: 'tokens',
minQuantity: 100,
maxQuantity: 1000000,
capabilities: {
models: ['gpt-4', 'gpt-4-turbo'],
max_context: 128000
}
};
const registered = await paegents.registerService(service);
console.log(`Service ID: ${registered.serviceId}`);Search for Services
// Search the catalog
const results = await paegents.searchServices({
query: 'gpt inference',
category: 'ai_inference',
maxPrice: 50, // Up to $0.50 per unit
limit: 10
});
for (const service of results.results) {
console.log(`${service.serviceName}: $${service.basePriceCents/100} per ${service.unit}`);
}Manage Services
// Update a service
await paegents.updateService('svc_123', {
basePriceCents: 8, // Lower price to $0.08
description: 'Updated description'
});
// List your services
const myServices = await paegents.listMyServices(50);
// Deactivate a service
await paegents.deleteService('svc_123');Prepaid Usage Escrow (Gap 3)
Create prepaid usage agreements with automatic escrow, payment release, and refunds.
Create Usage Agreement (Buyer)
import { UsageAgreementRequest } from 'paegents';
// Buyer creates prepaid agreement
const agreement = await paegents.createUsageAgreement({
sellerAgentId: 'agent_seller_123',
quantity: 5000, // 5,000 tokens
unit: 'tokens',
pricePerUnitCents: 10, // $0.10 per token
paymentMethod: { rail: 'stripe', type: 'card' },
serviceDescription: 'GPT-4 inference for chatbot',
expiresInHours: 24
});
console.log(`Agreement ID: ${agreement.agreementId}`);
console.log(`Total: $${agreement.totalCents / 100}`);
console.log(`Status: ${agreement.status}`);Accept Agreement (Seller)
// Seller accepts and funds escrow
const accepted = await paegents.acceptUsageAgreement(agreement.agreementId);
console.log(`Escrow funded: $${accepted.totalCents / 100}`);
console.log(`Payment ID: ${accepted.escrowPaymentId}`);Record Usage (Seller)
import { RecordUsageRequest } from 'paegents';
// Seller records actual usage
const completed = await paegents.recordUsage(agreement.agreementId, {
unitsUsed: 3000, // Used 3,000 out of 5,000 tokens
completed: true,
usageProof: { logs: 'proof_of_usage' }
});
// Automatic payment release and refund
console.log(`Released to seller: $${completed.releasedCents! / 100}`); // $300
console.log(`Refunded to buyer: $${(completed.totalCents - completed.releasedCents!) / 100}`); // $200List and Manage Agreements
// List all agreements (buyer or seller)
const agreements = await paegents.listUsageAgreements('active', 50);
// Get agreement details
const agreement = await paegents.getUsageAgreement('agr_123');
// Cancel before acceptance (buyer only)
await paegents.cancelUsageAgreement('agr_123');
// Dispute agreement (buyer)
const disputed = await paegents.disputeUsageAgreement(
'agr_123',
'Service not delivered as agreed',
{ screenshots: ['url1', 'url2'] }
);API Reference
AgentPaymentsSDK
The main SDK class for interacting with Paegents.
Constructor
new PaegentsSDK({
apiUrl: string,
agentId: string,
apiKey: string
})A2A Methods
paySupplier(supplier, amount, description, currency?, txnId?)→Promise<A2APaymentResponse>checkA2AStatus(txnId)→Promise<A2AStatusResponse>
Service Catalog Methods (Gap 2)
registerService(service: ServiceRegistration)→Promise<ServiceDetails>updateService(serviceId: string, updates: Partial<ServiceRegistration>)→Promise<{success: boolean}>deleteService(serviceId: string)→Promise<{success: boolean}>getService(serviceId: string)→Promise<ServiceDetails>listMyServices(limit?: number, offset?: number)→Promise<ServiceDetails[]>searchServices(options: SearchOptions)→Promise<CatalogSearchResult>
Usage Agreement Methods (Gap 3)
createUsageAgreement(request: UsageAgreementRequest)→Promise<UsageAgreement>getUsageAgreement(agreementId: string)→Promise<UsageAgreement>listUsageAgreements(status?: string, limit?: number)→Promise<UsageAgreement[]>acceptUsageAgreement(agreementId: string)→Promise<UsageAgreement>recordUsage(agreementId: string, request: RecordUsageRequest)→Promise<UsageAgreement>cancelUsageAgreement(agreementId: string)→Promise<{agreementId: string; status: string}>disputeUsageAgreement(agreementId: string, reason: string, evidence?: any)→Promise<UsageAgreement>
Legacy MCP Methods
createPayment(request)→Promise<PaymentResponse>createPayPalPayment(request)→Promise<PaymentResponse>searchRecipients(query, paymentMethod?)→Promise<RecipientSearchResult>discoverPayPalEmail(email)→Promise<EmailDiscoveryResult>checkBalance()→Promise<SpendingLimits>verifyReceipt(receiptId)→Promise<{valid: boolean; receipt?: Receipt}>
Support
- Documentation: docs.paegents.com
- API Reference: docs.paegents.com/api
- Support: [email protected]
- Issues: github.com/paegents/typescript-sdk/issues
License
MIT License - see LICENSE file for details.
