xiaohongshu
xiaohongshu
lemonsqueezy
Integrates payments and subscriptions with Lemon Squeezy merchant of record platform. Use when selling digital products, SaaS subscriptions, or software licenses with built-in tax handling.
Full skill instructions
Merchant of record platform for digital products and SaaS. Handles payments, taxes, and compliance globally. Official JavaScript SDK for server-side integration.
npm install @lemonsqueezy/lemonsqueezy.js
import { lemonSqueezySetup, getAuthenticatedUser } from '@lemonsqueezy/lemonsqueezy.js';
lemonSqueezySetup({
apiKey: process.env.LEMONSQUEEZY_API_KEY,
onError: (error) => console.error('Lemon Squeezy Error:', error),
});
// Verify setup
const { data, error } = await getAuthenticatedUser();
if (error) {
console.error('Auth failed:', error.message);
} else {
console.log('Connected as:', data.attributes.name);
}
Generate checkout URLs for customers to purchase.
import { createCheckout } from '@lemonsqueezy/lemonsqueezy.js';
async function createPaymentCheckout(variantId: string, customerEmail: string) {
const { data, error } = await createCheckout(process.env.LEMONSQUEEZY_STORE_ID!, {
productOptions: {
redirectUrl: 'https://myapp.com/success',
receiptButtonText: 'Go to Dashboard',
receiptThankYouNote: 'Thank you for your purchase!',
},
checkoutOptions: {
embed: true,
media: true,
logo: true,
},
checkoutData: {
email: customerEmail,
custom: {
userId: 'user_123',
},
},
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), // 24 hours
preview: false,
}, {
relationships: {
variant: {
data: {
type: 'variants',
id: variantId,
},
},
},
});
if (error) throw new Error(error.message);
return data.attributes.url;
}
const { data } = await createCheckout(storeId, {
checkoutData: {
discountCode: 'SAVE20',
email: customerEmail,
},
}, {
relationships: {
variant: {
data: { type: 'variants', id: variantId },
},
},
});
import { listProducts, listVariants, getProduct, getVariant } from '@lemonsqueezy/lemonsqueezy.js';
// List all products
const { data: products } = await listProducts({
filter: { storeId: process.env.LEMONSQUEEZY_STORE_ID },
});
products.forEach((product) => {
console.log(product.attributes.name, product.attributes.price_formatted);
});
// Get single product
const { data: product } = await getProduct('prod_123');
// List variants for a product
const { data: variants } = await listVariants({
filter: { productId: 'prod_123' },
});
// Get variant details
const { data: variant } = await getVariant('var_123');
import {
listSubscriptions,
getSubscription,
updateSubscription,
cancelSubscription,
} from '@lemonsqueezy/lemonsqueezy.js';
// List user's subscriptions
const { data: subscriptions } = await listSubscriptions({
filter: {
storeId: process.env.LEMONSQUEEZY_STORE_ID,
userEmail: '[email protected]',
},
});
// Get subscription details
const { data: subscription } = await getSubscription('sub_123');
console.log('Status:', subscription.attributes.status);
console.log('Renews at:', subscription.attributes.renews_at);
// Pause subscription
await updateSubscription('sub_123', {
pause: {
mode: 'void', // or 'free'
resumesAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
},
});
// Resume subscription
await updateSubscription('sub_123', {
pause: null,
});
// Change plan (upgrade/downgrade)
await updateSubscription('sub_123', {
variantId: 'new_variant_id',
invoiceImmediately: true,
});
// Cancel subscription
await cancelSubscription('sub_123');
import {
listLicenseKeys,
getLicenseKey,
updateLicenseKey,
activateLicense,
validateLicense,
deactivateLicense,
} from '@lemonsqueezy/lemonsqueezy.js';
// List license keys
const { data: licenses } = await listLicenseKeys({
filter: { orderId: 'order_123' },
});
// Activate license (no API key required)
const { data: activation } = await activateLicense('LICENSE-KEY-HERE', 'instance-name');
console.log('License valid:', activation.valid);
console.log('Activations:', activation.license_key.activation_usage);
// Validate license (no API key required)
const { data: validation } = await validateLicense('LICENSE-KEY-HERE', 'instance-name');
if (validation.valid) {
console.log('License is active');
} else {
console.log('Invalid:', validation.error);
}
// Deactivate license (no API key required)
await deactivateLicense('LICENSE-KEY-HERE', 'instance-id');
// Disable/enable license key (requires API key)
await updateLicenseKey('lk_123', {
disabled: true,
});
import { listOrders, getOrder, listOrderItems, generateOrderInvoice } from '@lemonsqueezy/lemonsqueezy.js';
// List orders
const { data: orders } = await listOrders({
filter: {
storeId: process.env.LEMONSQUEEZY_STORE_ID,
userEmail: '[email protected]',
},
});
// Get order details
const { data: order } = await getOrder('order_123');
console.log('Total:', order.attributes.total_formatted);
console.log('Status:', order.attributes.status);
// Get order items
const { data: items } = await listOrderItems({
filter: { orderId: 'order_123' },
});
// Generate invoice PDF
const { data: invoice } = await generateOrderInvoice('order_123');
console.log('Invoice URL:', invoice.attributes.url);
import {
createCustomer,
getCustomer,
listCustomers,
updateCustomer,
archiveCustomer,
} from '@lemonsqueezy/lemonsqueezy.js';
// Create customer
const { data: customer } = await createCustomer(process.env.LEMONSQUEEZY_STORE_ID!, {
name: 'John Doe',
email: '[email protected]',
city: 'New York',
country: 'US',
});
// List customers
const { data: customers } = await listCustomers({
filter: { storeId: process.env.LEMONSQUEEZY_STORE_ID },
});
// Update customer
await updateCustomer('cust_123', {
name: 'Jane Doe',
});
// Archive customer
await archiveCustomer('cust_123');
import {
createDiscount,
listDiscounts,
getDiscount,
deleteDiscount,
} from '@lemonsqueezy/lemonsqueezy.js';
// Create discount
const { data: discount } = await createDiscount(process.env.LEMONSQUEEZY_STORE_ID!, {
name: 'Summer Sale',
code: 'SUMMER2024',
amount: 20,
amountType: 'percent', // or 'fixed'
isLimitedToProducts: false,
isLimitedRedemptions: true,
maxRedemptions: 100,
startsAt: new Date().toISOString(),
expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
});
// List discounts
const { data: discounts } = await listDiscounts({
filter: { storeId: process.env.LEMONSQUEEZY_STORE_ID },
});
// Delete discount
await deleteDiscount('disc_123');
import { createWebhook, listWebhooks } from '@lemonsqueezy/lemonsqueezy.js';
import crypto from 'crypto';
// Create webhook programmatically
const { data: webhook } = await createWebhook(process.env.LEMONSQUEEZY_STORE_ID!, {
url: 'https://myapp.com/api/webhooks/lemonsqueezy',
events: [
'order_created',
'subscription_created',
'subscription_updated',
'subscription_cancelled',
'subscription_payment_success',
'subscription_payment_failed',
'license_key_created',
],
secret: process.env.LEMONSQUEEZY_WEBHOOK_SECRET,
});
// app/api/webhooks/lemonsqueezy/route.ts
import { NextRequest, NextResponse } from 'next/server';
import crypto from 'crypto';
export async function POST(request: NextRequest) {
const rawBody = await request.text();
const signature = request.headers.get('x-signature');
// Verify signature
const hmac = crypto.createHmac('sha256', process.env.LEMONSQUEEZY_WEBHOOK_SECRET!);
const digest = hmac.update(rawBody).digest('hex');
if (signature !== digest) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
}
const payload = JSON.parse(rawBody);
const eventName = payload.meta.event_name;
const data = payload.data;
switch (eventName) {
case 'order_created':
console.log('New order:', data.id);
// Fulfill order, send email, etc.
break;
case 'subscription_created':
console.log('New subscription:', data.id);
// Grant access, update database
break;
case 'subscription_updated':
console.log('Subscription updated:', data.attributes.status);
// Handle plan changes, pauses
break;
case 'subscription_cancelled':
console.log('Subscription cancelled:', data.id);
// Revoke access, send win-back email
break;
case 'subscription_payment_success':
console.log('Payment received');
// Update billing records
break;
case 'subscription_payment_failed':
console.log('Payment failed');
// Notify customer, retry logic
break;
case 'license_key_created':
console.log('License created:', data.attributes.key);
// Send license to customer
break;
}
return NextResponse.json({ received: true });
}
For client-side checkout overlays.
<script src="https://app.lemonsqueezy.com/js/lemon.js" defer></script>
<a href="https://mystore.lemonsqueezy.com/checkout/buy/abc123" class="lemonsqueezy-button">
Buy Now
</a>
// Initialize
window.createLemonSqueezy();
// Open checkout programmatically
window.LemonSqueezy.Url.Open('https://mystore.lemonsqueezy.com/checkout/buy/abc123');
// Listen to events
window.LemonSqueezy.Setup({
eventHandler: (event) => {
if (event.event === 'Checkout.Success') {
console.log('Purchase complete!', event.data);
}
},
});
import { createUsageRecord, listUsageRecords } from '@lemonsqueezy/lemonsqueezy.js';
// Report usage
const { data: record } = await createUsageRecord({
subscriptionItemId: 'si_123',
quantity: 100,
action: 'increment', // or 'set'
});
// List usage records
const { data: records } = await listUsageRecords({
filter: { subscriptionItemId: 'si_123' },
});
// app/actions/billing.ts
'use server';
import {
createCheckout,
cancelSubscription,
updateSubscription,
} from '@lemonsqueezy/lemonsqueezy.js';
import { auth } from '@/lib/auth';
export async function createCheckoutAction(variantId: string) {
const session = await auth();
if (!session?.user) throw new Error('Unauthorized');
const { data, error } = await createCheckout(
process.env.LEMONSQUEEZY_STORE_ID!,
{
checkoutData: {
email: session.user.email,
custom: { userId: session.user.id },
},
},
{
relationships: {
variant: { data: { type: 'variants', id: variantId } },
},
}
);
if (error) throw new Error(error.message);
return data.attributes.url;
}
export async function cancelSubscriptionAction(subscriptionId: string) {
const session = await auth();
if (!session?.user) throw new Error('Unauthorized');
// Verify ownership before cancelling
await cancelSubscription(subscriptionId);
return { success: true };
}
LEMONSQUEEZY_API_KEY=your_api_key
LEMONSQUEEZY_STORE_ID=your_store_id
LEMONSQUEEZY_WEBHOOK_SECRET=your_webhook_secret
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience