This commit is contained in:
2026-04-12 01:06:31 +07:00
commit 10d660cbcb
1066 changed files with 228596 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
# Creem.io API Reference
## Checkout Sessions
### Create Checkout Session
```javascript
// POST /v1/checkout/sessions
const session = await creem.checkout.sessions.create({
product_id: 'prod_xxx',
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/cancel',
customer_email: 'user@example.com', // Optional
metadata: { order_id: '123' } // Optional
});
// Returns: { url: 'https://checkout.creem.io/xxx', id: 'cs_xxx' }
```
## Products
### Create Product
```javascript
// POST /v1/products
const product = await creem.products.create({
name: 'Pro Plan',
description: 'Full access to all features',
price: 2900, // Amount in cents
currency: 'usd',
recurring: { // Optional - for subscriptions
interval: 'month',
interval_count: 1
}
});
```
### Retrieve Product
```javascript
// GET /v1/products/:id
const product = await creem.products.retrieve('prod_xxx');
```
## Transactions
### Retrieve Transaction
```javascript
// GET /v1/transactions/:id
const transaction = await creem.transactions.retrieve('txn_xxx');
```
### List Transactions
```javascript
// GET /v1/transactions
const transactions = await creem.transactions.list({
customer_id: 'cus_xxx', // Optional filter
product_id: 'prod_xxx', // Optional filter
status: 'completed', // Optional filter
limit: 25,
starting_after: 'txn_xxx' // Pagination cursor
});
```
## Customers
### Retrieve Customer
```javascript
// GET /v1/customers/:id
const customer = await creem.customers.retrieve('cus_xxx');
// GET /v1/customers/email/:email
const customer = await creem.customers.retrieveByEmail('user@example.com');
```
### List Customers
```javascript
// GET /v1/customers
const customers = await creem.customers.list({
limit: 25,
starting_after: 'cus_xxx'
});
```
### Generate Portal Link
```javascript
// POST /v1/customers/:id/portal
const portal = await creem.customers.createPortalSession('cus_xxx');
// Returns: { url: 'https://portal.creem.io/xxx' }
```
## Discount Codes
### Create Discount
```javascript
// POST /v1/discounts
const discount = await creem.discounts.create({
code: 'LAUNCH20',
type: 'percentage', // or 'fixed'
value: 20, // 20% or 20 cents
expires_at: '2024-12-31T23:59:59Z',
max_redemptions: 100 // Optional
});
```
### Retrieve Discount
```javascript
// GET /v1/discounts/:code
const discount = await creem.discounts.retrieve('LAUNCH20');
```
### Delete Discount
```javascript
// DELETE /v1/discounts/:code
await creem.discounts.delete('LAUNCH20');
```
## Error Handling
```javascript
try {
const session = await creem.checkout.sessions.create({...});
} catch (error) {
if (error.type === 'invalid_request_error') {
console.error('Invalid parameters:', error.message);
} else if (error.type === 'authentication_error') {
console.error('Invalid API key');
} else if (error.type === 'rate_limit_error') {
console.error('Rate limited, retry after:', error.retry_after);
}
}
```

View File

@@ -0,0 +1,99 @@
# Creem.io Checkouts
## Checkout Options
1. **Programmatic Sessions** - Full API control
2. **Checkout Links** - No-code, shareable URLs
3. **Storefronts** - Hosted product pages
## Create Checkout Session
```javascript
const session = await creem.checkout.sessions.create({
product_id: 'prod_xxx',
success_url: 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel_url: 'https://example.com/cancel',
// Optional parameters
customer_email: 'user@example.com',
customer_id: 'cus_xxx', // Existing customer
quantity: 1, // For seat-based products
discount_code: 'LAUNCH20', // Pre-apply discount
metadata: {
order_id: '123',
referral_code: 'abc'
},
// Custom fields
custom_fields: [
{ key: 'company', label: 'Company Name', required: true }
]
});
// Redirect user to checkout
redirect(session.url);
```
## Checkout Customization
Configure in dashboard or via API:
- **Branding**: Logo, colors, themes
- **Email Receipts**: Custom templates
- **Localization**: Auto-detect or force language (42 supported)
- **Custom Fields**: Collect additional data
## Retrieve Session
```javascript
// GET /v1/checkout/sessions/:id
const session = await creem.checkout.sessions.retrieve('cs_xxx');
// Returns: { id, status, customer_id, product_id, amount, metadata, ... }
```
## Success URL Parameters
Creem replaces `{CHECKOUT_SESSION_ID}` in success URL:
```javascript
// Frontend: parse session ID from URL
const urlParams = new URLSearchParams(window.location.search);
const sessionId = urlParams.get('session_id');
// Backend: verify and fulfill
const session = await creem.checkout.sessions.retrieve(sessionId);
if (session.status === 'complete') {
await fulfillOrder(session);
}
```
## No-Code Checkout Links
Create in dashboard - shareable URLs for any product. Good for:
- Social media links
- Email campaigns
- Quick sales without integration
## Storefronts
Hosted product pages - display multiple products without custom website:
1. Configure storefront in dashboard
2. Add products to display
3. Share storefront URL
4. Customers browse and checkout
## Cart Abandonment Recovery
Enable in dashboard - automatic emails sent when checkout abandoned:
- Configurable delay before sending
- Customizable email content
- Include discount code incentive
## Embedding (Coming)
For embedded checkout in your site, see SDK adapters:
- Next.js Adapter
- React components
See `references/creem/sdk.md` for implementation details.

