This guide covers how to integrate mavi pay with a Hono application. Hono is a lightweight web framework that runs on Cloudflare Workers, Deno, Bun, and Node.js. The integration uses @mavi-pay/sdk for API calls and webhook verification.
npm install @mavi-pay/sdk honoCreate a mavi pay client instance.
// lib/mavi-pay.ts
import { MaviPay } from '@mavi-pay/sdk'
export const maviPay = new MaviPay({
accessToken: process.env.MAVI_PAY_ACCESS_TOKEN!,
baseUrl: 'https://api.mavifinans.sh',
})Set up a route to receive and verify mavi pay webhooks.
// src/index.ts
import { Hono } from 'hono'
import { verifyWebhookSignature } from '@mavi-pay/sdk'
import { maviPay } from './lib/mavi-pay'
const app = new Hono()
app.post('/webhooks/mavi-pay', async (c) => {
const body = await c.req.text()
const signature = c.req.header('x-mavi-pay-signature')
if (!signature) {
return c.json({ error: 'Missing signature' }, 401)
}
const isValid = verifyWebhookSignature(
body,
signature,
process.env.MAVI_PAY_WEBHOOK_SECRET!
)
if (!isValid) {
return c.json({ error: 'Invalid signature' }, 401)
}
const event = JSON.parse(body)
switch (event.type) {
case 'checkout.completed': {
const { customer_email, product_id, order_id } = event.data
// Fulfil the order: grant access, send confirmation, etc.
console.log(`Order ${order_id} completed for ${customer_email}`)
break
}
case 'subscription.cancelled': {
const { customer_id, product_id } = event.data
// Revoke access for the cancelled subscription
console.log(`Subscription cancelled for customer ${customer_id}`)
break
}
}
return c.json({ received: true })
})
export default appGenerate a checkout URL from your Hono API and redirect the user.
app.post('/api/checkout', async (c) => {
const { productId, customerEmail } = await c.req.json()
const checkout = await maviPay.checkouts.create({
productId,
customerEmail,
successUrl: 'https://yourapp.com/success',
})
return c.json({ checkoutUrl: checkout.url })
})Expose your mavi pay products through a Hono endpoint.
app.get('/api/products', async (c) => {
const products = await maviPay.products.list()
return c.json(products)
})Create a Hono middleware to protect routes behind a purchase check.
import { createMiddleware } from 'hono/factory'
const requirePurchase = (productId: string) =>
createMiddleware(async (c, next) => {
const customerId = c.get('customerId') // Set by your auth middleware
if (!customerId) {
return c.json({ error: 'Unauthorized' }, 401)
}
const orders = await maviPay.orders.list({
customerId,
productId,
})
const hasAccess = orders.items.some(
(order) => order.status === 'paid' || order.status === 'active'
)
if (!hasAccess) {
return c.json({ error: 'Purchase required' }, 403)
}
await next()
})
// Use it on protected routes
app.get('/api/premium-content', requirePurchase('prod_xxxxxxxx'), async (c) => {
return c.json({ content: 'This is premium content.' })
})MAVI_PAY_ACCESS_TOKEN=your_api_key_here
MAVI_PAY_WEBHOOK_SECRET=your_webhook_secret_hereFor Cloudflare Workers, set these as secrets:
wrangler secret put MAVI_PAY_ACCESS_TOKEN
wrangler secret put MAVI_PAY_WEBHOOK_SECRETHono works across multiple runtimes. The mavi pay SDK is compatible with all of them:
wrangler deploybun run src/index.tsdeno run --allow-net src/index.tsnode dist/index.js