← All Posts
Tutorials

Building a Subscription Billing System with USDT and Paychainly

May 21, 2026· 2 min read

Architecture Overview

Traditional card-based subscriptions use stored card tokens. USDT subscriptions work differently: each billing cycle generates a new payment link and the customer pays manually. This is standard practice in crypto — and preferred by users who do not want automatic charges.

Data Model

subscriptions
  id, userId, plan, amount, currency,
  status (active|past_due|cancelled),
  currentPeriodStart, currentPeriodEnd,
  paymentLinkId, paidAt

Step 1 — Create Subscription on Sign-Up

POST /api/v1/payment-links
{
  "amount": "29.00",
  "description": "Starter Plan — May 2025",
  "metadata": { "subscriptionId": "sub_123", "cycle": 1 }
}

Store the returned paymentLinkId and set status = pending.

Step 2 — Handle the Webhook

// deposit_detected event
if (event.metadata.subscriptionId) {
  await activateSubscription(event.metadata.subscriptionId);
  await scheduleNextRenewal(event.metadata.subscriptionId, 30); // days
}

Step 3 — Renewal Cron Job

// runs daily at 00:00 UTC
const due = await db.subscriptions.findAll({
  where: { currentPeriodEnd: { [Op.lte]: addDays(new Date(), 3) }, status: 'active' }
});
for (const sub of due) {
  const link = await paychainly.createPaymentLink({ amount: sub.amount });
  await notifyUser(sub.userId, link.payUrl);
  await sub.update({ status: 'past_due', paymentLinkId: link.id });
}

Grace Period Strategy

Give users a 7-day grace period before downgrading. Send reminder emails at days 3, 5, and 7. After day 7, set status = cancelled and restrict feature access.

Key Advantages Over Card Billing

  • No chargeback reversals after months of service.
  • No card expiry failures.
  • Instant settlement to your master wallet.
← Back to Blog
subscriptionsrecurring paymentsUSDTbillingSaaS