View File

@@ -0,0 +1,136 @@
# Creem.io Licensing
Software licensing with device activation management.
## License Flow
```
purchase → license_key issued → activate device → validate → deactivate
```
## Activate License
Register a device against a license key:
```javascript
// POST /v1/licenses/activate
const activation = await creem.licenses.activate({
license_key: 'XXXX-XXXX-XXXX-XXXX',
instance_id: 'device_fingerprint_123', // Unique device identifier
instance_name: 'MacBook Pro' // Optional friendly name
});
// Returns: {
// id: 'act_xxx',
// license_key: '...',
// instance_id: '...',
// activated_at: '...',
// valid_until: '...'
// }
```
## Validate License
Check if license is active for specific device:
```javascript
// POST /v1/licenses/validate
const validation = await creem.licenses.validate({
license_key: 'XXXX-XXXX-XXXX-XXXX',
instance_id: 'device_fingerprint_123'
});
// Returns: {
// valid: true,
// license_key: '...',
// product_id: 'prod_xxx',
// customer_id: 'cus_xxx',
// expires_at: '2025-01-15T00:00:00Z',
// activations_used: 2,
// activations_limit: 5
// }
```
## Deactivate License
Remove device activation to free slot:
```javascript
// POST /v1/licenses/deactivate
await creem.licenses.deactivate({
license_key: 'XXXX-XXXX-XXXX-XXXX',
instance_id: 'device_fingerprint_123'
});
```
## Client-Side Implementation
```javascript
// Desktop app example (Electron, Tauri, etc.)
class LicenseManager {
constructor(apiKey) {
this.apiKey = apiKey;
this.instanceId = this.getDeviceFingerprint();
}
getDeviceFingerprint() {
// Generate unique device ID (machine ID, hardware hash, etc.)
return require('node-machine-id').machineIdSync();
}
async activate(licenseKey) {
const response = await fetch('https://api.creem.io/v1/licenses/activate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
license_key: licenseKey,
instance_id: this.instanceId,
instance_name: os.hostname()
})
});
return response.json();
}
async validate(licenseKey) {
const response = await fetch('https://api.creem.io/v1/licenses/validate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
license_key: licenseKey,
instance_id: this.instanceId
})
});
const data = await response.json();
return data.valid;
}
}
```
## Activation Limits
Configure per product - limits simultaneous device activations:
```javascript
const product = await creem.products.create({
name: 'Desktop App License',
price: 4900,
currency: 'usd',
license_config: {
activations_limit: 3 // Max 3 devices per license
}
});
```
## License Events (Webhooks)
- `license.activated` - Device activated
- `license.deactivated` - Device deactivated
- `license.expired` - License expired (subscription ended)
See `references/creem/webhooks.md` for webhook handling.

View File

@@ -0,0 +1,65 @@
# Creem.io Overview
Payment infrastructure platform supporting subscriptions, one-time payments, and licensing. Functions as Merchant of Record (MoR) - handles compliance, taxes, and payment processing.
## Key Features
- **Merchant of Record**: Tax compliance, payment processing, global coverage
- **Subscriptions**: Recurring billing, trials, seat-based, prorations
- **One-Time Payments**: Single charges for products/services
- **Licensing**: Activation keys, device management, validation
- **Checkouts**: Hosted, embedded, no-code options
- **Customer Portal**: Self-service billing management
- **Revenue Splits**: Automatic payment distribution to multiple recipients
## When to Choose Creem
- Global SaaS products requiring MoR
- Software licensing with activation management
- Subscription products with seat-based billing
- Digital product sales with file delivery
- Affiliate/commission programs
- Multi-recipient revenue splitting
## Authentication
```bash
# API Key authentication
curl -H "Authorization: Bearer sk_live_xxx" https://api.creem.io/v1/...
```
Environment variables:
```bash
CREEM_API_KEY=sk_live_xxx # Production
CREEM_API_KEY=sk_test_xxx # Test mode
CREEM_WEBHOOK_SECRET=whsec_xxx # Webhook verification
```
## API Base URLs
- **Production**: `https://api.creem.io/v1`
- **Test Mode**: Use `sk_test_` prefixed API keys
## Rate Limits
Standard API rate limits apply. Check response headers for limit status.
## Global Support
- **Customers**: Hundreds of countries supported
- **Merchants**: Global payouts
- **Languages**: 42 languages for checkout localization
## Related References
- **API Endpoints**: `references/creem/api.md`
- **Webhooks**: `references/creem/webhooks.md`
- **Checkouts**: `references/creem/checkouts.md`
- **Subscriptions**: `references/creem/subscriptions.md`
- **Licensing**: `references/creem/licensing.md`
- **SDKs**: `references/creem/sdk.md`
## External Resources
- **Documentation**: https://docs.creem.io
- **LLM Docs**: https://docs.creem.io/llms.txt

