recur-checkout
Recur Checkout Integration
You are helping implement Recur checkout flows. Recur supports multiple checkout modes for different use cases.
Checkout Modes
| Mode | Best For | User Experience |
|---|---|---|
embedded |
SPA apps | Form renders inline in your page |
modal |
Quick purchases | Form appears in a dialog overlay |
redirect |
Simple integration | Full page redirect to Recur |
Basic Implementation
Using useRecur Hook
import { useRecur } from 'recur-tw'
function CheckoutButton({ productId }: { productId: string }) {
const { checkout, isLoading } = useRecur()
const handleClick = async () => {
await checkout({
productId,
// Or use productSlug: 'pro-plan'
// Optional: Pre-fill customer info
customerEmail: 'user@example.com',
customerName: 'John Doe',
// Optional: Link to your user system
externalCustomerId: 'user_123',
// Callbacks
onPaymentComplete: (result) => {
console.log('Success!', result)
// result.id - Subscription/Order ID
// result.status - 'ACTIVE', 'TRIALING', etc.
},
onPaymentFailed: (error) => {
console.error('Failed:', error)
return { action: 'retry' } // or 'close' or 'custom'
},
onPaymentCancel: () => {
console.log('User cancelled')
},
})
}
return (
<button onClick={handleClick} disabled={isLoading}>
{isLoading ? 'Processing...' : 'Subscribe'}
</button>
)
}
Using useSubscribe Hook (with state management)
import { useSubscribe } from 'recur-tw'
function SubscribeButton({ productId }: { productId: string }) {
const { subscribe, isLoading, error, subscription } = useSubscribe()
const handleClick = () => {
subscribe({
productId,
onPaymentComplete: (sub) => {
// Subscription created successfully
router.push('/dashboard')
},
})
}
if (subscription) {
return <p>Subscribed! ID: {subscription.id}</p>
}
return (
<>
<button onClick={handleClick} disabled={isLoading}>
Subscribe
</button>
{error && <p className="error">{error.message}</p>}
</>
)
}
Embedded Mode Setup
For embedded mode, you need a container element:
// In RecurProvider config
<RecurProvider
config={{
publishableKey: process.env.NEXT_PUBLIC_RECUR_PUBLISHABLE_KEY,
checkoutMode: 'embedded',
containerElementId: 'recur-checkout-container',
}}
>
{children}
</RecurProvider>
// In your checkout page
function CheckoutPage() {
return (
<div>
<h1>Complete Your Purchase</h1>
{/* Recur will render the payment form here */}
<div id="recur-checkout-container" />
</div>
)
}
Handling 3D Verification
Recur handles 3D Secure automatically. For mobile apps or specific flows:
await checkout({
productId,
// These URLs are used when 3D verification requires redirect
successUrl: 'https://yourapp.com/checkout/success',
cancelUrl: 'https://yourapp.com/checkout/cancel',
})
Product Types
Recur supports different product types:
// Subscription (recurring)
checkout({ productId: 'prod_subscription_xxx' })
// One-time purchase
checkout({ productId: 'prod_onetime_xxx' })
// Credits (prepaid wallet)
checkout({ productId: 'prod_credits_xxx' })
// Donation (variable amount)
checkout({ productId: 'prod_donation_xxx' })
Listing Products
import { useProducts } from 'recur-tw'
function PricingPage() {
const { products, isLoading } = useProducts({
type: 'SUBSCRIPTION', // Filter by type
})
if (isLoading) return <div>Loading...</div>
return (
<div className="pricing-grid">
{products.map(product => (
<PricingCard key={product.id} product={product} />
))}
</div>
)
}
Payment Failed Handling
onPaymentFailed: (error) => {
// error.code tells you what went wrong
switch (error.code) {
case 'CARD_DECLINED':
return { action: 'retry' }
case 'INSUFFICIENT_FUNDS':
return {
action: 'custom',
customTitle: '餘額不足',
customMessage: '請使用其他付款方式',
}
default:
return { action: 'close' }
}
}
Server-Side Checkout (API)
For server-rendered apps or custom flows:
// Create checkout session
const response = await fetch('https://api.recur.tw/v1/checkouts', {
method: 'POST',
headers: {
'X-Recur-Secret-Key': process.env.RECUR_SECRET_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
productId: 'prod_xxx',
customerEmail: 'user@example.com',
successUrl: 'https://yourapp.com/success',
cancelUrl: 'https://yourapp.com/cancel',
}),
})
const { checkoutUrl } = await response.json()
// Redirect user to checkoutUrl
Checkout Result Structure
interface CheckoutResult {
id: string // Subscription or Order ID
status: string // 'ACTIVE', 'TRIALING', 'PENDING'
productId: string
amount: number // In cents (e.g., 29900 = NT$299)
billingPeriod?: string // 'MONTHLY', 'YEARLY' for subscriptions
currentPeriodEnd?: string // ISO date
trialEndsAt?: string // ISO date if trial
}
Best Practices
- Always handle all callbacks - onPaymentComplete, onPaymentFailed, onPaymentCancel
- Show loading states - Use isLoading to disable buttons during checkout
- Pre-fill customer info - Reduces friction if you already have user data
- Use externalCustomerId - Links Recur customers to your user system
- Test in sandbox first - Use
pk_test_keys during development
Related Skills
/recur-quickstart- Initial SDK setup/recur-webhooks- Receive payment notifications/recur-entitlements- Check subscription access
More from recur-tw/skills
recur-entitlements
Implement access control and permission checking with Recur entitlements API. Use when building paywalls, checking subscription status, gating premium features, or when user mentions "paywall", "權限檢查", "entitlements", "access control", "premium features".
32recur-quickstart
Quick setup guide for Recur payment integration. Use when starting a new Recur integration, setting up API keys, installing the SDK, or when user mentions "integrate Recur", "setup Recur", "Recur 串接", "金流設定".
31recur-webhooks
Set up and handle Recur webhook events for payment notifications. Use when implementing webhook handlers, verifying signatures, handling subscription events, or when user mentions "webhook", "付款通知", "訂閱事件", "payment notification".
30recur-help
List all available Recur skills and how to use them. Use when user asks "what can Recur do", "Recur skills", "Recur 有什麼功能", "help with Recur", "如何使用 Recur skills".
28recur-portal
Implement Customer Portal for subscription self-service. Use when building account pages, letting customers manage subscriptions, update payment methods, view billing history, or when user mentions "customer portal", "帳戶管理", "訂閱管理", "更新付款方式", "self-service".
27