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.