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.failed

Event 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.