View File

@@ -0,0 +1,161 @@
# Creem.io SDKs
## Official SDKs
### Core SDK (`creem`)
Full API access with maximum flexibility:
```bash
npm install creem
# or
pip install creem
```
```javascript
// Node.js
import Creem from 'creem';
const creem = new Creem({
apiKey: process.env.CREEM_API_KEY
});
// Create checkout
const session = await creem.checkout.sessions.create({
product_id: 'prod_xxx',
success_url: 'https://example.com/success'
});
```
```python
# Python
from creem import Creem
creem = Creem(api_key=os.environ['CREEM_API_KEY'])
session = creem.checkout.sessions.create(
product_id='prod_xxx',
success_url='https://example.com/success'
)
```
### Wrapper SDK (`creem_io`)
Helper functions for common operations:
```bash
npm install creem_io
```
```javascript
import { CreemClient, verifyWebhook } from 'creem_io';
const client = new CreemClient({
apiKey: process.env.CREEM_API_KEY,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET
});
// Simplified webhook verification
app.post('/webhook', async (req, res) => {
const event = client.verifyWebhook(req.body, req.headers['x-creem-signature']);
// Handle event...
});
// Access management helpers
const hasAccess = await client.checkAccess(customerId, productId);
```
## Framework Adapters
### Next.js Adapter
End-to-end billing integration:
```bash
npm install @creem/nextjs
```
```typescript
// app/api/checkout/route.ts
import { createCheckout } from '@creem/nextjs';
export const POST = createCheckout({
productId: 'prod_xxx',
successUrl: '/success',
cancelUrl: '/pricing'
});
// app/api/webhooks/creem/route.ts
import { handleWebhook } from '@creem/nextjs';
export const POST = handleWebhook({
onCheckoutCompleted: async (session) => {
await grantAccess(session.customer_id);
},
onSubscriptionCancelled: async (subscription) => {
await revokeAccess(subscription.customer_id);
}
});
```
### Better Auth Integration
Combined auth + payments:
```bash
npm install @creem/better-auth
```
```typescript
import { betterAuth } from 'better-auth';
import { creemPlugin } from '@creem/better-auth';
export const auth = betterAuth({
plugins: [
creemPlugin({
apiKey: process.env.CREEM_API_KEY,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET,
products: {
pro: 'prod_xxx',
enterprise: 'prod_yyy'
}
})
]
});
// Check subscription in auth session
const session = await auth.getSession();
if (session.user.subscription?.status === 'active') {
// User has active subscription
}
```
### Next.js Template
Pre-built starter with Prisma, shadcn/ui, Tailwind:
```bash
npx create-creem-app my-saas
# or
git clone https://github.com/creem-io/nextjs-template
```
Includes:
- Auth (Better Auth)
- Database (Prisma)
- UI (shadcn/ui, Tailwind)
- Pricing page
- Customer portal
- Webhook handling
## Environment Variables
```bash
# .env
CREEM_API_KEY=sk_live_xxx # or sk_test_xxx for test mode
CREEM_WEBHOOK_SECRET=whsec_xxx
```
## AI Tool Integration
Creem supports Claude Code, Cursor, Windsurf via official skill - this document is part of that integration.

View File

