@orvion/sdk
v0.5.3
Published
Orvion SDK for x402 V2 payment-protected APIs
Readme
Orvion Node.js SDK
Node.js SDK for integrating x402 payment-protected APIs with Orvion.
Installation
npm install @orvion/sdk
# or
yarn add @orvion/sdk
# or
pnpm add @orvion/sdkQuick Start
Express Integration
import express from 'express';
import { orvionInit, requirePayment } from '@orvion/sdk/express';
const app = express();
// Initialize Orvion
orvionInit({
apiKey: process.env.ORVION_API_KEY!,
});
// Protect an endpoint with payment requirement
app.get('/api/premium/data', requirePayment(), (req, res) => {
// Access payment info
const payment = req.payment;
res.json({
data: 'Premium content!',
paid: payment.amount,
transactionId: payment.transactionId,
});
});
// Override price in code
app.get('/api/reports/generate', requirePayment({ amount: '5.00', currency: 'USD' }), (req, res) => {
res.json({ report: '...' });
});
// Require customer identification (no anonymous access)
app.get('/api/ai/chat', requirePayment({ allowAnonymous: false }), (req, res) => {
const customerId = req.payment.customerRef;
res.json({ response: '...' });
});
app.listen(3000);Standalone Client
import { OrvionClient } from '@orvion/sdk';
const client = new OrvionClient({
apiKey: 'your_api_key',
});
// Create a charge
const charge = await client.createCharge({
amount: '0.10',
currency: 'USD',
customerRef: 'user_123',
resourceRef: 'protected_route:abc-123',
});
console.log(`Charge ID: ${charge.id}`);
console.log(`Payment URL: ${charge.x402Requirements}`);
// Verify a payment
const result = await client.verifyCharge({
transactionId: 'tx_abc123',
resourceRef: 'protected_route:abc-123',
});
if (result.verified) {
console.log('Payment verified!');
}Facilitator Payment (x402 V2) with web3.js
Build the EIP-3009 typed data, sign it in the browser, and send the
paymentPayload to your backend.
import { OrvionClient, buildEip3009TypedData, buildEvmAuthorization, buildEvmPaymentPayload } from '@orvion/sdk';
const client = new OrvionClient({ apiKey: 'your_api_key' });
const authorization = buildEvmAuthorization({
from: '0x...',
to: '0x...',
value: '1000000',
validAfter: '1716150000',
validBefore: '1716153600',
nonce: '0x...',
});
const typedData = buildEip3009TypedData({
tokenName: 'USDC',
tokenVersion: '2',
chainId: 8453,
verifyingContract: '0x...',
authorization,
});
const signature = await window.ethereum.request({
method: 'eth_signTypedData_v4',
params: [authorization.from, JSON.stringify(typedData)],
});
const paymentPayload = buildEvmPaymentPayload({
signature,
authorization,
network: 'base',
});
await client.processPayment({
transactionId: 'charge_xxx',
paymentPayload,
});Configuration
Environment Variables
ORVION_API_KEY- Your Orvion API keyORVION_BASE_URL- API base URL (default: https://api.orvion.sh)
Middleware Options
orvionInit({
apiKey: 'your_api_key',
baseUrl: 'https://api.orvion.sh', // Custom API URL
cacheTtlSeconds: 60, // Route config cache TTL
transactionHeader: 'X-Transaction-Id', // Custom header name
customerHeader: 'X-Customer-Id', // Custom header name
});Middleware Options
requirePayment({
amount: '0.10', // Override dashboard price
currency: 'USD',
allowAnonymous: false, // Require customer identification
customerResolver: (req) => req.user?.id, // Custom customer ID extraction
hostedCheckout: true, // Enable hosted checkout mode (redirects to pay.orvion.sh)
})Hosted Checkout Mode
For web applications, use hosted checkout mode for a seamless payment experience:
// API endpoint - protected with payment
app.get('/api/premium',
requirePayment({
amount: '1.00',
currency: 'USDC',
hostedCheckout: true, // Just add this!
}),
(req, res) => {
res.json({ message: 'Premium content!' });
}
);
// Frontend page - serves the UI
app.get('/premium', (req, res) => {
res.sendFile('static/premium.html');
});Automatic URL Convention: The SDK strips /api prefix automatically:
- API at
/api/premium→ Frontend at/premium - After payment, users are redirected to
/premium?charge_id=xxx&status=succeeded - No
returnUrlconfiguration needed!
Testing
The SDK includes comprehensive testing utilities and is fully tested with Vitest.
Testing Utilities
import { mockOrvion, fakePayment } from '@orvion/sdk/testing';
// Mock all Orvion calls
const mock = mockOrvion({ alwaysApprove: true });
mock.addRoute('/api/premium/*', { amount: '0.10' });
// In your test
const response = await request(app).get('/api/premium/data');
expect(response.status).toBe(200);
mock.restore();
// Create fake payment for testing
req.payment = fakePayment({
amount: '0.10',
currency: 'USD',
transactionId: 'test_tx_123',
});Running Tests
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
# Run E2E tests (requires ORVION_STAGING_API_KEY)
npm run test:e2eTest Structure
The SDK uses a three-layer testing approach:
- Unit Tests (
tests/unit/) - Pure logic tests for matcher, cache, and error classes - Integration Tests (
tests/integration/) - HTTP mocking with MSW for client and middleware - E2E Tests (
tests/e2e/) - Smoke tests against staging API
HTTP Mocking with MSW
The SDK uses MSW (Mock Service Worker) for HTTP mocking in integration tests:
import { server } from './tests/helpers/server';
import { http, HttpResponse } from 'msw';
// Override default handlers
server.use(
http.post('https://api.orvion.sh/v1/charges', () => {
return HttpResponse.json({
id: 'custom_charge',
amount: '1.00',
currency: 'USD',
status: 'pending',
});
})
);Express Middleware Testing
Test Express middleware with Supertest:
import request from 'supertest';
import express from 'express';
import { orvionInit, requirePayment } from '@orvion/sdk/express';
const app = express();
app.use(orvionInit({ apiKey: 'test_key' }));
app.get('/api/premium/data', requirePayment(), (req, res) => {
res.json({ data: 'premium', payment: req.payment });
});
// Test
const response = await request(app)
.get('/api/premium/data')
.set('X-Payment-Transaction', 'valid_tx_123')
.expect(200);
expect(response.body.payment).toBeDefined();Telemetry
Opt-in telemetry is available for monitoring SDK usage:
import { OrvionClient } from '@orvion/sdk';
const client = new OrvionClient({
apiKey: 'your_key',
telemetry: {
enabled: true,
serviceName: 'my-app',
serviceVersion: '1.0.0',
},
});Privacy: Telemetry is opt-in and never collects PII (no customer refs, transaction IDs, or amounts).
TypeScript
This package includes TypeScript declarations. The Payment type is available on Express requests:
import { Request } from 'express';
import { PaymentInfo } from '@orvion/sdk';
app.get('/api/premium', requirePayment(), (req: Request, res) => {
const payment: PaymentInfo = req.payment;
// ...
});License
MIT
