Events & Webhooks
Listen for on-chain payment events and set up webhooks to automatically process payments when they're confirmed.
On-Chain Events
ZynPay's router contract emits events when payments are processed. You can listen for these events to automatically update your system.
PaymentCompleted Event
Emitted when a payment is successfully processed
solidity
event PaymentCompleted(
address indexed merchant,
uint256 amount,
bytes32 indexed paymentId,
address customer,
uint256 merchantAmount,
uint256 platformFee
)1
Listen for events using ethers.js
Set up an event listener to automatically process payments when they're confirmed on-chain.
typescript
import { JsonRpcProvider, Contract } from 'ethers'
import { ZynPayClient, Environment } from '@zyntrialabs/zynpay-sdk'
const provider = new JsonRpcProvider('https://sepolia.base.org')
const routerAddress = '0x73a499e043b03fc84ca62b99f58103436c52221a'
// Router ABI (simplified)
const routerABI = [
'event PaymentCompleted(address indexed merchant, uint256 amount, bytes32 indexed paymentId, address customer, uint256 merchantAmount, uint256 platformFee)',
]
const router = new Contract(routerAddress, routerABI, provider)
// Listen for PaymentCompleted events
router.on('PaymentCompleted', async (merchant, amount, paymentId, customer, merchantAmount, platformFee, event) => {
console.log('Payment completed:', {
merchant,
amount: amount.toString(),
paymentId,
customer,
merchantAmount: merchantAmount.toString(),
platformFee: platformFee.toString(),
txHash: event.transactionHash,
blockNumber: event.blockNumber,
})
// Update your database
await db.payments.update({
where: { paymentId },
data: {
status: 'completed',
txHash: event.transactionHash,
completedAt: new Date(),
},
})
// Unlock access or fulfill order
await fulfillOrder(paymentId)
})2
Query past events
You can also query past events to catch up on payments that occurred while your listener was offline.
typescript
// Query events from the last 1000 blocks
const currentBlock = await provider.getBlockNumber()
const fromBlock = currentBlock - 1000
const filter = router.filters.PaymentCompleted(
null, // merchant (any)
null, // paymentId (any)
)
const events = await router.queryFilter(filter, fromBlock, currentBlock)
for (const event of events) {
const { merchant, amount, paymentId, customer, merchantAmount, platformFee } = event.args
// Process each payment
await processPayment({
paymentId,
merchant,
amount: amount.toString(),
customer,
merchantAmount: merchantAmount.toString(),
platformFee: platformFee.toString(),
txHash: event.transactionHash,
})
}3
Set up webhooks (recommended)
For production applications, set up webhooks that ZynPay will call when payments are confirmed. This is more reliable than polling or event listeners.
typescript
// app/api/webhooks/payment/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { verifyWebhookSignature } from '@/lib/webhook-verification'
export async function POST(request: NextRequest) {
const body = await request.json()
// Verify webhook signature (implement your own verification)
const signature = request.headers.get('x-zynpay-signature')
const isValid = await verifyWebhookSignature(body, signature)
if (!isValid) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 })
}
const { event, data } = body
if (event === 'payment.completed') {
const { paymentId, amount, merchantAmount, platformFee, txHash, metadata } = data
// Update payment status
await db.payments.update({
where: { paymentId },
data: {
status: 'completed',
txHash,
completedAt: new Date(),
},
})
// Unlock access based on metadata
if (metadata.orderId) {
await updateOrderStatus(metadata.orderId, 'paid')
}
if (metadata.userId) {
await unlockUserAccess(metadata.userId, metadata.resourceId)
}
// Send notification
await sendNotification(metadata.userId, 'Payment confirmed!')
}
return NextResponse.json({ received: true })
}
// Configure webhook in ZynPay dashboard:
// URL: https://your-api.com/api/webhooks/payment
// Events: payment.completed, payment.failedEvent Types
PaymentCompleted
Emitted when a payment is successfully processed and confirmed on-chain.
- merchant: Address receiving the payment
- amount: Total payment amount
- paymentId: Unique payment identifier
- customer: Address making the payment
- merchantAmount: Amount sent to merchant (after fee)
- platformFee: Fee sent to platform
PaymentFailed
Emitted when a payment transaction fails or is reverted on-chain.
Best Practice: Always verify events on-chain by checking the transaction receipt. Don't rely solely on webhook data—verify it matches what's on the blockchain.