@@ -0,0 +1,129 @@
# Creem.io Subscriptions
## Subscription Lifecycle
```
create → active → [pause] → [resume] → [upgrade] → cancel
```
## Create Subscription
Via checkout session with recurring product:
```javascript
const session = await creem.checkout.sessions.create({
product_id: 'prod_recurring_xxx',
success_url: 'https://example.com/success',
customer_email: 'user@example.com'
});
```
## Retrieve Subscription
```javascript
// GET /v1/subscriptions/:id
const subscription = await creem.subscriptions.retrieve('sub_xxx');
// Returns: { id, status, product_id, current_period_end, ... }
```
## Modify Subscription
### Update Seats/Units
```javascript
// PATCH /v1/subscriptions/:id
const updated = await creem.subscriptions.update('sub_xxx', {
quantity: 10, // Seat count
prorate: true, // Prorate charges
billing_immediately: false
});
```
### Upgrade/Downgrade
```javascript
const updated = await creem.subscriptions.update('sub_xxx', {
product_id: 'prod_higher_tier',
prorate: true
});
```
## Pause Subscription
```javascript
// POST /v1/subscriptions/:id/pause
const paused = await creem.subscriptions.pause('sub_xxx', {
resume_at: '2024-02-01T00:00:00Z' // Optional auto-resume date
});
```
## Resume Subscription
```javascript
// POST /v1/subscriptions/:id/resume
const resumed = await creem.subscriptions.resume('sub_xxx');
```
## Cancel Subscription
```javascript
// POST /v1/subscriptions/:id/cancel
const cancelled = await creem.subscriptions.cancel('sub_xxx', {
at_period_end: true // false = immediate cancellation
});
```
## Free Trials
Configure on product level:
```javascript
const product = await creem.products.create({
name: 'Pro Plan',
price: 2900,
currency: 'usd',
recurring: { interval: 'month' },
trial_period_days: 14
});
```
## Seat-Based Billing
```javascript
const product = await creem.products.create({
name: 'Team Plan',
price: 1000, // Per seat price
currency: 'usd',
recurring: { interval: 'month' },
billing_scheme: 'per_unit'
});
// Checkout with quantity
const session = await creem.checkout.sessions.create({
product_id: 'prod_xxx',
quantity: 5, // 5 seats
success_url: '...'
});
```
## Product Bundles
Group related tiers for upsells:
```javascript
const bundle = await creem.bundles.create({
name: 'Growth Plans',
products: ['prod_starter', 'prod_pro', 'prod_enterprise']
});
```
## Subscription Events (Webhooks)
- `subscription.created` - New subscription started
- `subscription.updated` - Quantity, product, or status changed
- `subscription.paused` - Subscription paused
- `subscription.resumed` - Subscription resumed
- `subscription.cancelled` - Cancellation scheduled or completed
- `subscription.renewed` - Successful renewal charge
See `references/creem/webhooks.md` for webhook handling.

View File

@@ -0,0 +1,120 @@
# Creem.io Webhooks
## Webhook Setup
Configure webhook endpoint in Creem dashboard. Receive events at your endpoint URL.
## Event Types
### Checkout Events
- `checkout.completed` - Payment successful, access granted
- `checkout.abandoned` - Cart abandoned (triggers recovery emails if enabled)
### Subscription Events
- `subscription.created` - New subscription started
- `subscription.updated` - Changes to quantity, product, status
- `subscription.paused` - Subscription paused
- `subscription.resumed` - Subscription resumed
- `subscription.cancelled` - Cancellation scheduled/completed
- `subscription.renewed` - Successful renewal charge
### Payment Events
- `payment.succeeded` - Charge successful
- `payment.failed` - Charge failed
- `refund.created` - Refund processed
- `chargeback.created` - Dispute opened
### License Events
- `license.activated` - Device activated against license
- `license.deactivated` - Device deactivated
## Webhook Payload Structure
```json
{
"id": "evt_xxx",
"type": "checkout.completed",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"object": {
"id": "cs_xxx",
"customer_id": "cus_xxx",
"product_id": "prod_xxx",
"amount": 2900,
"currency": "usd",
"metadata": { "order_id": "123" }
}
}
}
```
## Signature Verification
```javascript
import crypto from 'crypto';
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Express handler
app.post('/webhooks/creem', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-creem-signature'];
const payload = req.body.toString();
if (!verifyWebhook(payload, signature, process.env.CREEM_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(payload);
switch (event.type) {
case 'checkout.completed':
await handleCheckoutCompleted(event.data.object);
break;
case 'subscription.cancelled':
await handleSubscriptionCancelled(event.data.object);
break;
}
res.status(200).send('OK');
});
```
## Idempotency
Store processed event IDs to prevent duplicate processing:
```javascript
async function handleWebhook(event) {
// Check if already processed
const existing = await db.webhookEvents.findOne({ eventId: event.id });
if (existing) return { status: 'already_processed' };
// Process event
await processEvent(event);
// Mark as processed
await db.webhookEvents.create({
eventId: event.id,
type: event.type,
processedAt: new Date()
});
}
```
## Retry Behavior
Creem retries failed webhooks (non-2xx responses). Implement idempotency to handle retries safely.
## Testing Webhooks
Use test mode API keys (`sk_test_`) - events sent to same webhook endpoint with test data.