Payment Processing Guide¶
Complete guide to processing payments with Nivatio.
Payment Flow Overview¶
graph TD
A[Customer clicks Pay] --> B[Your app creates order]
B --> C[Nivatio returns checkoutUrl]
C --> D[Redirect to Checkout]
D --> E[Customer connects wallet]
E --> F[Customer approves payment]
F --> G[Transaction submitted]
G --> H[Wait for confirmations]
H --> I[Payment succeeded webhook]
I --> J[Fulfill order]
Creating a Payment Order¶
Basic Order¶
const order = await client.orders.create({
amount: 100000, // 100.000 NUSD (6 decimals)
currency: 'NUSD',
description: 'Premium Subscription - 1 Year',
successUrl: 'https://yourapp.com/success',
cancelUrl: 'https://yourapp.com/cancel'
});
Order with Metadata¶
Attach internal references to orders:
const order = await client.orders.create({
amount: 100000,
currency: 'NUSD',
description: 'Order #12345',
metadata: {
internalOrderId: 'ord_12345',
customerId: 'cust_789',
planId: 'plan_premium_yearly'
}
});
Redirecting to Checkout¶
Simple Redirect¶
window.location.href = order.checkoutUrl;
Opening in New Tab¶
window.open(order.checkoutUrl, '_blank');
Using JavaScript SDK (Embedded)¶
NivatioCheckout.open({
orderId: order.id,
onSuccess: (data) => {
console.log('Payment successful!', data);
// Redirect to success page
window.location.href = '/success?orderId=' + order.id;
},
onCancel: () => {
console.log('Payment cancelled');
window.location.href = '/cancel';
}
});
Handling Payment Status¶
Webhook Notification (Recommended)¶
app.post('/webhook', (req, res) => {
const event = req.body;
if (event.type === 'payment.succeeded') {
const order = event.data;
// Verify required confirmations
if (order.confirmations >= 2) {
fulfillOrder(order);
}
}
res.json({ received: true });
});
Polling (Alternative)¶
// Poll order status every 3 seconds
const pollOrder = async (orderId) => {
const order = await client.orders.retrieve(orderId);
if (order.status === 'PAID') {
fulfillOrder(order);
return;
}
if (order.status === 'FAILED' || order.status === 'EXPIRED') {
showError('Payment failed');
return;
}
// Continue polling
setTimeout(() => pollOrder(orderId), 3000);
};
pollOrder(order.id);
Confirmation Requirements¶
Nivatio waits for blockchain confirmations before marking payment as PAID.
| Environment | Required Confirmations | Approx. Time |
|---|---|---|
| Sandbox | 1 | ~2 seconds |
| Production | 2 | ~30 seconds |
Confirmation Cron
A background job runs every 5 seconds (dev) or 1 minute (prod) to check for confirmations.
On-Chain Verification (Optional)¶
For high-value orders, verify the transaction on-chain:
import { createPublicClient, http } from 'viem';
import { anvilLocal } from './chains';
const client = createPublicClient({
chain: anvilLocal,
transport: http()
});
// Verify transaction after webhook
const verifyOnChain = async (txHash) => {
const receipt = await client.getTransactionReceipt({ hash: txHash });
if (receipt.status === 'success') {
console.log(`Confirmed with ${receipt.confirmations} blocks`);
return true;
}
return false;
};
Common Scenarios¶
Subscription Payment¶
const subscriptionOrder = await client.orders.create({
amount: 100000, // Annual subscription
currency: 'NUSD',
description: 'Premium Plan - Annual',
metadata: {
type: 'subscription',
billingCycle: 'annual',
userId: 'user_123'
}
});
One-Time Purchase¶
const purchaseOrder = await client.orders.create({
amount: 50000, // One-time payment
currency: 'NUSD',
description: 'Widget Pro License',
metadata: {
type: 'onetime',
productId: 'widget_pro_license'
}
});
Refund (Future)¶
// Note: Refunds are currently manual via dashboard
// Automated refunds coming in v2
console.log('Process refund via dashboard.nivat.io');
Error Handling¶
See Error Handling Guide for complete details.
Common payment errors:
| Error | Cause | Solution |
|---|---|---|
invalid_amount |
Amount not in 6-decimal format | Use 100000 for 100.000 NUSD |
insufficient_funds |
Customer has no NUSD | Show faucet instructions |
tx_failed |
Transaction reverted | Ask customer to retry |
order_expired |
Payment timeout | Create new order |
Testing Payments¶
Use sandbox environment for testing:
# Simulate successful payment (sandbox only)
curl -X POST https://sandbox.nivat.io/v1/sandbox/simulate-pay \
-H "x-nivatio-internal-key: YOUR_INTERNAL_KEY" \
-H "Content-Type: application/json" \
-d '{"orderId": "order_abc123"}'
Next Steps¶
- Error Handling - Handle errors gracefully
- Webhook Integration - Receive notifications
- Testing Guide - Test thoroughly