Subscription billing with Inzi
Accept recurring crypto payments for your SaaS product using Inzi payment links and metadata tracking.
Automatic recurring charges are not yet supported. Use payment links with metadata to track subscriptions manually.
Create a payment link for each plan
curl -X POST https://api.inzilink.com/api/v1/links \
-H "Authorization: Bearer sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"title": "Pro Plan — Monthly",
"amount": "29.00",
"currency": "USD",
"type": "subscription",
"metadata": { "plan": "pro", "interval": "monthly" }
}'Share on your pricing page
Embed the payment link URL on your pricing page or send it directly to customers:
<a href="https://inzilink.com/p/your-link-code" class="btn">
Pay with Crypto — $29/mo
</a>Track payments via metadata
Each payment through the link creates a checkout. Include user_id in metadata by creating individual checkouts:
const checkout = await fetch('https://api.inzilink.com/api/v1/checkouts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.INZI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: '29.00',
currency: 'USD',
description: 'Pro Plan — Monthly',
metadata: {
user_id: userId,
plan: 'pro',
interval: 'monthly',
billing_period: '2026-04',
},
redirect_url: `https://yourapp.com/billing/success`,
webhook_url: 'https://yourapp.com/webhooks/inzi',
}),
})Handle subscription webhooks
app.post('/webhooks/inzi', async (req, res) => {
const event = verifyWebhook(req.body, req.headers, WEBHOOK_SECRET)
if (event.event === 'checkout.completed') {
const { user_id, plan, billing_period } = event.data.metadata
// Extend subscription
await extendSubscription(user_id, plan, billing_period)
// Send receipt
await sendSubscriptionReceipt(user_id, event.data.amount)
}
res.json({ ok: true })
})Send renewal reminders
Since auto-charge isn’t available yet, send reminders when subscriptions are expiring:
// Cron job: check for expiring subscriptions daily
const expiring = await getExpiringSubscriptions()
for (const sub of expiring) {
// Create a new checkout for renewal
const checkout = await createCheckout({
amount: sub.plan_price,
metadata: { user_id: sub.user_id, plan: sub.plan, type: 'renewal' },
})
await sendRenewalEmail(sub.user_id, checkout.checkout_url)
}Recommended approach
- Create checkouts per user (not shared payment links) so metadata tracks who paid
- Store
billing_periodin metadata for reconciliation - Use webhooks to auto-extend subscriptions
- Send renewal links via email/in-app notification before expiry