Subscriptions let you charge customers on a recurring basis using Lightning payments. Customers pay once to start their subscription, then receive renewal reminders before each billing period.
What are Subscriptions?
Subscriptions in moneydevkit work differently from traditional card-based subscriptions:
- No stored payment methods - Lightning payments are push-based, so customers pay proactively
- Renewal reminders - Customers receive emails 7, 4, and 1 days before their subscription renews
- Grace period - If a customer misses a payment, they have 3 days to renew before cancellation
- Instant settlement - Payments settle immediately in Bitcoin
Setup
Create a recurring product
In your moneydevkit dashboard, create a product with a recurring interval:
- Navigate to Products
- Click the + button
- Fill in product details
- Select a Recurring interval: Monthly, Quarterly, or Yearly
- Click Create Product
Create a subscription checkout
Use the recurring product ID when creating checkouts:import { useCheckout } from '@moneydevkit/nextjs'
function SubscribeButton() {
const { createCheckout, isLoading } = useCheckout()
const handleSubscribe = async () => {
const result = await createCheckout({
type: 'PRODUCTS',
product: 'your-recurring-product-id',
successUrl: '/checkout/success',
customer: {
externalId: user.id, // Link to your user
email: user.email,
name: user.name,
},
})
if (result.error) {
console.error(result.error.message)
return
}
window.location.href = result.data.checkoutUrl
}
return (
<button onClick={handleSubscribe} disabled={isLoading}>
Subscribe
</button>
)
}
Subscriptions require customer data. Always pass customer.email so renewal reminders can be sent.
Check subscription status
Use the useCustomer hook to check if a user has an active subscription:import { useCustomer } from '@moneydevkit/nextjs'
function PremiumContent() {
const { customer, isLoading } = useCustomer({ externalId: user.id })
if (isLoading) return <p>Loading...</p>
if (!customer?.hasActiveSubscription) {
return <SubscribeButton />
}
return <div>Premium content here</div>
}
Subscription Lifecycle
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────┐ payment ┌────────┐ period ends ┌────────┐ │
│ │ Checkout │ ───────────▶ │ Active │ ───────────────▶ │past_due│ │
│ └──────────┘ └────────┘ └────────┘ │
│ │ │ │
│ │ cancel │ │
│ ▼ │ │
│ ┌────────┐ 3 day grace │ │
│ │canceled│ ◀─────────────────────┘ │
│ └────────┘ │
│ ▲ │
│ │ renewal payment │
│ │ │
│ ┌────────┐ │
│ │ Active │ (extended) │
│ └────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
| Status | Description |
|---|
active | Subscription is active and within the current billing period |
past_due | Billing period ended, customer is in the 3-day grace period |
canceled | Subscription has been canceled (either by customer or after grace period) |
Checking Subscription Status
The useCustomer hook fetches customer data including their subscriptions:
import { useCustomer } from '@moneydevkit/nextjs'
function AccountPage() {
const { customer, isLoading, error, refetch } = useCustomer({ externalId: user.id })
if (isLoading) return <p>Loading...</p>
if (error) return <p>Error: {error.message}</p>
if (!customer) return <p>Customer not found</p>
return (
<div>
<h2>Subscription Status</h2>
{customer.hasActiveSubscription ? (
<p>You have an active subscription</p>
) : (
<p>No active subscription</p>
)}
<h3>All Subscriptions</h3>
<ul>
{customer.subscriptions.map(sub => (
<li key={sub.id}>
{sub.status} - {sub.recurringInterval}
</li>
))}
</ul>
</div>
)
}
CustomerIdentifier Types
You can identify customers in three ways:
| Identifier | Description | Example |
|---|
externalId | Your app’s user ID | { externalId: user.id } |
email | Customer’s email address | { email: '[email protected]' } |
customerId | moneydevkit customer ID | { customerId: 'cus_abc123' } |
Grace Period
When a subscription’s billing period ends without payment:
- Day 0 - Status changes to
past_due, first grace period email sent
- Day 1 - Second grace period reminder
- Day 2 - Third grace period reminder
- Day 3 - Subscription auto-cancels if no payment received
During the grace period, customers can still renew their subscription by clicking the renewal link in their email.
Renewal Reminders
Customers receive renewal reminder emails at:
- 7 days before the billing period ends
- 4 days before the billing period ends
- 1 day before the billing period ends
Each email includes a link for the customer to renew their subscription.
Recurring Intervals
| Interval | Value | Billing Cycle |
|---|
| Monthly | MONTH | Every 1 month |
| Quarterly | QUARTER | Every 3 months |
| Yearly | YEAR | Every 12 months |
Billing dates use calendar math. A subscription started on January 31st will renew on February 28th (or 29th in leap years), then March 31st, and so on.
Price Units
Product prices are returned in base currency units:
- USD: cents (divide by 100 for dollars)
- SAT: satoshis (no conversion needed)
const { products } = useProducts()
// USD prices are in cents - divide by 100 for display
const displayPrice = (product.prices[0]?.priceAmount ?? 0) / 100