paysovra
v1.0.1
Published
Official PaySovra SDK — accept crypto and stablecoin payments, non-custodially.
Maintainers
Readme
PaySovra SDK
Accept crypto and stablecoin payments, non-custodially. Funds settle straight to wallets you control — PaySovra never holds or routes them.
npm install paysovraRequires a PaySovra account and a secret integration key. Node 18+.
Quick start
import { PaySovra } from "paysovra";
const paysovra = new PaySovra(process.env.PAYSOVRA_SECRET_KEY);Server-side only. The secret key can create charges and read customer data, so it must never reach a browser.
Taking a payment from a web page
Authorise the amount on your server and hand the browser a token. The price never exists in client code, so a customer cannot edit it before paying.
// Your server
const { token } = await paysovra.checkout.createIntent({
amountFiat: 49.99,
currency: "EUR",
orderId: "ORD-1234",
metadata: { userId: "u_88" }, // comes back on the webhook
});// The browser — the amount comes from the intent, not the page
window.PaySovra.open({ intentToken: token });Verifying webhooks
This is the part worth using the SDK for. constructEvent does a timing-safe
comparison and rejects deliveries outside a five-minute window, so replays and
forged signatures fail before your code sees them. It throws rather than
returning unverified data.
import { webhooks, SignatureVerificationError } from "paysovra";
app.post("/webhooks/paysovra",
express.raw({ type: "application/json" }), // RAW body, not parsed
(req, res) => {
let event;
try {
event = webhooks.constructEvent(req.body, req.headers, process.env.PAYSOVRA_WEBHOOK_SECRET);
} catch (err) {
if (err instanceof SignatureVerificationError) return res.status(400).send(err.message);
throw err;
}
if (event.event === "payment.confirmed") {
fulfillOrder(event.orderId);
}
res.json({ received: true });
});The body must be the exact bytes received. A body that has been parsed and re-stringified will not verify — key order and whitespace change the hash.
Payments
const payment = await paysovra.payments.create({
amountFiat: 49.99,
currency: "USD",
cryptoAsset: "USDC_BASE",
orderId: "ORD-1234",
});
await paysovra.payments.get(payment.id);
const { data, total } = await paysovra.payments.list({ page: 1, limit: 50 });Products, invoices, customers
await paysovra.products.create({
name: "Pro licence",
type: "digital",
price: 129,
currency: "GBP",
deliveryConfig: { linkUrl: "https://example.com/download" },
});
const { invoice } = await paysovra.invoices.create({
items: [{ name: "Consulting", quantity: 4, unitPrice: 250 }],
currency: "EUR",
customerEmail: "[email protected]",
});
await paysovra.invoices.send(invoice.id);
await paysovra.customers.list({ limit: 100 });products.update and invoices.update replace the record — send the full
definition, not a patch. Fetch first if you mean to change one field.
Types
Assets and currencies are literal unions, so a typo is a compile error rather than a runtime 400.
import type { CryptoAsset, Currency, Payment, WebhookEvent } from "paysovra";Assets: BTC LTC ETH TRX SOL POL BNB, plus USDC/USDT on
Ethereum, Polygon, BNB Chain, Arbitrum, Optimism, Base, Solana and TRON.
Currencies: USD EUR GBP CAD AUD PLN INR. The exchange rate is
locked when the customer commits, so what arrives matches what you charged.
Errors
import { PaySovraAPIError } from "paysovra";
try {
await paysovra.payments.create({ /* … */ });
} catch (err) {
if (err instanceof PaySovraAPIError) {
err.status; // HTTP status
err.isAuthError; // 401/403 — wrong key, or publishable where secret is needed
err.isRateLimited; // 429
err.issues; // field-level validation detail when supplied
}
}Requests carry an idempotency key automatically and retry on 429 and 5xx, so a network blip cannot create a duplicate payment.
Testing
Point at a testnet instance and integrate end to end without spending real money. Sepolia, Polygon Amoy, Base/Arbitrum/Optimism Sepolia, Solana Devnet and TRON Nile are supported, with test USDT and USDC contracts on Sepolia.
new PaySovra({ apiKey: "sk_test_…", baseUrl: "https://your-test-instance" });Links
License
MIT
