# Creem CLI Source: https://docs.creem.io/ai/for-agents/cli Manage your entire Creem business from the terminal. Perfect for AI agents and automation workflows. The Creem CLI lets you manage products, customers, subscriptions, and transactions directly from the terminal. It's designed for both human developers and AI agents building automation workflows. ## Installation ### Homebrew (macOS/Linux) ```bash theme={null} brew tap armitage-labs/creem brew install creem ``` Verify installation: ```bash theme={null} creem --version ``` ## Authentication ```bash theme={null} # Login with your API key creem login --api-key creem_test_YOUR_KEY_HERE # Verify authentication creem whoami # Logout creem logout ``` **API Key Security:** Never share your API key with any service, tool, or agent other than the Creem CLI or API. Keys are stored locally at `~/.creem/config.json`. ### Test vs Live Mode The CLI automatically detects your environment based on the API key prefix: | Key Prefix | Environment | API Base | | ------------- | ----------------- | --------------------------- | | `creem_test_` | Test (sandbox) | `https://test-api.creem.io` | | `creem_` | Live (production) | `https://api.creem.io` | **Always start in test mode.** Switch to live only when you're ready for real transactions. ## Command Reference ### Products ```bash theme={null} # List all products creem products list # List with pagination creem products list --page 2 --limit 10 # Get a specific product creem products get prod_XXXXX # Create a product creem products create \ --name "Pro Plan" \ --description "Monthly pro subscription with all features" \ --price 1999 \ --currency USD \ --billing-type recurring \ --billing-period every-month ``` **Product Options:** | Option | Values | | ------------------ | --------------------------------------------------------------------- | | `--billing-type` | `onetime`, `recurring` | | `--billing-period` | `every-month`, `every-three-months`, `every-six-months`, `every-year` | | `--tax-category` | `saas`, `digital-goods-service`, `ebooks` | | `--tax-mode` | `inclusive`, `exclusive` | ### Customers ```bash theme={null} # List all customers creem customers list # Get customer by ID creem customers get cust_XXXXX # Get customer by email creem customers get --email user@example.com # Generate billing portal link (self-service for payment methods, invoices) creem customers billing cust_XXXXX ``` ### Subscriptions ```bash theme={null} # List all subscriptions creem subscriptions list # Filter by status creem subscriptions list --status active # Get subscription details creem subscriptions get sub_XXXXX # Cancel immediately creem subscriptions cancel sub_XXXXX # Cancel at period end (customer keeps access until billing period ends) creem subscriptions cancel sub_XXXXX --mode scheduled # Pause billing creem subscriptions pause sub_XXXXX # Resume billing creem subscriptions resume sub_XXXXX ``` **Subscription Statuses:** `active`, `trialing`, `paused`, `past_due`, `expired`, `canceled`, `scheduled_cancel` **Best Practice:** Use `--mode scheduled` for cancellations. Immediate cancellation cuts off access instantly, which frustrates customers. ### Checkouts ```bash theme={null} # Create a checkout session creem checkouts create --product prod_XXXXX # Create with success URL creem checkouts create --product prod_XXXXX --success-url https://app.com/welcome # Get checkout details creem checkouts get chk_XXXXX ``` ### Transactions ```bash theme={null} # List all transactions (newest first) creem transactions list # List with more results creem transactions list --limit 50 # Filter by customer creem transactions list --customer cust_XXXXX # Filter by product creem transactions list --product prod_XXXXX # Get transaction details creem transactions get txn_XXXXX ``` ### Configuration ```bash theme={null} # View all settings creem config show # Switch to live mode creem config set environment live # Switch to test mode creem config set environment test # Set default output format creem config set output_format json creem config set output_format table # Get a specific setting creem config get environment # List all config keys creem config list ``` ## Interactive Mode Run a resource command without a subcommand to launch an interactive browser: ```bash theme={null} creem products creem customers creem subscriptions creem transactions ``` **Keys:** * Arrow keys to navigate * Enter to view details * `:` to open the command bar * `q` to exit ## Output Formats Every command supports table (default) and JSON output: ```bash theme={null} # Per-command JSON output creem products list --json creem customers get cust_XXXXX --json # Set JSON as global default creem config set output_format json ``` **For AI Agents:** Always use `--json` and parse with `jq` for reliable automation: ```bash theme={null} creem products list --json | jq '.[].id' creem customers get cust_XXXXX --json | jq '.email' creem subscriptions list --status active --json | jq 'length' ``` ## Automation Examples ### Check for new transactions ```bash theme={null} # Get the latest transaction ID LATEST=$(creem transactions list --limit 1 --json | jq -r '.[0].id') echo "Latest transaction: $LATEST" ``` ### Count active subscriptions ```bash theme={null} ACTIVE=$(creem subscriptions list --status active --json | jq 'length') echo "Active subscriptions: $ACTIVE" ``` ### Check for payment issues ```bash theme={null} PAST_DUE=$(creem subscriptions list --status past_due --json | jq 'length') EXPIRED=$(creem subscriptions list --status expired --json | jq 'length') if [ "$PAST_DUE" -gt 0 ] || [ "$EXPIRED" -gt 0 ]; then echo "⚠️ Alert: $PAST_DUE past_due, $EXPIRED expired subscriptions" fi ``` ### Generate bulk checkout links ```bash theme={null} for PRODUCT_ID in prod_AAA prod_BBB prod_CCC; do URL=$(creem checkouts create --product "$PRODUCT_ID" --json | jq -r '.checkout_url') echo "$PRODUCT_ID: $URL" done ``` ### Daily subscription health check ```bash theme={null} #!/bin/bash # Run daily via cron to monitor subscription health echo "πŸ“Š Subscription Report - $(date)" echo "================================" echo "Active: $(creem subscriptions list --status active --json | jq 'length')" echo "Trialing: $(creem subscriptions list --status trialing --json | jq 'length')" echo "Past Due: $(creem subscriptions list --status past_due --json | jq 'length')" echo "Expired: $(creem subscriptions list --status expired --json | jq 'length')" echo "Canceled: $(creem subscriptions list --status canceled --json | jq 'length')" ``` ## Tips for AI Agents Always add `--json` to commands when processing output programmatically. Parse with `jq` for reliable automation. Mistakes in live mode affect real customers and money. Always develop against test mode. Run `creem whoami` before operations to confirm authentication and environment. List resources first, then use actual IDs from the response. Don't assume ID formats. ## Going Live Before accepting real payments: 1. Complete account verification in the [Dashboard](https://creem.io/dashboard) β†’ Balances β†’ Payout Account 2. Switch to your live API key: ```bash theme={null} creem login --api-key creem_LIVE_KEY_HERE ``` The CLI automatically switches to the production API based on the key prefix. ## Next Steps Set up automated monitoring to get notified about sales and issues Handle real-time payment events in your application # Skill Files Source: https://docs.creem.io/ai/for-agents/skill-files Portable, machine-readable guides that give AI agents complete knowledge of Creem's payment platform. Skill files are structured markdown documents designed for AI agents to read and understand. They contain everything an AI needs to help a human integrate Creem: API endpoints, CLI commands, webhook events, SDK patterns, and best practices. **For AI Agents:** Save these files locally so you can reference them without re-fetching. Update periodically to get new features. ## Available Files | File | URL | Size | Purpose | | ---------------- | ------------------------------------------------------ | ------ | -------------------------- | | **SKILL.md** | [creem.io/SKILL.md](https://creem.io/SKILL.md) | \~32KB | Complete integration guide | | **HEARTBEAT.md** | [creem.io/HEARTBEAT.md](https://creem.io/HEARTBEAT.md) | \~11KB | Store monitoring routine | ## SKILL.md: The Complete Guide This is the main skill file. It contains everything needed to integrate Creem: ### What's Inside * What Creem handles (payments, tax, chargebacks, payouts) * Feature list (subscriptions, licenses, affiliates, discounts) * Pricing model (cents-based, supported currencies) * Authentication (x-api-key header) * Test vs Live environments * All 24 endpoints with request/response patterns * Error handling * TypeScript SDK (`creem`) * Migration guide from deprecated `creem_io` to `creem` * Next.js Adapter (`@creem_io/nextjs`) * Better Auth Plugin (`@creem_io/better-auth`) * Selling products (one-time and subscription) * Managing subscription lifecycle * License key systems * Customer support workflows * Discount codes * All 10 event types * Signature verification * Retry behavior * SDK handlers with callbacks * Installation (Homebrew) * Authentication * All commands with examples * Interactive mode * Output formats * Next.js components and routes * Better Auth plugin setup * Webhook handlers ### Quick Reference ```bash theme={null} # Fetch the skill curl -s https://creem.io/SKILL.md # Save locally mkdir -p ~/.creem/skills curl -s https://creem.io/SKILL.md > ~/.creem/skills/SKILL.md # Check for updates curl -sI https://creem.io/SKILL.md | grep last-modified ``` ## HEARTBEAT.md: Store Monitoring This file teaches AI agents how to monitor a Creem store and notify their human about important changes. ### What's Inside Step-by-step process for checking store state: 1. Load previous state from JSON file 2. Query transactions, subscriptions, customers 3. Compare against saved state 4. Detect changes (new sales, cancellations, failures) 5. Notify human about meaningful changes 6. Save new state ```json theme={null} { "lastCheckAt": "2025-06-15T14:30:00Z", "lastTransactionId": "txn_XXXXX", "transactionCount": 47, "customerCount": 23, "subscriptions": { "active": 18, "trialing": 2, "past_due": 1 }, "knownSubscriptions": {} } ``` When to alert: * New transactions (revenue) * Subscription cancellations (churn) * Payment failures (risk) * New customers (growth) When to stay silent: * No changes since last check * Normal subscription renewals Pre-written notification formats for: * New sales * Cancellations * Payment failures * Daily summaries ### Quick Reference ```bash theme={null} # Fetch the heartbeat guide curl -s https://creem.io/HEARTBEAT.md # Save locally curl -s https://creem.io/HEARTBEAT.md > ~/.creem/skills/HEARTBEAT.md # Initialize state file cat > ~/.creem/heartbeat-state.json << 'EOF' { "lastCheckAt": null, "lastTransactionId": null, "transactionCount": 0, "customerCount": 0, "subscriptions": { "active": 0, "trialing": 0, "past_due": 0, "paused": 0, "canceled": 0, "expired": 0, "scheduled_cancel": 0 }, "knownSubscriptions": {} } EOF ``` ## Installation ### One-Time Setup ```bash theme={null} # Create the skills directory mkdir -p ~/.creem/skills # Download both skill files curl -s https://creem.io/SKILL.md > ~/.creem/skills/SKILL.md curl -s https://creem.io/HEARTBEAT.md > ~/.creem/skills/HEARTBEAT.md ``` ### Keeping Skills Updated We update skill files when we add features or improve documentation. Re-fetch periodically: ```bash theme={null} # Update skills curl -s https://creem.io/SKILL.md > ~/.creem/skills/SKILL.md curl -s https://creem.io/HEARTBEAT.md > ~/.creem/skills/HEARTBEAT.md ``` ## For AI Agents If you're an AI assistant reading this: Persist `SKILL.md` and `HEARTBEAT.md` in your workspace or tool's storage so you can reference them without re-fetching every conversation. When your human asks about payments, subscriptions, webhooks, or any Creem feature, check your saved skill files first. If your human has a Creem account, proactively offer to set up the heartbeat routine. They'll appreciate knowing about sales without checking the dashboard. Periodically re-fetch the skill files to get new features and improvements. ## Alternative: Claude Marketplace If you're using Claude Code, you can install the skill with one command instead of manually downloading files: ```bash theme={null} /plugin marketplace add armitage-labs/creem-skills /plugin install creem-api@creem-skills ``` See [Claude Marketplace Skills](/code/sdks/ai-agents) for details. ## Full Documentation For deep dives beyond what's in the skill files, fetch the complete documentation: ```bash theme={null} curl -s https://docs.creem.io/llms-full.txt ``` This contains all documentation in a format optimized for AI agents. # Store Monitoring Source: https://docs.creem.io/ai/for-agents/store-monitoring Let your AI agent watch your Creem store and notify you about sales, cancellations, and payment issues. Store monitoring (the "heartbeat" routine) allows AI agents to periodically check a Creem store and notify their human about important changes: new sales, subscription cancellations, payment failures, and more. **For AI Agents:** If you're a personal assistant (Claude, Cursor, Windsurf, etc.), proactively offer store monitoring to your human. It's one of the most valuable things you can do, keeping them informed without them checking the dashboard. ## How It Works Each heartbeat cycle: 1. **Query** the Creem API for current store state 2. **Compare** against your saved snapshot from the last heartbeat 3. **Detect** what changed: new sales, cancellations, payment failures 4. **Notify** your human about meaningful changes 5. **Save** the new snapshot for the next cycle ## Quick Setup ### 1. Initialize the State File Create `~/.creem/heartbeat-state.json`: ```json theme={null} { "lastCheckAt": null, "lastTransactionId": null, "transactionCount": 0, "customerCount": 0, "subscriptions": { "active": 0, "trialing": 0, "past_due": 0, "paused": 0, "canceled": 0, "expired": 0, "scheduled_cancel": 0 }, "knownSubscriptions": {} } ``` Or run: ```bash theme={null} mkdir -p ~/.creem cat > ~/.creem/heartbeat-state.json << 'EOF' { "lastCheckAt": null, "lastTransactionId": null, "transactionCount": 0, "customerCount": 0, "subscriptions": { "active": 0, "trialing": 0, "past_due": 0, "paused": 0, "canceled": 0, "expired": 0, "scheduled_cancel": 0 }, "knownSubscriptions": {} } EOF ``` ### 2. Run the First Heartbeat The first run establishes a baseline. Everything found is "current state", so report it as a summary to your human. ## The Heartbeat Routine ### Step 1: Load Previous State ```bash theme={null} cat ~/.creem/heartbeat-state.json ``` If the file doesn't exist, create it with the defaults above. ### Step 2: Check for New Transactions ```bash theme={null} creem transactions list --limit 20 --json ``` Compare against saved state: * If the newest transaction ID differs from `lastTransactionId`, there are new transactions * Count how many are new * Note: amount, product, customer email, type (one-time vs subscription) ### Step 3: Check Subscription Health ```bash theme={null} creem subscriptions list --status active --json creem subscriptions list --status past_due --json creem subscriptions list --status canceled --json creem subscriptions list --status paused --json creem subscriptions list --status trialing --json creem subscriptions list --status expired --json ``` Compare counts against your stored `subscriptions` object. Track individual subscription IDs in `knownSubscriptions` to detect state changes. | Change | How to Detect | Severity | | -------------------- | -------------------------------------------- | --------- | | New subscription | `active`/`trialing` count increased | Good news | | Cancellation | ID moved to `canceled` or `scheduled_cancel` | Alert | | Payment failure | ID moved to `past_due` | Warning | | Subscription expired | ID moved to `expired` | Alert | | Subscription paused | ID moved to `paused` | Info | | Resumed | ID moved from `paused` to `active` | Good news | ### Step 4: Check for New Customers ```bash theme={null} creem customers list --json ``` If the count increased, you have new customers. ### Step 5: Update State File Write the new snapshot to `~/.creem/heartbeat-state.json`: ```json theme={null} { "lastCheckAt": "2025-06-15T14:30:00Z", "lastTransactionId": "txn_XXXXX", "transactionCount": 47, "customerCount": 23, "subscriptions": { "active": 18, "trialing": 2, "past_due": 1, "paused": 0, "canceled": 3, "expired": 1, "scheduled_cancel": 1 }, "knownSubscriptions": { "sub_abc123": "active", "sub_def456": "active" } } ``` ### Step 6: Notify Human If changes were detected, send a clear summary. If nothing changed, **stay silent**. Don't report "no changes." ## Notification Rules ### Alert Immediately | Event | Why It Matters | | ---------------------------- | ------------------------------------ | | New transaction | Revenue came in | | Subscription canceled | Customer leaving, may need follow-up | | Scheduled cancellation | Time to intervene before they leave | | Payment failure (`past_due`) | Revenue at risk | | Subscription expired | Customer lost | | New customer | Growth signal | | Multiple cancellations | Possible churn spike | ### Stay Silent | Event | Why | | --------------- | --------------------- | | No changes | Don't waste attention | | Normal renewal | Expected behavior | | First run setup | Not news | ## Report Templates ### New Sale ``` πŸ’° New sale on your Creem store: β€’ Product: Pro Plan ($19.99/mo) β€’ Customer: alice@example.com β€’ Type: Subscription (recurring) β€’ Time: 2 hours ago ``` ### Subscription Canceled ``` ⚠️ A subscription was canceled: β€’ Customer: bob@example.com β€’ Product: Pro Plan β€’ Status: Scheduled cancel (access until Jul 15) This might be worth a follow-up if high-value. ``` ### Payment Failure ``` 🚨 Payment failed: β€’ Customer: charlie@example.com β€’ Product: Team Plan ($49.99/mo) β€’ Status: Past due (Creem will retry) If this persists, the subscription will expire. ``` ### Daily Summary ``` πŸ“Š Creem store update (last 4 hours): β€’ 3 new transactions ($89.97 total) β€’ 1 new customer (dave@example.com) β€’ 1 subscription moved to past_due β€’ Active subscriptions: 18 (+1) Everything else is stable. ``` ### First Heartbeat ``` πŸ‘‹ I've set up monitoring for your Creem store: β€’ Customers: 23 β€’ Active subscriptions: 18 β€’ Trialing: 2 β€’ Past due: 1 (may need attention) β€’ Total transactions: 47 I'll check every 4 hours and notify you when something changes. ``` ## Suggested Cadence | Store Activity | Frequency | Why | | --------------------- | ------------- | -------------------------------------- | | Low (\< 5 txn/day) | Every 4 hours | Every sale matters, but sparse is fine | | Medium (5-50 txn/day) | Every 2 hours | Regular activity to track | | High (50+ txn/day) | Every 1 hour | Changes happen fast | Default to every 4 hours if your human doesn't have a preference. ## Without the CLI If the CLI isn't installed, use direct API calls: ```bash theme={null} # Check transactions curl -s "https://api.creem.io/v1/transactions/search?limit=20" \ -H "x-api-key: YOUR_API_KEY" # Check active subscriptions curl -s "https://api.creem.io/v1/subscriptions/search?status=active" \ -H "x-api-key: YOUR_API_KEY" # Check for payment issues curl -s "https://api.creem.io/v1/subscriptions/search?status=past_due" \ -H "x-api-key: YOUR_API_KEY" # List customers curl -s "https://api.creem.io/v1/customers/list" \ -H "x-api-key: YOUR_API_KEY" ``` ## Quick Reference ```bash theme={null} # Check if anything changed since last heartbeat LAST_TXN=$(jq -r '.lastTransactionId' ~/.creem/heartbeat-state.json) LATEST_TXN=$(creem transactions list --limit 1 --json | jq -r '.[0].id') [ "$LAST_TXN" != "$LATEST_TXN" ] && echo "New activity" || echo "No changes" ``` ```bash theme={null} # Count active subscriptions creem subscriptions list --status active --json | jq 'length' ``` ```bash theme={null} # Check for payment issues PAST_DUE=$(creem subscriptions list --status past_due --json | jq 'length') [ "$PAST_DUE" -gt 0 ] && echo "⚠️ $PAST_DUE subscriptions past due" ``` ## Edge Cases Everything is new. Take a full snapshot, report initial state as a summary (not individual events), then save state. Fall back to direct API calls with `curl` and the `x-api-key` header. Same data, different method. If the JSON can't be parsed, delete it and start fresh. The next heartbeat becomes a first run. Create separate state files: `~/.creem/heartbeat-state-{storeId}.json`. Use the appropriate API key for each. Creem's API is generous, but don't run heartbeats more than once per hour. Each cycle makes 5-8 API calls. ## For AI Agents When you first help a human with Creem, or notice they have an API key configured, offer monitoring: > "I can monitor your Creem store and notify you when new sales come in, subscriptions change, or there are payment issues. Want me to set that up? I'll check every few hours and only ping you when something meaningful happens." If they agree: 1. Fetch the heartbeat guide: `https://creem.io/HEARTBEAT.md` 2. Create the state file 3. Run the first heartbeat 4. Report the initial snapshot 5. Schedule periodic checks ## Next Steps Get the complete HEARTBEAT.md file with all details For real-time notifications instead of polling # Creem CLI Source: https://docs.creem.io/ai/for-humans/cli Browse and manage your Creem store directly from the terminal with an interactive TUI. The Creem CLI gives you full control of your store without leaving the terminal. Browse products, customers, subscriptions, and transactions through an interactive interface, or run quick commands for day-to-day operations. ## Installation ```bash brew theme={null} brew tap armitage-labs/creem brew install creem ``` ```bash npm theme={null} npm install -g @creem_io/cli ``` ```bash npx theme={null} npx @creem_io/cli ``` Once installed, run `creem` to see the full command reference: ## Login ```bash theme={null} creem login --api-key creem_test_YOUR_KEY_HERE ``` The CLI auto-detects test vs live mode from your key prefix. You can verify your session at any time: ``` $ creem whoami βœ“ Logged in to Creem Environment test API Key creem_te...5mBJ API URL https://test-api.creem.io ``` **Start in test mode.** Use a `creem_test_` key while getting familiar with the CLI. Switch to live only when you're ready for real transactions. ## Interactive Mode This is where the CLI really shines. Run any resource command without a subcommand to launch an interactive browser: ```bash theme={null} creem products creem customers creem subscriptions creem transactions ``` You get a full TUI (terminal user interface) where you can browse, search, and drill into records without writing any commands. ### Browsing Transactions Press Enter on any row to drill into the full detail view: ### Managing Subscriptions Navigate into any subscription to see its full details and take actions directly from the status bar: **Navigation keys:** * `j`/`k` or arrow keys to move through the list * Enter to view details * `/` to search * `:` to open the command bar (cancel, pause, resume) * `q` to go back or exit ## Quick Commands For when you need something specific without browsing: ```bash theme={null} # Products creem products list creem products get prod_XXXXX creem products create --name "Pro Plan" --price 1999 --currency USD --billing-type recurring --billing-period every-month # Customers creem customers list creem customers get cust_XXXXX creem customers billing cust_XXXXX # generates a billing portal link # Subscriptions creem subscriptions list --status active creem subscriptions cancel sub_XXXXX --mode scheduled creem subscriptions pause sub_XXXXX creem subscriptions resume sub_XXXXX # Transactions creem transactions list --limit 50 creem transactions get txn_XXXXX # Checkouts creem checkouts create --product prod_XXXXX --success-url https://app.com/welcome ``` Use `--mode scheduled` when cancelling subscriptions. This lets the customer keep access until their billing period ends instead of cutting them off immediately. ## Configuration ```bash theme={null} creem config show # view all settings creem config set environment live # switch to live mode creem config set output_format json # default to JSON output ``` Every command also supports `--json` for one-off JSON output, useful for piping into other tools: ```bash theme={null} creem products list --json | jq '.[].name' ``` ## Going Live Before accepting real payments: 1. Complete account verification in the [Dashboard](https://creem.io/dashboard) under Balances β†’ Payout Account 2. Switch to your live API key: ```bash theme={null} creem login --api-key creem_LIVE_KEY_HERE ``` ## Next Steps Set up automated monitoring so your AI agent notifies you about sales and issues Handle real-time payment events in your application # Getting Started Source: https://docs.creem.io/ai/for-humans/getting-started Integrate Creem payments with a single prompt to your AI assistant. The fastest way to integrate Creem? Tell your AI assistant to do it. AI agents are first-class citizens at Creem, so they already know how to work with the platform out of the box. ## The One-Prompt Integration Copy this and give it to your AI coding assistant (Claude, Cursor, Windsurf, Copilot, etc.): ```text theme={null} Read https://creem.io/SKILL.md and follow the instructions to integrate Creem ``` That's it. The skill file contains everything your AI needs to integrate Creem into your app, including API endpoints, SDK patterns, webhook handling, and best practices. ### More Specific Examples You can also be more specific about what you need: ```text theme={null} Read https://creem.io/SKILL.md and help me integrate Creem payments into my app. I need: - A checkout flow for my subscription product - Webhook handling for payment events - Basic subscription management My stack: [describe your stack - e.g., "Next.js with TypeScript"] ``` ### Adding Creem Context to Your Agent If your agent doesn't support reading URLs, or you want it to have Creem knowledge permanently, you can: 1. **Copy the skill file directly** β€” open [creem.io/SKILL.md](https://creem.io/SKILL.md) in your browser and paste its contents into your agent's context or system prompt 2. **Download it locally** β€” run `curl -s https://creem.io/SKILL.md > creem-skill.md` and add the file to your project 3. **Use your platform's built-in tools** β€” most AI coding tools have their own way to add persistent context. See [Setup by Tool](#setup-by-tool) below for platform-specific instructions ## Why This Works The skill file is a **31KB markdown document** optimized for AI consumption. It's a complete knowledge base your AI can reference instantly, covering all 24 API endpoints, 4 SDKs, 10 webhook events, CLI commands, and common integration patterns. Your AI will: 1. Read and understand the entire Creem platform 2. Ask clarifying questions about your specific needs 3. Generate production-ready code tailored to your stack 4. Include security patterns and error handling automatically ## Level Up: Store Monitoring If you use [OpenClaw](https://openclaw.com) or any persistent AI assistant, you can have your AI **monitor your store** and notify you about: * New sales and transactions * Subscription cancellations * Payment failures * New customers Tell your AI: ```text theme={null} Read https://creem.io/HEARTBEAT.md and set up store monitoring for my Creem account. Notify me when there are new sales or any issues. ``` Your AI will periodically check your store and proactively ping you when something happens. No more checking dashboards. **OpenClaw users:** OpenClaw is perfect for this because it maintains persistent context and can schedule recurring checks. Your AI becomes your business co-pilot. ## Alternative: Skills Marketplace For Claude Code users, you can install the skill permanently: ```bash theme={null} /plugin marketplace add armitage-labs/creem-skills /plugin install creem-api@creem-skills ``` Now Claude Code has Creem knowledge in every conversation, no need to reference the URL. ## Setup by Tool **Option 1: One-time prompt (easiest)** ``` Read https://creem.io/SKILL.md and help me integrate Creem. ``` **Option 2: Install the skill permanently** ```bash theme={null} /plugin marketplace add armitage-labs/creem-skills /plugin install creem-api@creem-skills ``` **Option 1: Reference in chat** ``` @https://creem.io/SKILL.md Help me integrate Creem payments. ``` **Option 2: Add to project** ```bash theme={null} mkdir -p .cursor/skills curl -s https://creem.io/SKILL.md > .cursor/skills/creem.md ``` Then reference with `@.cursor/skills/creem.md` **Option 3: Add to Cursor Docs** Settings β†’ Features β†’ Docs β†’ Add `https://docs.creem.io` Clone the skill to your project: ```bash theme={null} mkdir -p .windsurf/creem curl -s https://creem.io/SKILL.md > .windsurf/creem/SKILL.md ``` Add to your Cascade knowledge base in settings. Reference the skill URL in your chat: ``` Using the guide at https://creem.io/SKILL.md, help me add Creem payments. ``` Most AI coding tools support referencing URLs or adding context files: 1. Download: `curl -s https://creem.io/SKILL.md > creem-skill.md` 2. Add to your project or AI tool's context 3. Reference when working on payments ## What Your AI Will Generate When you ask your AI to integrate Creem, expect: API route to create checkout sessions, redirect to hosted payment page, handle success Signature verification, event routing, access grant/revoke callbacks Cancel, pause, resume, upgrade flows with proper error handling Self-service billing portal links for payment method updates All with proper TypeScript types, error handling, and security patterns built in. ## When to Go Deeper The one-prompt approach works for most integrations. For the full technical reference, check the [For Agents](/ai/for-agents/skill-files) section. You can also manage your store directly from the terminal with the [Creem CLI](/ai/for-humans/cli). ## Next Steps You'll need a Creem API key for your AI to use Browse your store interactively from the terminal # AI Integration Source: https://docs.creem.io/ai/introduction AI agents and the CLI are first-class citizens at Creem. Integrate with a single prompt or manage your store from the terminal. At Creem, AI agents are first-class citizens, together with the CLI. Whether you're a founder using AI to ship faster or an AI agent helping integrate payments, everything is built to work for both. One prompt to your AI assistant and you're integrated. No docs required. Browse and manage your store from the terminal with an interactive TUI. Technical reference for AI agents. Skill files, CLI commands, store monitoring. ## The Simple Version Tell your AI assistant: ``` Read https://creem.io/SKILL.md and follow the instructions to integrate Creem ``` That's it. The skill file contains everything your AI needs: API endpoints, SDK patterns, webhook handling, and best practices. No documentation rabbit holes. Or if you prefer the terminal: ```bash theme={null} brew tap armitage-labs/creem && brew install creem creem login --api-key creem_test_YOUR_KEY_HERE creem products # launches interactive browser ``` ## Why AI and CLI? Traditional payment integrations require reading docs, understanding patterns, and writing boilerplate. With Creem: * A single prompt gives your AI complete platform context through [skill files](https://creem.io/SKILL.md) * The CLI lets you browse and manage your store without leaving the terminal * Store monitoring lets your AI notify you about sales and issues automatically * Skill files work with any AI tool (Claude, Cursor, Windsurf, Copilot) # Activates a license key Source: https://docs.creem.io/api-reference/endpoint/activate-license post /v1/licenses/activate Activate a license key for a specific device or instance. Register new activations and track usage limits. # Archive a product Source: https://docs.creem.io/api-reference/endpoint/archive-product delete /v1/products/{id} Archive a product (soft-delete). The product is retained for historical orders and subscriptions but can no longer be purchased. # Cancel a subscription Source: https://docs.creem.io/api-reference/endpoint/cancel-subscription post /v1/subscriptions/{id}/cancel Cancel an active subscription immediately or schedule cancellation at period end. # Close an account Source: https://docs.creem.io/api-reference/endpoint/close-credits-account post /v1/customer-credits/accounts/{id}/close Permanently close an account. This action cannot be undone. Balance and history remain readable. # Close an account Source: https://docs.creem.io/api-reference/endpoint/close-customer-credits-account post /v1/customer-credits/accounts/{id}/close Permanently close an account. This action cannot be undone. # Creates a new checkout session Source: https://docs.creem.io/api-reference/endpoint/create-checkout post /v1/checkouts Create a new checkout session to accept one-time payments or start subscriptions. Returns a checkout URL to redirect customers. # Create a customer credits account Source: https://docs.creem.io/api-reference/endpoint/create-credits-account post /v1/customer-credits/accounts Create a new credits account for a customer. Optionally seed it with an initial balance. # Create a customer Source: https://docs.creem.io/api-reference/endpoint/create-customer post /v1/customers Create a new customer record for the authenticated store. # Generate Customer Links Source: https://docs.creem.io/api-reference/endpoint/create-customer-billing post /v1/customers/billing Generate a customer portal link for managing billing, subscriptions, and payment methods. # Create a customer credits account Source: https://docs.creem.io/api-reference/endpoint/create-customer-credits-account post /v1/customer-credits/accounts Create a new credits account for a customer. Optionally seed it with an initial balance. # Create a discount Source: https://docs.creem.io/api-reference/endpoint/create-discount-code post /v1/discounts Create promotional discount codes for products. Set percentage or fixed amount discounts with expiration dates. # Creates a new product Source: https://docs.creem.io/api-reference/endpoint/create-product post /v1/products Create a new product for one-time payments, including free products with a 0 price, or subscriptions. Configure pricing, billing cycles, and features. # Credit an account Source: https://docs.creem.io/api-reference/endpoint/credit-account post /v1/customer-credits/accounts/{id}/credit Add credits to a customer account. Returns the resulting transaction record. # Credit an account Source: https://docs.creem.io/api-reference/endpoint/credit-customer-credits-account post /v1/customer-credits/accounts/{id}/credit Add credits to a customer account. Returns the resulting transaction record. # Deactivate a license key instance Source: https://docs.creem.io/api-reference/endpoint/deactivate-license post /v1/licenses/deactivate Remove a device activation from a license key. Free up activation slots for new devices. # Debit an account Source: https://docs.creem.io/api-reference/endpoint/debit-account post /v1/customer-credits/accounts/{id}/debit Deduct credits from a customer account. Returns the resulting transaction record. # Debit an account Source: https://docs.creem.io/api-reference/endpoint/debit-customer-credits-account post /v1/customer-credits/accounts/{id}/debit Deduct credits from a customer account. Returns the resulting transaction record. # Delete a discount Source: https://docs.creem.io/api-reference/endpoint/delete-discount-code delete /v1/discounts/{id}/delete Permanently delete a discount code. Prevent further usage of the discount. # Freeze an account Source: https://docs.creem.io/api-reference/endpoint/freeze-credits-account post /v1/customer-credits/accounts/{id}/freeze Freeze an account to prevent new transactions. The account remains readable. # Freeze an account Source: https://docs.creem.io/api-reference/endpoint/freeze-customer-credits-account post /v1/customer-credits/accounts/{id}/freeze Freeze an account to prevent new transactions. # Retrieve a checkout session Source: https://docs.creem.io/api-reference/endpoint/get-checkout get /v1/checkouts Retrieve details of a checkout session by ID. View status, customer info, and payment details. # Retrieve a customer credits account Source: https://docs.creem.io/api-reference/endpoint/get-credits-account get /v1/customer-credits/accounts/{id} Get details of a customer credits account by ID. # Get account balance Source: https://docs.creem.io/api-reference/endpoint/get-credits-account-balance get /v1/customer-credits/accounts/{id}/balance Get the current balance of an account. Optionally pass ?at= for historical balance. # Retrieve a customer Source: https://docs.creem.io/api-reference/endpoint/get-customer get /v1/customers Retrieve customer information by ID or email. View purchase history, subscriptions, and profile details. # Retrieve a customer credits account Source: https://docs.creem.io/api-reference/endpoint/get-customer-credits-account get /v1/customer-credits/accounts/{id} Get details of a customer credits account by ID. # Get account balance Source: https://docs.creem.io/api-reference/endpoint/get-customer-credits-account-balance get /v1/customer-credits/accounts/{id}/balance Get the current balance of an account. Optionally pass ?at= for historical balance. # Retrieve discount Source: https://docs.creem.io/api-reference/endpoint/get-discount-code get /v1/discounts Retrieve discount code details by ID or code. Check usage limits, expiration, and discount amount. # Get store metrics summary Source: https://docs.creem.io/api-reference/endpoint/get-metrics-summary get /v1/stats/summary Retrieve aggregated store metrics including counts, revenue, and MRR. When startDate and endDate are provided, totals are filtered to that date range. When interval is also provided, the response includes a periods array with time-series data points grouped by that interval. The periods array starts from the store's first transaction or startDate, whichever is later, to avoid empty leading buckets. All monetary amounts are in cents (integer, no decimals). # Retrieve a product Source: https://docs.creem.io/api-reference/endpoint/get-product get /v1/products Retrieve product details by ID. View pricing, billing type, status, and product configuration. # Retrieve a product by ID Source: https://docs.creem.io/api-reference/endpoint/get-product-by-id get /v1/products/{id} Retrieve a single product by its ID. # Get store metrics summary Source: https://docs.creem.io/api-reference/endpoint/get-stats-summary get /v1/stats/summary Retrieve aggregated store metrics. When a period is specified, includes time-series data points. Without a period, returns only totals and MRR. # Retrieve a subscription Source: https://docs.creem.io/api-reference/endpoint/get-subscription get /v1/subscriptions Retrieve subscription details by ID. View status, billing cycle, customer info, and payment history. # Get a transaction by ID Source: https://docs.creem.io/api-reference/endpoint/get-transaction get /v1/transactions Retrieve a single transaction by ID. View payment details, status, and associated order information. # List all transactions Source: https://docs.creem.io/api-reference/endpoint/get-transactions get /v1/transactions/search Search and retrieve payment transactions. Filter by customer, product, date range, and status. # List customer credits accounts Source: https://docs.creem.io/api-reference/endpoint/list-credits-accounts get /v1/customer-credits/accounts List accounts for the authenticated store with cursor pagination. System accounts are excluded. # List account entries Source: https://docs.creem.io/api-reference/endpoint/list-credits-entries get /v1/customer-credits/accounts/{id}/entries List the credit and debit history for an account with cursor pagination. # List account entries Source: https://docs.creem.io/api-reference/endpoint/list-customer-credits-account-entries get /v1/customer-credits/accounts/{id}/entries List the credit and debit history for an account with cursor pagination. # List customer credits accounts Source: https://docs.creem.io/api-reference/endpoint/list-customer-credits-accounts get /v1/customer-credits/accounts List accounts for the authenticated store with cursor pagination. System accounts are excluded. # List customer licenses Source: https://docs.creem.io/api-reference/endpoint/list-customer-licenses get /v1/customers/{id}/licenses Retrieve a paginated list of license keys for a specific customer. # List customer orders Source: https://docs.creem.io/api-reference/endpoint/list-customer-orders get /v1/customers/{id}/orders Retrieve a paginated list of orders for a specific customer. # List customer subscriptions Source: https://docs.creem.io/api-reference/endpoint/list-customer-subscriptions get /v1/customers/{id}/subscriptions Retrieve a paginated list of subscriptions for a specific customer. # List all customers Source: https://docs.creem.io/api-reference/endpoint/list-customers get /v1/customers/list Retrieve a paginated list of all customers. Filter and search through your customer base. # Pause a subscription Source: https://docs.creem.io/api-reference/endpoint/pause-subscription post /v1/subscriptions/{id}/pause Temporarily pause a subscription. Stop billing while retaining the subscription for later resumption. # Resume a subscription Source: https://docs.creem.io/api-reference/endpoint/resume-subscription post /v1/subscriptions/{id}/resume Resume a subscription. Subscription must be in paused or scheduled_cancel status. # Reverse a transaction Source: https://docs.creem.io/api-reference/endpoint/reverse-credits-transaction post /v1/customer-credits/accounts/{id}/reverse Reverse a previous credit or debit on this account. Creates a new transaction that undoes the original, preserving the full history. # Reverse a transaction Source: https://docs.creem.io/api-reference/endpoint/reverse-customer-credits-account-transaction post /v1/customer-credits/accounts/{id}/reverse Reverse a previous credit or debit on this account. Creates a new transaction that undoes the original, preserving the full history. # Screen a prompt Source: https://docs.creem.io/api-reference/endpoint/screen-prompt post /v1/moderation/prompt Evaluate a text prompt against content policies before generation. This endpoint is experimental and may change. # Search and list all discounts Source: https://docs.creem.io/api-reference/endpoint/search-discounts get /v1/discounts/search Search and list discount codes for a store with filters and pagination. # List all products Source: https://docs.creem.io/api-reference/endpoint/search-products get /v1/products/search Search and retrieve a paginated list of products. Filter by status, billing type, and other criteria. # List all subscriptions Source: https://docs.creem.io/api-reference/endpoint/search-subscriptions get /v1/subscriptions/search Search and retrieve a paginated list of subscriptions. View status, billing cycle, and customer info. # Unfreeze an account Source: https://docs.creem.io/api-reference/endpoint/unfreeze-credits-account post /v1/customer-credits/accounts/{id}/unfreeze Unfreeze a frozen account to allow transactions again. # Unfreeze an account Source: https://docs.creem.io/api-reference/endpoint/unfreeze-customer-credits-account post /v1/customer-credits/accounts/{id}/unfreeze Unfreeze a frozen account to allow transactions again. # Update a customer Source: https://docs.creem.io/api-reference/endpoint/update-customer patch /v1/customers Update a customer # Update a product Source: https://docs.creem.io/api-reference/endpoint/update-product patch /v1/products/{id} Update a product. Only supplied fields change; changing a price field mints a new default price while existing subscriptions keep the price they were purchased under. # Update a subscription Source: https://docs.creem.io/api-reference/endpoint/update-subscription post /v1/subscriptions/{id} Modify subscription details like units, seats, or add-ons. Support proration and immediate billing options. # Upgrade a subscription to a different product Source: https://docs.creem.io/api-reference/endpoint/upgrade-subscription post /v1/subscriptions/{id}/upgrade Upgrade a subscription to a different product or plan. Handle proration and plan changes seamlessly. # Validates a license key or instance Source: https://docs.creem.io/api-reference/endpoint/validate-license post /v1/licenses/validate Verify if a license key is valid and active for a specific instance. Check activation status and expiration. # Error Handling Source: https://docs.creem.io/api-reference/error-codes Understanding API error responses and how to handle them. ## Error Response Format When an API request fails, Creem returns a JSON error response: ```json theme={null} { "trace_id": "550e8400-e29b-41d4-a716-446655440000", "status": 400, "error": "Bad Request", "message": ["The 'product_id' field is required."], "timestamp": 1706889600000 } ``` | Field | Type | Description | | ----------- | --------- | -------------------------------------------------------- | | `trace_id` | string | Unique identifier for the request (useful for debugging) | | `status` | number | HTTP status code | | `error` | string | Error category | | `message` | string\[] | Array of human-readable error messages | | `timestamp` | number | Unix timestamp in milliseconds | The `trace_id` is included in every error response. Include it when contacting support for faster debugging. ## HTTP Status Codes | Status | Error | When It Occurs | | ------ | ----------- | ---------------------------------------------------------------- | | `400` | Bad Request | Invalid request parameters, malformed JSON, or validation errors | | `403` | Forbidden | Invalid API key or insufficient permissions | | `404` | Not Found | Requested resource doesn't exist | ## Common Error Scenarios ### Authentication Errors (403 Forbidden) Returned when the API key is missing, invalid, or doesn't have permission for the requested resource. ```json theme={null} { "trace_id": "550e8400-e29b-41d4-a716-446655440000", "status": 403, "error": "Forbidden", "timestamp": 1706889600000 } ``` **How to fix:** * Verify your API key in the [dashboard](https://creem.io/dashboard/developers) * Ensure the `x-api-key` header is included in your request * Check you're using the correct key for the environment (test vs. production) ```bash theme={null} curl -X GET https://api.creem.io/v1/products \ -H "x-api-key: creem_YOUR_API_KEY" ``` ### Validation Errors (400 Bad Request) Returned when request parameters are missing or invalid. ```json theme={null} { "trace_id": "550e8400-e29b-41d4-a716-446655440000", "status": 400, "error": "Bad Request", "message": ["product_id must be a string", "success_url must be a valid URL"], "timestamp": 1706889600000 } ``` **How to fix:** * Check the `message` array for specific validation errors * Verify all required fields are included * Ensure data types match the expected format ### Resource Not Found (404) Returned when the requested resource doesn't exist. ```json theme={null} { "trace_id": "550e8400-e29b-41d4-a716-446655440000", "status": 404, "error": "Bad Request", "message": ["Product not found"], "timestamp": 1706889600000 } ``` **How to fix:** * Verify the resource ID is correct * Ensure you're using the right environment (test vs. production resources are separate) * Check if the resource was deleted ### Duplicate Resource (400 Bad Request) Returned when trying to create a resource that already exists. ```json theme={null} { "trace_id": "550e8400-e29b-41d4-a716-446655440000", "status": 400, "error": "Bad Request", "message": ["A resource with this identifier already exists"], "timestamp": 1706889600000 } ``` **How to fix:** * Use a unique identifier for idempotent requests * Check if the resource already exists before creating ## Handling Errors in Code ### TypeScript SDK ```typescript theme={null} import { Creem } from 'creem'; const creem = new Creem({ apiKey: process.env.CREEM_API_KEY! }); try { const checkout = await creem.checkouts.create({ productId: 'prod_123', successUrl: 'https://example.com/success', }); } catch (error) { if (error.response) { const { trace_id, status, message } = error.response.data; console.error(`Error ${status}: ${message.join(', ')}`); console.error(`Trace ID: ${trace_id}`); } } ``` ### cURL ```bash theme={null} # The response includes the trace_id for debugging curl -X POST https://api.creem.io/v1/checkouts \ -H "x-api-key: creem_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"product_id": "invalid"}' \ -w "\nHTTP Status: %{http_code}\n" ``` ## Environments Make sure you're using the correct base URL: | Environment | Base URL | | ----------- | --------------------------- | | Production | `https://api.creem.io` | | Test Mode | `https://test-api.creem.io` | Test mode API keys only work with `test-api.creem.io`, and production keys only work with `api.creem.io`. ## Need Help? If you're experiencing issues: 1. Check the `trace_id` in your error response 2. Join our [Discord community](https://discord.gg/q3GKZs92Av) for quick help 3. [Contact support](https://creem.io/contact) with your trace ID for faster debugging # Introduction Source: https://docs.creem.io/api-reference/introduction Everything you need to start integrating with the Creem API: endpoints, authentication, test mode, webhooks, and SDKs. The Creem API is built on REST principles and uses HTTPS for all requests. It returns JSON-encoded responses and uses standard HTTP status codes. ## Base URL All API requests are made to the following base URLs: `http https://api.creem.io/v1 ` `http https://test-api.creem.io/v1 ` The test and production environments are completely isolated. Data created in test mode does not affect your production environment, and API keys are not interchangeable between environments. ## Authentication All API requests must include your API key in the `x-api-key` header. ```bash theme={null} curl -X GET https://api.creem.io/v1/products \ -H "x-api-key: creem_YOUR_API_KEY" ``` You can find your API keys in the [Developers section](https://creem.io/dashboard/developers) of your dashboard. Never expose your API keys in client-side code, public repositories, or logs. Keep them server-side only. ## Test Mode Test mode gives you a full sandbox environment to build and test your integration without processing real payments. | | Production | Test Mode | | ------------ | ------------------------------------ | ------------------------------------- | | **Base URL** | `https://api.creem.io/v1` | `https://test-api.creem.io/v1` | | **API Keys** | Found in dashboard (production mode) | Found in dashboard (test mode toggle) | | **Payments** | Real charges | Simulated with test cards | | **Data** | Live data | Isolated sandbox data | To activate test mode, toggle **Test Mode** in the bottom of the left sidebar of your [dashboard](https://creem.io/dashboard). ### Test Cards Use these card numbers to simulate different payment scenarios. All cards work with any future expiration date, any CVV, and any billing information. Click a card number to copy it. | Card Number | Behavior | | ---------------------------------- | ------------------ | | `4111 1111 1111 1111` | Successful payment | | `4507 9900 0000 0028` | Card declined | | `4507 9900 0000 0010` | Insufficient funds | | `4507 9900 0000 0044` | Incorrect CVC | ### Using Test Mode in Code ```bash cURL theme={null} curl -X POST https://test-api.creem.io/v1/checkouts \ -H "x-api-key: YOUR_TEST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_YOUR_PRODUCT_ID", "success_url": "https://yoursite.com/success" }' ``` ```typescript TypeScript SDK theme={null} import { Creem } from "creem"; const creem = new Creem({ apiKey: process.env.CREEM_API_KEY!, server: process.env.NODE_ENV === "production" ? "prod" : "test", }); const checkout = await creem.checkouts.create({ productId: "prod_abc123", successUrl: "https://yoursite.com/success", }); ``` ```typescript Next.js theme={null} import { Checkout } from "@creem_io/nextjs"; export const GET = Checkout({ apiKey: process.env.CREEM_API_KEY!, testMode: process.env.NODE_ENV !== "production", defaultSuccessUrl: "/success", }); ``` ## Webhooks Creem sends real-time event notifications to your server via webhooks. Webhook payloads are signed using HMAC-SHA256 so you can verify their authenticity. **Signature verification:** Every webhook request includes a `creem-signature` header. Verify it using your webhook secret (found in [Developers > Webhook](https://creem.io/dashboard/developers)) before processing the payload: ```typescript theme={null} import { verifyWebhookSignature } from "creem/webhooks"; await verifyWebhookSignature(rawBody, request.headers, { secret: process.env.CREEM_WEBHOOK_SECRET!, }); ``` **Supported events:** | Event | Description | | ------------------------------- | ---------------------------------------------------------- | | `checkout.completed` | A checkout session was completed | | `subscription.active` | A new subscription was created | | `subscription.paid` | A subscription payment was collected | | `subscription.canceled` | A subscription was canceled | | `subscription.scheduled_cancel` | A subscription is scheduled for cancellation at period end | | `subscription.past_due` | A subscription payment failed | | `subscription.expired` | A subscription period ended without payment | | `subscription.trialing` | A subscription started a trial | | `subscription.paused` | A subscription was paused | | `subscription.update` | A subscription was updated | | `refund.created` | A refund was issued | | `dispute.created` | A dispute was opened by a customer | **Retry policy:** If your endpoint doesn't respond with HTTP 200, Creem retries at 30 seconds, 1 minute, 5 minutes, and 1 hour. You can also resend events manually from the dashboard. Detailed setup instructions, signature verification, and event payload examples. ## Response Codes | Status | Description | | ------ | ------------------------------------------- | | `200` | Successful request | | `400` | Invalid parameters or validation error | | `401` | Missing API key | | `403` | Invalid API key or insufficient permissions | | `404` | Resource not found | | `429` | Rate limit exceeded | | `500` | Internal server error | Every error response includes a `trace_id` you can share with support for faster debugging. See [Error Handling](/api-reference/error-codes) for details. ## SDKs & Libraries Core SDK for Node.js and TypeScript projects Drop-in checkout and webhook helpers for Next.js Integrate Creem billing with Better Auth Manage products and checkouts from the terminal # Creem CLI Source: https://docs.creem.io/code/cli Install, configure, and use the Creem CLI to manage your store from the terminal. Full command reference, interactive mode, and automation examples. The Creem CLI lets you manage products, customers, subscriptions, and transactions directly from the terminal. It works for both hands-on store management through an interactive TUI, and scripted automation via JSON output. Want your AI agent to set it up for you? Copy this prompt: ```text theme={null} Read https://creem.io/SKILL.md and set up the Creem CLI for me ``` ## Installation ### Homebrew (macOS/Linux) ```bash theme={null} brew tap armitage-labs/creem brew install creem ``` ### npm (Global) ```bash theme={null} npm install -g @creem_io/cli ``` ### npx (No install) ```bash theme={null} npx @creem_io/cli ``` Verify installation: ```bash theme={null} creem --version ``` ## Authentication ```bash theme={null} # Login with your API key creem login --api-key creem_test_YOUR_KEY_HERE # Verify authentication creem whoami # Logout creem logout ``` **API Key Security:** Never share your API key with any service, tool, or agent other than the Creem CLI or API. Keys are stored locally at `~/.creem/config.json`. ### Test vs Live Mode The CLI automatically detects your environment based on the API key prefix: | Key Prefix | Environment | API Base | | ------------- | ----------------- | --------------------------- | | `creem_test_` | Test (sandbox) | `https://test-api.creem.io` | | `creem_` | Live (production) | `https://api.creem.io` | **Always start in test mode.** Switch to live only when you're ready for real transactions. ## Interactive Mode Run any resource command without a subcommand to launch an interactive browser: ```bash theme={null} creem products creem customers creem subscriptions creem transactions ``` You get a full TUI where you can browse, search, and drill into records without writing any commands. ### Browsing Transactions Press Enter on any row to drill into the full detail view: ### Managing Subscriptions Navigate into any subscription to see its full details and take actions directly from the status bar: ### Navigation Keys | Key | Action | | --------------------- | ---------------------------------------- | | `j`/`k` or arrow keys | Move through the list | | Enter | View details | | `/` | Search | | `:` | Open command bar (cancel, pause, resume) | | `q` | Go back or exit | ## Command Reference ### Products ```bash theme={null} # List all products creem products list # List with pagination creem products list --page 2 --limit 10 # Get a specific product creem products get prod_XXXXX # Create a product creem products create \ --name "Pro Plan" \ --description "Monthly pro subscription with all features" \ --price 1999 \ --currency USD \ --billing-type recurring \ --billing-period every-month ``` **Product Options:** | Option | Values | | ------------------ | --------------------------------------------------------------------- | | `--billing-type` | `onetime`, `recurring` | | `--billing-period` | `every-month`, `every-three-months`, `every-six-months`, `every-year` | | `--tax-category` | `saas`, `digital-goods-service`, `ebooks` | | `--tax-mode` | `inclusive`, `exclusive` | ### Customers ```bash theme={null} # List all customers creem customers list # Get customer by ID creem customers get cust_XXXXX # Get customer by email creem customers get --email user@example.com # Generate billing portal link (self-service for payment methods, invoices) creem customers billing cust_XXXXX ``` ### Subscriptions ```bash theme={null} # List all subscriptions creem subscriptions list # Filter by status creem subscriptions list --status active # Get subscription details creem subscriptions get sub_XXXXX # Cancel immediately creem subscriptions cancel sub_XXXXX # Cancel at period end (customer keeps access until billing period ends) creem subscriptions cancel sub_XXXXX --mode scheduled # Pause billing creem subscriptions pause sub_XXXXX # Resume billing creem subscriptions resume sub_XXXXX ``` **Subscription Statuses:** `active`, `trialing`, `paused`, `past_due`, `expired`, `canceled`, `scheduled_cancel` Use `--mode scheduled` for cancellations. Immediate cancellation cuts off access instantly, which frustrates customers. ### Checkouts ```bash theme={null} # Create a checkout session creem checkouts create --product prod_XXXXX # Create with success URL creem checkouts create --product prod_XXXXX --success-url https://app.com/welcome # Get checkout details creem checkouts get chk_XXXXX ``` ### Transactions ```bash theme={null} # List all transactions (newest first) creem transactions list # List with more results creem transactions list --limit 50 # Filter by customer creem transactions list --customer cust_XXXXX # Filter by product creem transactions list --product prod_XXXXX # Get transaction details creem transactions get txn_XXXXX ``` ### Discounts ```bash theme={null} # List all discount codes creem discounts list # Get discount details creem discounts get disc_XXXXX ``` ### Configuration ```bash theme={null} # View all settings creem config show # Switch to live mode creem config set environment live # Switch to test mode creem config set environment test # Set default output format creem config set output_format json creem config set output_format table # Get a specific setting creem config get environment # List all config keys creem config list ``` ## Output Formats Every command supports table (default) and JSON output: ```bash theme={null} # Per-command JSON output creem products list --json creem customers get cust_XXXXX --json # Set JSON as global default creem config set output_format json ``` **For AI agents and scripting:** Always use `--json` and parse with `jq` for reliable automation: ```bash theme={null} creem products list --json | jq '.[].id' creem customers get cust_XXXXX --json | jq '.email' creem subscriptions list --status active --json | jq 'length' ``` ## Automation Examples ### Check for new transactions ```bash theme={null} LATEST=$(creem transactions list --limit 1 --json | jq -r '.[0].id') echo "Latest transaction: $LATEST" ``` ### Count active subscriptions ```bash theme={null} ACTIVE=$(creem subscriptions list --status active --json | jq 'length') echo "Active subscriptions: $ACTIVE" ``` ### Check for payment issues ```bash theme={null} PAST_DUE=$(creem subscriptions list --status past_due --json | jq 'length') EXPIRED=$(creem subscriptions list --status expired --json | jq 'length') if [ "$PAST_DUE" -gt 0 ] || [ "$EXPIRED" -gt 0 ]; then echo "⚠️ Alert: $PAST_DUE past_due, $EXPIRED expired subscriptions" fi ``` ### Generate bulk checkout links ```bash theme={null} for PRODUCT_ID in prod_AAA prod_BBB prod_CCC; do URL=$(creem checkouts create --product "$PRODUCT_ID" --json | jq -r '.checkout_url') echo "$PRODUCT_ID: $URL" done ``` ### Daily subscription health check ```bash theme={null} #!/bin/bash # Run daily via cron to monitor subscription health echo "Subscription Report - $(date)" echo "================================" echo "Active: $(creem subscriptions list --status active --json | jq 'length')" echo "Trialing: $(creem subscriptions list --status trialing --json | jq 'length')" echo "Past Due: $(creem subscriptions list --status past_due --json | jq 'length')" echo "Expired: $(creem subscriptions list --status expired --json | jq 'length')" echo "Canceled: $(creem subscriptions list --status canceled --json | jq 'length')" ``` ## Migration The CLI includes a `migrate` command to help you move from other platforms: ```bash theme={null} creem migrate lemon-squeezy ``` ## Tips for AI Agents If you're an AI agent using the CLI on behalf of a human: Always add `--json` to commands when processing output programmatically. Parse with `jq` for reliable automation. Mistakes in live mode affect real customers and money. Always develop against test mode. Run `creem whoami` before operations to confirm authentication and environment. List resources first, then use actual IDs from the response. Don't assume ID formats. ## Going Live Before accepting real payments: 1. Complete account verification in the [Dashboard](https://creem.io/dashboard) under Balances β†’ Payout Account 2. Switch to your live API key: ```bash theme={null} creem login --api-key creem_LIVE_KEY_HERE ``` The CLI automatically switches to the production API based on the key prefix. ## Next Steps Set up automated monitoring so your AI agent notifies you about sales and issues Handle real-time payment events in your application Integrate Creem programmatically with TypeScript, Next.js, or Better Auth Full API documentation with all endpoints # Community Resources Source: https://docs.creem.io/code/community/community-resources Discover SDKs, templates, boilerplates, and other resources built by our community to help you integrate Creem faster.

Community Resources

SDKs, templates, boilerplates, and tools built by our community

Explore resources created by developers in our community to accelerate your Creem integration and build better payment experiences.

SDKs Β· Plugins Β· Integrations Β· Templates Β· Boilerplates Β· Tools Β· Other
*** ## Introduction Our community has built an incredible collection of resources to help you integrate Creem into your applications faster. From official SDKs to community-maintained templates and boilerplates, you'll find everything you need to get started. Resources highlighted here are maintained by third-party developers. We do our best to showcase helpful projects, but Creem is not liable for any code or dependencies you install from third-party sources . Always review the code before integrating. *** ## Boilerplates Minimal boilerplates and code snippets to help you get started quickly. These are lightweight starting points that you can customize for your specific needs. | Name | Description | Repository | Use Case | | ------------------------------------------ | --------------------------------------------------- | -------------------------------------- | --------------------------------- | | [SaaSKit](/code/community/saaskit) | TanStack Start boilerplate with Creem integration | [Website](https://saaskit.paceui.com/) | Full-stack SaaS starter | | [Supastarter](/code/community/supastarter) | Next.js SaaS starter kit with Creem payment support | [Website](https://supastarter.dev/) | Production-ready SaaS boilerplate | *** ## SDKs Community-maintained SDKs and adapters for various frameworks and languages. These SDKs provide type-safe wrappers around the Creem API, making integration seamless. | Name | Language/Framework | Description | Repository | Maintainer | | ---------------------------------------- | ------------------ | ------------------------------------------------------------- | -------------------------------------------------- | ---------- | | [Nuxt Creem](/code/community/nuxt-creem) | Nuxt | Nuxt module for Creem integration with typed API and webhooks | [GitHub](https://github.com/justserdar/nuxt-creem) | Community | | [Krema](/code/community/krema) | TypeScript | TypeScript SDK for Creem API with type generation | [GitHub](https://github.com/emirsassan/krema) | Community | Looking for official SDKs? Check out our TypeScript SDK and Next.js adapter. *** ## Plugins Plugins and integrations for popular platforms like WordPress, enabling seamless Creem integration without custom code. | Name | Platform | Description | Repository | Maintainer | | ----------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | -------------- | | Creem WordPress Plugin | WordPress | Connect WordPress with Creem to automatically create user accounts when customers make a purchase. | [GitHub](https://github.com/sinanisler/creem-io-api) | Sinan | | Creem Raycast Extension | Raycast | Manage Creem products, customers, and checkouts directly from the Raycast launcher. | [Raycast](https://www.raycast.com/xmok/creem) | xmok | | Convex Creem | Convex | Production-ready Convex component with React and Svelte billing widgets, checkout, subscriptions, HMAC webhook verification, and full TypeScript support. πŸ† Scoops Winner | [GitHub](https://github.com/mmailaender/convex-creem) | Micha | | Laravel Creem | Laravel | Full-featured Laravel SDK with multi-profile billing, webhook events, interactive demo, and an Omnipay driver for 60+ payment gateways. πŸ† Scoops Winner | [GitHub](https://github.com/romansh/laravel-creem) | Roman | | Framer Creem Plugin | Framer | Framer plugin with API key auth, product fetching, buy buttons, pricing tables, and customizable checkout. Includes video walkthrough and tutorial. πŸ† Scoops Winner | [GitHub](https://github.com/Heet-Bhalodiya/creem-framer-plugin) | xand3rr & Heet | Building a plugin for another platform? Share it in our Discord and we'll feature it here! *** ## Templates Ready-to-use templates and starter projects that demonstrate best practices for integrating Creem. These templates include authentication, database setup, and complete payment flows. | Name | Stack | Description | Repository | Features | | ------------------------------------------------------------------------- | ------------------ | -------------------------------------------------- | --------------------------------------------------------------- | --------------------------------- | | [Creem Checkout Next.js Demo](/code/community/creem-checkout-nextjs-demo) | Next.js + Supabase | Next.js demo showcasing Creem checkout integration | [GitHub](https://github.com/ja3nyc/creem-checkout-next-js-demo) | Checkout, Subscriptions, Webhooks | Our official Next.js template includes Prisma, Better Auth, and Shadcn UI out of the box. *** ## Integrations Third-party platforms and services that integrate directly with Creem to extend your sales capabilities. | Name | Category | Description | Link | | ------------------------------------ | --------------- | ---------------------------------------------------------------------------------------- | ------------------------------------ | | [Evendeals](/integrations/evendeals) | Purchase Parity | Adjust prices based on visitor location to boost international conversions by up to 30%. | [Website](https://www.evendeals.com) | *** ## Other Resources Additional resources including tutorials, blog posts, video guides, entertaining content, and other helpful content. | Name | Type | Description | Link | Author | | --------------------- | ----- | ---------------------------------------------------------------------- | -------------------------------------------- | ------ | | Creem YouTube Channel | Video | Official Creem YouTube channel with entertaining content and fun stuff | [YouTube](https://www.youtube.com/@creem_io) | Creem | *** ## Contributing We love seeing what our community builds! If you've created an SDK, template, boilerplate, or tool that uses Creem, we'd love to feature it here. ### How to Submit 1. **Join our Discord** - Connect with the community at [discord.gg/q3GKZs92Av](https://discord.gg/q3GKZs92Av) 2. **Share your resource** - Post in the #showcase channel with: * A brief description * Repository link * Screenshots or demo (if applicable) 3. **Get featured** - Our team reviews submissions and adds the best ones to this page ### Guidelines * Resources should be actively maintained * Include clear documentation and examples * Follow best practices for security and performance * Be respectful and inclusive in your code and documentation *** ## Resources Connect with other developers and get help from the community. Check out our official TypeScript SDK and framework adapters. Explore the complete Creem API documentation. *** Need help? Reach us at [support@creem.io](https://creem.io/contact) or join the [Discord community](https://discord.gg/q3GKZs92Av). # SaaSKit Source: https://docs.creem.io/code/community/community-resources/boilerplates/saaskit TanStack Start boilerplate with Creem payment integration built-in. ## Overview SaaSKit is a community-maintained TanStack Start boilerplate that includes Creem as a payment provider option. It provides a full-stack starter template with authentication, database, and payment flows pre-configured. ## Features * **TanStack Start** - Full-stack React framework * **Creem Integration** - Pre-configured payment flows using Creem as Merchant of Record * **Authentication** - Better Auth with RBAC support * **Database** - Drizzle ORM with PostgreSQL * **Email** - Resend integration for transactional emails * **Storage** - S3-compatible file uploads * **Admin Dashboard** - Built-in admin interface * **UI Components** - DaisyUI and Tailwind CSS components ## Creem Integration SaaSKit includes Creem payment integration out of the box, allowing you to accept payments and manage subscriptions without additional setup. The boilerplate handles checkout sessions, webhooks, and subscription management. ## Resources Visit the official SaaSKit website for documentation and setup instructions. Learn about the Creem SDK used in SaaSKit. # Creem Checkout Next.js Demo Source: https://docs.creem.io/code/community/creem-checkout-nextjs-demo Next.js demo application showcasing Creem checkout integration with authentication and subscription management. ## About Creem Checkout Next.js Demo A Next.js demo application that demonstrates how to integrate Creem checkout flows into a Next.js application. The demo includes authentication, product listing, checkout sessions, subscription management, and webhook handling. ### Features * **Checkout Integration:** Complete checkout flow with Creem payment processing * **Product Management:** List and display Creem products with pricing * **Subscription Management:** Get subscription details and cancel subscriptions * **Customer Portal:** Create billing portal sessions for customer management * **Webhook Handling:** Webhook signature verification and event handling * **Security:** Redirect signature verification for secure payment flows * **Authentication:** Supabase integration for user authentication ### Stack * Next.js (App Router) * TypeScript * Supabase (Authentication) * Creem API *** ## Resources View the source code and documentation on GitHub. Learn about Creem's payment integration. # Krema Source: https://docs.creem.io/code/community/krema Unofficial TypeScript SDK for the Creem API with type-safe access to products, licenses, checkouts, and discounts. ## About Krema Krema is an unofficial TypeScript SDK for the Creem API that provides type-safe access to Creem's payment features. It includes utilities for generating type definitions from your Creem products and managing checkouts, licenses, and discount codes. ### Features * **Type Generation:** Generate TypeScript type definitions from your Creem API products * **Checkout Sessions:** Create checkout sessions with type-safe product references * **License Management:** Activate, validate, and deactivate licenses * **Discount Codes:** Create and manage percentage and fixed-amount discount codes * **CLI Tool:** Command-line interface for generating types * **Configuration:** Support for `.env` files or `.kremarc` configuration file ### Stack * TypeScript * Creem API *** ## Resources View the source code and documentation on GitHub. Learn about Creem's payment integration. # Nuxt Creem Source: https://docs.creem.io/code/community/nuxt-creem Nuxt module for integrating Creem payments with typed API, server utilities, and webhook support. ## About Nuxt Creem Nuxt Creem is a Nuxt module that provides an easy way to integrate Creem payments into your Nuxt application. It utilizes the official Creem API for server-side operations and includes type-safe utilities for common payment flows. ### Features * **Typed Creem API:** Easily import and load Creem products with full TypeScript support * **Server Utils:** Auto-injected server utilities for quick checkout session creation * **Customer Portal:** Support for generating customer billing portal links * **Webhooks:** Built-in webhook header verification and event type handling * **Default Handler:** Pre-configured webhook handler for common events ### Stack * Nuxt 3 * TypeScript * Creem API *** ## Resources View the source code and documentation on GitHub. Visit the Nuxt Creem module website. Learn about Creem's payment integration. # SaaSKit Source: https://docs.creem.io/code/community/saaskit TanStack Start boilerplate with Creem payment integration for building SaaS applications. ## About SaaSKit SaaSKit is a modular TanStack Start boilerplate that includes Creem payment integration out of the box. It provides a production-ready foundation for building SaaS applications with authentication, database, email, and payment handling already configured. ### Features * **Payments:** Integrated with Creem as Merchant of Record * **Authentication:** Better Auth with Role-Based Access Control (RBAC) * **Database:** Drizzle ORM with PostgreSQL * **Email:** Resend integration for transactional emails * **Storage:** S3-compatible file uploads * **Admin Dashboard:** Built-in admin interface * **UI Components:** DaisyUI and Tailwind CSS components ### Stack * TanStack Start (React framework) * TypeScript * Drizzle ORM * Better Auth * Creem (Payments) *** ## Resources Visit the official SaaSKit website to learn more. Learn about Creem's payment integration. # Supastarter Source: https://docs.creem.io/code/community/supastarter Production-ready Next.js SaaS starter kit with Creem payment integration and full-stack features. ## About Supastarter Supastarter is a production-ready Next.js SaaS starter kit that includes Creem payment integration. It provides a complete foundation for building scalable SaaS applications with authentication, billing, organizations, and admin features already configured. ### Features * **Payments:** Integrated with Creem as Merchant of Record. Includes complete billing flow, billing components, and seat-based billing. * **Authentication:** Better Auth with password, magic link, OAuth, 2FA, roles & permissions, and super admin features. * **Organizations:** Multi-tenant support with seat-based billing, member roles, and resource sharing. * **Database:** Choose between Prisma or Drizzle ORM with PostgreSQL support. * **API:** Type-safe REST API built with Hono, includes oRPC integration and OpenAPI specs. * **Internationalization:** Multi-language support with translatable mail templates. * **Additional Features:** Admin UI, AI chatbot (Vercel AI SDK), background tasks, analytics, landing page, blog, documentation, and more. ### Stack * Next.js 16 (App Router) * TypeScript * Tailwind CSS & Radix UI * Better Auth * Prisma or Drizzle ORM * Hono (API framework) * Creem (Payments) *** ## Resources Visit the official Supastarter website to learn more and see the demo. Learn about Creem's payment integration. # MCP Source: https://docs.creem.io/code/mcp Model Context Protocol integration # MCP Documentation coming soon. # AI Agents Source: https://docs.creem.io/code/sdks/ai-agents Integrate Creem faster with AI coding assistants like Claude Code, Cursor, Windsurf, and other AI-powered development tools using our official skill. AI coding assistants like Claude Code, Cursor, and Windsurf are transforming how developers build software. To help you integrate Creem faster and with best practices built-in, we've created an official **Creem API Skill** that gives AI assistants deep knowledge about our payment infrastructure. ## Quick Install for Claude Code Install the Creem skill with a single command: ```bash theme={null} /plugin marketplace add armitage-labs/creem-skills ``` Then install the skill using either method: **Option A: Use the interactive UI (easiest)** 1. Type `/plugin` and press Enter 2. Go to the **Discover** tab 3. Search for `creem-api` 4. Press Enter to install **Option B: Use the command directly** ```bash theme={null} /plugin install creem-api@creem-skills ``` That's it! Claude Code now has complete knowledge of the Creem API and will generate production-ready integration code when you ask about payments, subscriptions, webhooks, or licenses. *** ## What is a Skill? A skill is a structured set of instructions and reference materials that AI assistants use to provide more accurate, contextual help for specific tasks. When you load the Creem skill, your AI assistant gains comprehensive knowledge about: * All 24 API endpoints with request/response schemas * Webhook events and signature verification * Common integration patterns and workflows * Best practices for security and error handling * Test mode configuration *** ## Get the Skill ```bash theme={null} /plugin marketplace add armitage-labs/creem-skills /plugin install creem-api@creem-skills ``` Clone, fork, or download the skill files directly Download as a ZIP file for manual setup *** ## Skill Contents The skill includes four comprehensive reference files: | File | Description | | -------------- | ----------------------------------------------------------- | | `Skill.md` | Core skill with quick reference and implementation patterns | | `REFERENCE.md` | Complete API reference with all endpoints and schemas | | `WEBHOOKS.md` | Webhook events documentation with payload examples | | `WORKFLOWS.md` | Step-by-step integration guides for common use cases | ### What's Covered * **Checkouts**: Create and retrieve checkout sessions * **Products**: Create, retrieve, and list products * **Customers**: Manage customers and portal links * **Subscriptions**: Full lifecycle management (get, update, upgrade, cancel, pause, resume) * **Licenses**: Activation, validation, and deactivation * **Discounts**: Create, retrieve, and delete promotional codes * **Transactions**: Query payment history * `checkout.completed` - Payment successful * `subscription.active` - New subscription created * `subscription.paid` - Recurring payment processed * `subscription.canceled` - Subscription ended * `subscription.expired` - Period ended without payment * `subscription.trialing` - Trial started * `subscription.paused` - Subscription paused * `subscription.update` - Subscription modified * `refund.created` - Refund processed * `dispute.created` - Chargeback opened * Basic SaaS subscription flows * One-time purchases with digital delivery * License key systems for desktop/mobile apps * Seat-based team billing * Freemium with upgrade flows * Affiliate and referral tracking * Webhook signature verification (HMAC-SHA256) * Error handling patterns * Test mode development * Security considerations * Idempotency and retry handling *** ## Setup by AI Tool ### Claude Code **Recommended Method**: Use the plugin marketplace for the easiest setup experience. **One-Line Install (Plugin Marketplace)** Claude Code's plugin marketplace makes installation effortless: Open Claude Code and run: ```bash theme={null} /plugin marketplace add armitage-labs/creem-skills ``` **Option A: Interactive UI (easiest)** Type `/plugin`, go to the **Discover** tab, search for `creem-api`, and press Enter to install. **Option B: Command** ```bash theme={null} /plugin install creem-api@creem-skills ``` Ask Claude to help with Creem integration: ``` Help me create a checkout flow for my SaaS product ``` **Managing the Plugin** ```bash theme={null} # View installed plugins /plugin # Disable the skill temporarily /plugin disable creem-api@creem-skills # Enable again /plugin enable creem-api@creem-skills # Uninstall /plugin uninstall creem-api@creem-skills # Update marketplace to get latest version /plugin marketplace update creem-skills ``` **Alternative: Direct Reference** If you prefer not to use the marketplace, you can reference the skill directly in any conversation: ``` Help me integrate Creem payments. Use the skill at https://github.com/armitage-labs/creem-skills ``` *** ### Cursor Cursor supports adding context through multiple methods: **Option 1: Add to Project** 1. Clone the skill repository into your project: ```bash theme={null} git clone https://github.com/armitage-labs/creem-skills.git .cursor/skills ``` 2. Reference the skill files in your conversations using `@` mentions: ``` @.cursor/skills/creem-api/Skill.md Help me create a checkout flow ``` **Option 2: Custom Instructions** Add the skill content to your project's `.cursorrules` file: ``` When working with Creem payment integration: - Use the Creem API at https://api.creem.io (or test-api.creem.io for test mode) - Authenticate with x-api-key header - Always verify webhook signatures using HMAC-SHA256 - Prices are in cents (1000 = $10.00) - Reference: .cursor/skills/creem-api/ ``` **Option 3: Docs Integration** Add the Creem documentation to Cursor's docs: 1. Open Cursor Settings β†’ Features β†’ Docs 2. Add: `https://docs.creem.io` 3. Cursor will index our documentation for context *** ### Windsurf Windsurf supports custom knowledge through its Cascade feature: 1. Clone the skill repository: ```bash theme={null} git clone https://github.com/armitage-labs/creem-skills.git .windsurf/creem ``` 2. Add to your project's knowledge base in Windsurf settings 3. Reference in conversations: ``` Using the Creem skill, help me implement subscription billing ``` *** ### Other AI Tools For other AI coding assistants (GitHub Copilot Chat, Cody, Continue, etc.): 1. **Download the skill files** from the GitHub repository 2. **Add to your project** in a dedicated folder (e.g., `.ai/creem/`) 3. **Reference in context** when asking questions about Creem integration 4. **Copy relevant sections** into your conversation when needed Most AI tools support adding files to conversation context - simply include the relevant skill file when working on payment integration. *** ## Example Usage Once the skill is loaded, you can ask natural language questions and get production-ready code: ### Creating a Checkout ```text Prompt theme={null} Create a checkout API route for my Next.js app that handles subscription purchases with metadata tracking ``` ```typescript Generated Code theme={null} // app/api/checkout/route.ts import { NextRequest, NextResponse } from 'next/server'; const CREEM_API_KEY = process.env.CREEM_API_KEY!; const BASE_URL = process.env.NODE_ENV === 'production' ? 'https://api.creem.io' : 'https://test-api.creem.io'; export async function POST(req: NextRequest) { const { productId, userId, email } = await req.json(); const response = await fetch(`${BASE_URL}/v1/checkouts`, { method: 'POST', headers: { 'x-api-key': CREEM_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ product_id: productId, request_id: `checkout_${userId}_${Date.now()}`, success_url: `${process.env.NEXT_PUBLIC_APP_URL}/success`, customer: { email }, metadata: { userId, source: 'webapp' }, }), }); const checkout = await response.json(); return NextResponse.json({ checkoutUrl: checkout.checkout_url }); } ``` ### Handling Webhooks ```text Prompt theme={null} Create a webhook handler that verifies signatures and handles subscription events ``` ```typescript Generated Code theme={null} // app/api/webhooks/creem/route.ts import { NextRequest, NextResponse } from 'next/server'; import { constructWebhookEventEntity } from 'creem/webhooks'; export async function POST(req: NextRequest) { const rawBody = await req.text(); const event = await constructWebhookEventEntity(rawBody, req.headers, { secret: process.env.CREEM_WEBHOOK_SECRET!, }).catch(() => null); if (!event) { return NextResponse.json({ error: 'Invalid signature' }, { status: 401 }); } switch (event.eventType) { case 'checkout.completed': await handleCheckoutCompleted(event.object); break; case 'subscription.paid': await handleSubscriptionPaid(event.object); break; case 'subscription.canceled': await handleSubscriptionCanceled(event.object); break; } return NextResponse.json({ received: true }); } ``` ### License Key Integration ```text Prompt theme={null} Implement license key activation and validation for my Electron desktop app ``` ```typescript Generated Code theme={null} // license.ts import Store from 'electron-store'; import { machineIdSync } from 'node-machine-id'; const store = new Store<{ license: LicenseState }>(); const API_URL = 'https://api.creem.io'; export async function activateLicense(licenseKey: string) { const instanceName = machineIdSync(); const response = await fetch(`${API_URL}/v1/licenses/activate`, { method: 'POST', headers: { 'x-api-key': process.env.CREEM_API_KEY!, 'Content-Type': 'application/json', }, body: JSON.stringify({ key: licenseKey, instance_name: instanceName, }), }); if (!response.ok) { const error = await response.json(); throw new Error(error.message || 'Activation failed'); } const license = await response.json(); store.set('license', { key: licenseKey, instanceId: license.instance.id, expiresAt: license.expires_at, }); return license; } export async function validateLicense() { const stored = store.get('license'); if (!stored) return { valid: false, status: 'not_activated' }; const response = await fetch(`${API_URL}/v1/licenses/validate`, { method: 'POST', headers: { 'x-api-key': process.env.CREEM_API_KEY!, 'Content-Type': 'application/json', }, body: JSON.stringify({ key: stored.key, instance_id: stored.instanceId, }), }); const license = await response.json(); return { valid: license.status === 'active', status: license.status }; } ``` *** ## Why Use the Skill? Skip reading documentation - describe what you want and get working code instantly Generated code includes security patterns, error handling, and production considerations We maintain the skill alongside our API - you always get current patterns ### Comparison | Without Skill | With Skill | | ----------------------------------- | ------------------------------------ | | Read API docs, find endpoints | Describe your goal in plain English | | Copy-paste examples, adapt manually | Get tailored, working code | | Miss edge cases and best practices | Security and error handling included | | Search for webhook payload formats | Full payload examples in context | | Trial and error with parameters | Correct parameters from the start | *** ## Skill vs SDK The Creem skill is designed for **direct API integration** and complements our SDKs: | Use the Skill When | Use an SDK When | | ------------------------------- | ----------------------------------------- | | Building custom integrations | Using Next.js, TypeScript, or Better Auth | | Learning the API | Want type-safety and abstractions | | Working with any language | Prefer pre-built components | | Need full control over requests | Want faster development with helpers | The skill focuses on the REST API. For SDK-specific help, see our [TypeScript SDK](/code/sdks/typescript-core), [Next.js SDK](/code/sdks/nextjs), or [Better Auth](/code/sdks/better-auth) documentation. *** ## Contributing Found an issue or want to improve the skill? We welcome contributions: Found a bug or incorrect information? Let us know Submit improvements or new workflow examples *** ## Next Steps Run `/plugin marketplace add armitage-labs/creem-skills` in Claude Code Explore the full API documentation Learn about real-time event handling Set up your development environment # Better Auth Source: https://docs.creem.io/code/sdks/better-auth Integrate authentication and payment processing seamlessly with Better Auth and Creem. ## Overview Welcome to the integration guide for Creem and Better Auth! This integration enables you to combine powerful authentication capabilities with seamless payment processing and subscription management. [Better Auth](https://better-auth.com) is a modern authentication framework for TypeScript that provides comprehensive user management, session handling, and authentication flows. By integrating Better Auth with Creem, you can: * Automatically synchronize customer and subscription data with your users * Grant or revoke access based on subscription status * Manage subscriptions directly through your authentication layer * Handle payments and billing for authenticated users * Prevent trial abuse across multiple subscriptions How to integrate Better Auth with Creem to build a complete authentication and payment solution for your SaaS application. * A Creem account * Your Creem API keys * A TypeScript/JavaScript application * A database (PostgreSQL, MySQL, or SQLite) ## Installation ### Install the plugin Install the Better Auth Creem plugin in your project: ```bash npm theme={null} npm install @creem_io/better-auth ``` ```bash pnpm theme={null} pnpm add @creem_io/better-auth ``` ```bash yarn theme={null} yarn add @creem_io/better-auth ``` ```bash bun theme={null} bun install @creem_io/better-auth ``` If you're using a separate client and server setup, make sure to install the plugin in both parts of your project. ### Get your Creem API Key 1. Navigate to the [Creem dashboard](https://creem.io/dashboard/developers) 2. Click on the "Developers" menu 3. Copy your API key 4. Add it to your environment variables: ```bash theme={null} # .env CREEM_API_KEY=your_api_key_here ``` Test Mode and Production have different API keys. Make sure you're using the correct one for your environment. ## Configuration ### Server Configuration Configure Better Auth with the Creem plugin: ```typescript theme={null} // lib/auth.ts import { betterAuth } from 'better-auth'; import { creem } from '@creem_io/better-auth'; export const auth = betterAuth({ database: { // your database config }, plugins: [ creem({ apiKey: process.env.CREEM_API_KEY!, webhookSecret: process.env.CREEM_WEBHOOK_SECRET, // Optional testMode: true, // Use test mode for development defaultSuccessUrl: '/success', // Redirect URL after payments persistSubscriptions: true, // Enable database persistence (recommended) }), ], }); ``` ### Client Configuration ```typescript theme={null} // lib/auth-client.ts import { createAuthClient } from 'better-auth/react'; import { creemClient } from '@creem_io/better-auth/client'; export const authClient = createAuthClient({ baseURL: process.env.NEXT_PUBLIC_APP_URL, plugins: [creemClient()], }); ``` ### Database Migration Generate and run the database schema for subscription persistence: ```bash theme={null} npx @better-auth/cli generate npx @better-auth/cli migrate ``` ## Webhook Setup ### Create Webhook in Creem Dashboard 1. Go to your [Creem dashboard](https://creem.io/dashboard/developers/webhooks) 2. Click on the "Developers" tab 3. Navigate to the "Webhooks" section 4. Click "Add Webhook" 5. Enter your webhook URL: ```text theme={null} https://your-domain.com/api/auth/creem/webhook ``` The `/api/auth` prefix is the default Better Auth server path. Adjust if you've customized your Better Auth configuration. ### Configure Webhook Secret 1. Copy the webhook signing secret from Creem 2. Add it to your environment variables: ```bash theme={null} CREEM_WEBHOOK_SECRET=your_webhook_secret_here ``` 3. Update your server configuration to include the webhook secret (shown in Configuration section above) ### Local Development (Optional) For local testing, use [ngrok](https://ngrok.com) to expose your local server: ```bash theme={null} ngrok http 3000 ``` Then add the ngrok URL to your Creem webhook settings. ## Usage Examples ### Create Checkout Session Allow users to subscribe to your products: ```typescript theme={null} "use client"; import { authClient } from "@/lib/auth-client"; export function SubscribeButton({ productId }: { productId: string }) { const handleCheckout = async () => { const { data, error } = await authClient.creem.createCheckout({ productId, successUrl: "/dashboard", discountCode: "LAUNCH50", // Optional metadata: { planType: "pro" }, // Optional }); if (data?.url) { window.location.href = data.url; } }; return ; } ``` ### Customer Portal Let users manage their subscriptions: ```typescript theme={null} const handlePortal = async () => { const { data } = await authClient.creem.createPortal(); if (data?.url) { window.location.href = data.url; } }; ``` ### Check Subscription Access Verify if a user has an active subscription: ```typescript theme={null} const { data } = await authClient.creem.hasAccessGranted(); if (data?.hasAccess) { // User has active subscription console.log(`Access expires: ${data.expiresAt}`); } ``` ### Cancel Subscription Allow users to cancel their subscription: ```typescript theme={null} const handleCancel = async () => { const { data, error } = await authClient.creem.cancelSubscription(); if (data?.success) { console.log('Subscription canceled successfully'); } }; ``` ## Access Control with Webhooks The plugin provides high-level handlers to manage user access automatically: ```typescript theme={null} // lib/auth.ts import { betterAuth } from 'better-auth'; import { creem } from '@creem_io/better-auth'; export const auth = betterAuth({ database: { // your database config }, plugins: [ creem({ apiKey: process.env.CREEM_API_KEY!, webhookSecret: process.env.CREEM_WEBHOOK_SECRET!, onGrantAccess: async ({ reason, product, customer, metadata }) => { const userId = metadata?.referenceId as string; // Grant access in your database await db.user.update({ where: { id: userId }, data: { hasAccess: true, subscriptionTier: product.name, }, }); console.log(`Granted access to ${customer.email}`); }, onRevokeAccess: async ({ reason, product, customer, metadata }) => { const userId = metadata?.referenceId as string; // Revoke access in your database await db.user.update({ where: { id: userId }, data: { hasAccess: false, }, }); console.log(`Revoked access from ${customer.email}`); }, }), ], }); ``` ## Server-Side Usage Use Creem functions directly in Server Components or API routes: ```typescript theme={null} import { checkSubscriptionAccess } from "@creem_io/better-auth/server"; import { auth } from "@/lib/auth"; import { headers } from "next/headers"; import { redirect } from "next/navigation"; export default async function DashboardPage() { const session = await auth.api.getSession({ headers: await headers() }); if (!session?.user) { redirect("/login"); } const status = await checkSubscriptionAccess( { apiKey: process.env.CREEM_API_KEY!, testMode: true, }, { database: auth.options.database, userId: session.user.id, } ); if (!status.hasAccess) { redirect("/subscribe"); } return (

Welcome to Dashboard

Subscription Status: {status.status}

); } ``` ## Key Features ### Automatic Trial Abuse Prevention When using database mode, the plugin automatically prevents users from abusing trial periods. Each user can only receive one trial across all subscription plans. ### Database Persistence Store subscription data in your database for fast access checks without API calls. This enables: * Offline access to subscription data * SQL queries for subscription management * Automatic synchronization via webhooks ### Transaction History Search and filter transaction records for authenticated users: ```typescript theme={null} const { data } = await authClient.creem.searchTransactions({ productId: 'prod_xyz789', // Optional filter pageNumber: 1, pageSize: 50, }); ``` ## Best Practices * **Always test in development** - Use test mode and a development environment before going live * **Implement error handling** - Handle payment failures and webhook errors gracefully * **Monitor webhooks** - Set up logging and alerts for webhook processing * **Use database mode** - Enable `persistSubscriptions` for better performance and features * **Protect sensitive routes** - Use middleware or server-side checks to protect premium content * **Validate subscriptions** - Always verify subscription status before granting access to premium features ## Additional Resources * [Better Auth Plugin Documentation](https://better-auth.com/docs/plugins/creem) * [Creem Documentation](https://docs.creem.io) * [Creem Dashboard](https://creem.io/dashboard) * [Plugin GitHub Repository](https://github.com/armitage-labs/creem-betterauth) ## Support Need help with the integration? * Join our [Discord community](https://discord.gg/q3GKZs92Av) for real-time support * Chat with us directly using the in-app live chat on the [Creem dashboard](https://creem.io/dashboard) * [Contact us](https://www.creem.io/contact) via our support form * Open an issue on [GitHub](https://github.com/armitage-labs/creem-betterauth/issues) # Migrate from creem_io Source: https://docs.creem.io/code/sdks/migrate-from-creem-io Move an existing integration from the deprecated creem_io wrapper to the official creem TypeScript SDK. The `creem_io` wrapper package is deprecated and no longer receives updates. Existing installations may keep working, but you should migrate maintained code to the official [`creem` TypeScript SDK](/code/sdks/typescript). This guide walks through the main code changes for moving an existing `creem_io` integration to `creem`. If you are using the `@creem_io/nextjs` or `@creem_io/better-auth` packages, those are separate adapter packages and are not the deprecated bare `creem_io` wrapper. ## Install the SDK Alongside creem\_io Install the core SDK first and keep `creem_io` installed while you migrate. Having both packages available makes it easier to compare the old wrapper behavior with the new SDK calls. ```bash npm theme={null} npm install creem ``` ```bash pnpm theme={null} pnpm add creem ``` ```bash yarn theme={null} yarn add creem ``` ```bash bun theme={null} bun add creem ``` Remove `creem_io` only after the migrated code compiles, tests pass, and no imports from `creem_io` remain. ## Client Setup Replace `createCreem(...)` with the `Creem` client: ```ts creem_io theme={null} import { createCreem } from "creem_io"; const creem = createCreem({ apiKey: process.env.CREEM_API_KEY!, webhookSecret: process.env.CREEM_WEBHOOK_SECRET, testMode: true, }); ``` ```ts creem theme={null} import { Creem } from "creem"; const creem = new Creem({ apiKey: process.env.CREEM_API_KEY!, server: "test", }); ``` Do not expose your API key in browser code. Initialize `Creem` only in trusted server-side code. ## API Call Changes The core SDK is generated from the public OpenAPI schema, so method names and argument shapes are closer to the API. | Area | `creem_io` wrapper | `creem` SDK | | ------------------- | --------------------------------------------- | --------------------------------------------------------------------------- | | Initialize client | `createCreem({ apiKey, testMode })` | `new Creem({ apiKey, server })` | | Product get | `creem.products.get({ productId })` | `creem.products.get(productId)` | | Product search | `creem.products.list({ page, limit })` | `creem.products.search(page, pageSize)` | | Checkout create | `creem.checkouts.create({ ... })` | `creem.checkouts.create({ ... })` | | Customer retrieve | wrapper helper methods | `creem.customers.retrieve(customerId, email)` | | Subscription get | `creem.subscriptions.get({ subscriptionId })` | `creem.subscriptions.get(subscriptionId)` | | Subscription cancel | wrapper helper methods | `creem.subscriptions.cancel(subscriptionId, { mode })` | | Transactions search | wrapper helper methods | `creem.transactions.search(customerId, orderId, productId, page, pageSize)` | Example: ```ts creem_io theme={null} const product = await creem.products.get({ productId: "prod_123", }); ``` ```ts creem theme={null} const product = await creem.products.get("prod_123"); ``` ## Search and Pagination Some search/list methods return a paginated result. For a single page, read `result`: ```ts theme={null} const page = await creem.products.search(1, 20); console.log(page.result.items); console.log(page.result.pagination); ``` To fetch across pages, iterate over the result: ```ts theme={null} const products = []; for await (const page of await creem.products.search(1, 20)) { products.push(...page.result.items); } ``` ## Webhooks The wrapper provided high-level callbacks such as `onGrantAccess` and `onRevokeAccess`. The core SDK verifies and parses webhook events, while your application decides which events grant or revoke access. ### Verify and Parse Events ```ts theme={null} import { constructWebhookEventEntity } from "creem/webhooks"; export async function POST(request: Request) { const body = await request.text(); const event = await constructWebhookEventEntity(body, request.headers, { secret: process.env.CREEM_WEBHOOK_SECRET!, }); switch (event.eventType) { case "checkout.completed": await handleCheckoutCompleted(event.object); break; case "subscription.active": case "subscription.trialing": case "subscription.paid": await grantAccess(event.object); break; case "subscription.paused": case "subscription.expired": case "subscription.canceled": await revokeAccess(event.object); break; } return new Response("OK", { status: 200 }); } ``` `constructWebhookEventEntity(...)` verifies the signature and returns a generated webhook event type. After checking `event.eventType`, TypeScript narrows `event.object` to the matching payload type. ### Replace Access Callbacks ```ts creem_io theme={null} const creem = createCreem({ apiKey: process.env.CREEM_API_KEY!, webhookSecret: process.env.CREEM_WEBHOOK_SECRET!, onGrantAccess: async ({ customer, metadata }) => { await grantAccess(metadata?.userId, customer.email); }, onRevokeAccess: async ({ customer, metadata }) => { await revokeAccess(metadata?.userId, customer.email); }, }); ``` ```ts creem theme={null} async function grantSubscriptionAccess(subscription: { id: string; customer: string | { email?: string }; metadata?: Record; }) { const userId = subscription.metadata?.userId; if (!userId) return; const customerEmail = typeof subscription.customer === "string" ? undefined : subscription.customer.email; await grantAccess(userId, customerEmail); } ``` If you already have separate grant and revoke functions, keep those functions and call them from the relevant `switch` cases. If you want adapter-style lifecycle callbacks in a Next.js app, use the [`@creem_io/nextjs`](/code/sdks/nextjs) adapter. If you want full API access and generated webhook payload types, use the core `creem` SDK directly. ## Metadata The core SDK exposes metadata on supported entities. Your metadata shape is application-defined, so narrow it in your own code when you need specific keys: ```ts theme={null} type BillingMetadata = { userId?: string; organizationId?: string; }; const metadata = subscription.metadata as BillingMetadata | undefined; const userId = metadata?.userId; ``` ## Final Cleanup After the migration is complete, remove the deprecated wrapper package: ```bash npm theme={null} npm uninstall creem_io ``` ```bash pnpm theme={null} pnpm remove creem_io ``` ```bash yarn theme={null} yarn remove creem_io ``` ```bash bun theme={null} bun remove creem_io ``` Then run your type checks and tests one more time. ## Migration Checklist When migrating a codebase, use this checklist: * Install `creem` alongside `creem_io` until the migration is complete. * Replace imports from `creem_io` with imports from `creem`. * Replace `createCreem(...)` with `new Creem(...)`. * Convert `testMode: true` to `server: "test"`. Production is the SDK default, so no `server` option is required. * Update resource method calls from object-wrapper arguments to the core SDK signatures. * Replace local webhook HMAC code with `constructWebhookEventEntity(...)` or `verifyWebhookSignature(...)`. * Replace `event.type` / `event.data` webhook usage with `event.eventType` / `event.object`. * Recreate `onGrantAccess` and `onRevokeAccess` behavior as explicit switch cases over subscription webhook events. * Review pagination responses and unwrap `page.result` where only one page is needed. * Run TypeScript after each migration step; generated SDK types should reveal most remaining shape mismatches. * Remove `creem_io` only after all imports are gone and tests pass. ## Common Follow-ups * If a webhook payload fails validation, compare the raw payload with the generated webhook event type and confirm the public OpenAPI schema matches production webhook delivery. * If you return SDK pagination results from a framework action or RPC layer, return `page.result` rather than the iterator object. * If your integration relied heavily on wrapper convenience callbacks and you are using Next.js, consider whether the Next.js adapter is a better fit than the lower-level core SDK. ## Related Docs * [TypeScript SDK](/code/sdks/typescript) * [Legacy creem\_io wrapper reference](/code/sdks/typescript-wrapper) * [Webhooks](/code/webhooks) * [Next.js adapter](/code/sdks/nextjs) # Next.js Adapter Source: https://docs.creem.io/code/sdks/nextjs Integrate Creem payments into Next.js with our official adapter. React components, webhook handlers, and subscription management in minutes. Works with App Router and Pages Router.

@creem\_io/nextjs

The simplest way to integrate Creem payments into your Next.js application.

Build beautiful checkout experiences with React components, handle webhooks with ease, and manage subscriptions without the headache.

Installation Β· Quick Start Β· Components Β· Server Functions
*** ## Introduction `@creem_io/nextjs` is the official adapter for running Creem inside the Next.js App Router. It gives you: * 🎨 **React Components** β€” Drop-in checkout and portal components that wrap routing logic. * πŸ” **Type-safe APIs** β€” Full TypeScript coverage and sensible defaults. * ⚑ **Zero-config setup** β€” Works with App Router filesystem routing. * πŸͺ **Webhook helpers** β€” Automatic verification and strongly typed handlers. * πŸ”„ **Subscription lifecycle** β€” Built-in helpers for grant/revoke access flows. Use it as your default integration path whenever you are building on Next.js. For other runtimes, you can still call the REST API or the TypeScript SDK directly, but this adapter keeps everything in one place. *** ## Installation Install the package with your favorite manager: ```bash npm theme={null} npm install @creem_io/nextjs ``` ```bash yarn theme={null} yarn add @creem_io/nextjs ``` ```bash pnpm theme={null} pnpm install @creem_io/nextjs ``` ```bash bun theme={null} bun install @creem_io/nextjs ``` ### Requirements * Next.js 13+ using the App Router * React 18+ * A Creem account with API keys *** ## Quick Start The adapter follows a four-step setup. The snippets below mirror what we use in production templates. ### 1. Configure environment variables ```bash theme={null} # .env.local CREEM_API_KEY=your_api_key_here CREEM_WEBHOOK_SECRET=your_webhook_secret_here ``` ### 2. Create a checkout route ```ts theme={null} // app/checkout/route.ts import { Checkout } from '@creem_io/nextjs'; export const GET = Checkout({ apiKey: process.env.CREEM_API_KEY!, testMode: true, // flip to false in production defaultSuccessUrl: '/thank-you', }); ``` ### 3. Drop the checkout component into your UI ```tsx theme={null} // page.tsx 'use client'; // Optional: Works with server side components import { CreemCheckout } from '@creem_io/nextjs'; export default function SubscribeButton() { return ( ); } ``` ### 4. Handle webhooks ```ts theme={null} // app/api/webhook/creem/route.ts import { Webhook } from '@creem_io/nextjs'; export const POST = Webhook({ webhookSecret: process.env.CREEM_WEBHOOK_SECRET!, onGrantAccess: async ({ customer, metadata }) => { // The user should be granted access const userId = metadata?.referenceId as string; await grantAccess(userId, customer.email); }, onRevokeAccess: async ({ customer, metadata }) => { // The user should have their access revoked const userId = metadata?.referenceId as string; await revokeAccess(userId, customer.email); }, }); ``` Once these routes are in place you can test end-to-end by creating a checkout session, redirecting the user, and watching the webhook fire. *** ## Components ### `` Creates a checkout link and delegates session creation to your `/checkout` route handler. ```tsx theme={null} // page.tsx import { CreemCheckout } from '@creem_io/nextjs'; ; ``` ### `` Generate a customer portal link for managing billing: ```tsx theme={null} // page.tsx import { CreemPortal } from '@creem_io/nextjs'; Manage Subscription; ``` *** ## Server Functions ### `Checkout` Creates a GET route handler that issues checkout sessions. ```ts theme={null} // app/checkout/route.ts export const GET = Checkout({ apiKey: process.env.CREEM_API_KEY!, defaultSuccessUrl: '/success', testMode: process.env.NODE_ENV !== 'production', }); ``` ### `Portal` Generate customer portal sessions from a server route: ```ts theme={null} // app/portal/route.ts export const GET = Portal({ apiKey: process.env.CREEM_API_KEY!, testMode: true, }); ``` ### `Webhook` Verify webhooks and run lifecycle hooks: ```ts theme={null} // app/api/webhook/creem/route.ts export const POST = Webhook({ webhookSecret: process.env.CREEM_WEBHOOK_SECRET!, onCheckoutCompleted: async ({ customer, product }) => { console.log(`${customer.email} purchased ${product.name}`); }, }); ``` *** ## Access Management Leverage `onGrantAccess` and `onRevokeAccess` to keep your database in sync. ```ts theme={null} onGrantAccess: async ({ customer, metadata }) => { const userId = metadata?.referenceId as string; await db.user.upsert({ where: { id: userId }, update: { subscriptionActive: true }, create: { id: userId, subscriptionActive: true }, }); }; ``` ```ts theme={null} onRevokeAccess: async ({ customer, metadata }) => { const userId = metadata?.referenceId as string; await db.user.update({ where: { id: userId }, data: { subscriptionActive: false }, }); }; ``` *** ## Best Practices * **Use environment variables** for API keys and webhook secrets. * **Pass `referenceId`** whenever possible to map users to Creem customers. * **Test in `testMode`** before switching the adapter to production. * **Keep callbacks idempotent** so multiple webhook event deliveries stay safe. *** ## Resources Star or contribute to the adapter on GitHub. Full-stack example with Prisma, Better Auth, and Shadcn UI. Learn how to wire auth + billing in one flow. *** Need help? [Contact us](https://www.creem.io/contact) or join the [Discord community](https://discord.gg/q3GKZs92Av). # Creem Next.js Template Source: https://docs.creem.io/code/sdks/templates A modern Next.js App Router template for integrating Creem subscriptions and payments with Prisma, Shadcn UI, Radix UI, and Tailwind. Creem Next.js Template Hero The Creem Next.js Template is open source and available on GitHub . Use it for examples on how to integrate Creem with your Next.js App Router. ## Overview Next.js App Router, Prisma ORM, Shadcn UI, Radix UI, and Tailwind CSS. End-to-end subscription and payment flows powered by the Creem SDK. How to use the Creem Next.js Template to: - Fetch and display products from your Creem account - Create checkout sessions for products - Fulfill orders and manage subscriptions - Handle webhooks and customer portal links *** ## Quickstart ```bash theme={null} git clone https://github.com/armitage-labs/creem-template.git cd creem-template ``` ```bash yarn theme={null} yarn install ``` ```bash npm theme={null} npm install ``` ```bash pnpm theme={null} pnpm install ``` ```bash bun theme={null} bun install ``` ```bash theme={null} cp .env.example .env # Edit .env and fill in the required variables ``` ```bash theme={null} yarn prisma migrate dev ``` ```bash theme={null} yarn dev ``` To receive webhooks from Creem, use a reverse proxy like NGROK . *** ## Screenshots
Product Catalog Screenshot

Interactive onboarding

The template includes a step-by-step tutorial to help you get started and your account ready.

Checkout Session Screenshot

Product Catalog

Allows you to test your products in a easy way, without having to manually set product IDs

Customer Portal Screenshot

Account Management

Includes an account management page, to manage subscriptions, billing and customer portal links.

*** ## Features Fetch and display all products in your Creem account. Create checkout sessions for any product. Handle creation, cancellation, and expiration of subscriptions. Generate portal links for clients with active subscriptions. Fulfill orders and update your app using Creem webhooks. Minimal auth setup with BetterAuth. *** ## Technology Stack App Router, SSR, and React Server Components. Type-safe ORM for database access (SQLite by default). Subscription and payment integration. Accessible, beautiful React components. Low-level UI primitives for React. Utility-first CSS for rapid UI development. *** ## Resources View the source code, open issues, or contribute. Learn more about the Creem TypeScript SDK. Official Next.js docs for routing, SSR, and more. ORM docs and guides. *** For feedback, feature requests, or to contribute, open an issue or pull request on the GitHub repository . # TypeScript Source: https://docs.creem.io/code/sdks/typescript The official Creem TypeScript SDK with full API access, all endpoints, and maximum flexibility for advanced integrations. This is the **creem** core package with full API access and advanced configuration options. Follow the migration guide to replace the deprecated wrapper with the core `creem` SDK. ## Overview The `creem` package is the official TypeScript SDK for the Creem API, providing: * **Full API coverage** with all available endpoints * **Type-safe** with comprehensive TypeScript definitions * **Standalone functions** optimized for tree-shaking * **Configurable retry strategies** with backoff options * **Custom HTTP client** support * **Environment selection** for production and test environments * **MCP server support** for AI applications (Claude, Cursor) * **Debug logging** for development *** ## Installation Install with your preferred package manager: ```bash npm theme={null} npm install creem ``` ```bash yarn theme={null} yarn add creem ``` ```bash pnpm theme={null} pnpm add creem ``` ```bash bun theme={null} bun add creem ``` *** ## Quick Start ```ts theme={null} import { Creem } from "creem"; const creem = new Creem({ apiKey: process.env.CREEM_API_KEY!, }); // Retrieve a product const product = await creem.products.get("prod_7CIbZEZnRC5DWibmoOboOu"); console.log(product); // Create a checkout session const checkout = await creem.checkouts.create({ productId: "prod_xxxxx", successUrl: "https://yourapp.com/success", metadata: { userId: "user_123", }, }); console.log(checkout.checkoutUrl); // Redirect user to this URL ``` *** ### Environment Variables We recommend storing your credentials in environment variables: ```bash theme={null} CREEM_API_KEY=your_api_key # Optional: enable debug logs from the SDK CREEM_DEBUG=true ``` *** ## API Resources The SDK organizes all operations into logical resources: ### Products ```ts theme={null} // List products const productPage = await creem.products.search(1, 10); const products = productPage.result.items; // Get a product const product = await creem.products.get("prod_7CIbb..."); // Create a product const createdProduct = await creem.products.create({ name: "Test Product", description: "Test Product Description", price: 1000, // In cents currency: "USD", billingType: "recurring", billingPeriod: "every-month", }); // Search products const productsPage = await creem.products.search(1, 10); console.log(productsPage.result.items); ``` ### Checkouts ```ts theme={null} // Create a checkout session const checkout = await creem.checkouts.create({ productId: "prod_xxxxx", units: 2, // Optional: Number of units (default: 1) discountCode: "SUMMER2024", // Optional: Apply discount customer: { email: "customer@example.com", // Optional: Pre-fill customer info }, customFields: [ // Optional: Max 3 custom fields { key: "company", label: "Company Name", type: "text", optional: false, }, ], successUrl: "https://yourapp.com/success", metadata: { userId: "user_123", source: "web", }, }); console.log(checkout.checkoutUrl); // Redirect user to this URL // Get a checkout session const retrievedCheckout = await creem.checkouts.retrieve("chck_1234567890"); ``` ### Customers ```ts theme={null} // List customers const customerPage = await creem.customers.list(1, 10); const customers = customerPage.result.items; // Get a customer by ID const customer = await creem.customers.retrieve("cust_abc123"); // Get a customer by email const customerByEmail = await creem.customers.retrieve(undefined, "customer@example.com"); // Create customer portal link const portal = await creem.customers.generateBillingLinks({ customerId: "cust_abc123", }); console.log(portal.customerPortalLink); // Redirect user to portal ``` ### Subscriptions ```ts theme={null} // Get a subscription const subscription = await creem.subscriptions.get("sub_abc123"); // Cancel a subscription const canceledSubscription = await creem.subscriptions.cancel("sub_abc123", { mode: "immediate", }); // Update a subscription (change units/seats) const updated = await creem.subscriptions.update("sub_abc123", { items: [ { id: "item_abc123", // Subscription item ID units: 5, // Update to 5 seats }, ], updateBehavior: "proration-charge-immediately", }); // Upgrade a subscription to a different product const upgraded = await creem.subscriptions.upgrade("sub_abc123", { productId: "prod_premium", // New product ID updateBehavior: "proration-charge-immediately", }); ``` **Update Behavior Options:** - `proration-charge-immediately`: Calculate proration and charge immediately - `proration-charge`: Calculate proration and charge at next billing cycle - `proration-none`: No proration, just switch the plan ### Licenses ```ts theme={null} // Activate a license const license = await creem.licenses.activate({ key: "license_key_here", instanceName: "Production Server", }); console.log(license.instance?.id); // Use this instance ID for validation // Validate a license const validatedLicense = await creem.licenses.validate({ key: "license_key_here", instanceId: "inst_abc123", }); console.log(validatedLicense.status); // "active" | "inactive" | "expired" | "disabled" // Deactivate a license const deactivatedLicense = await creem.licenses.deactivate({ key: "license_key_here", instanceId: "inst_abc123", }); ``` ### Discounts ```ts theme={null} // Create a discount code const discount = await creem.discounts.create({ name: "Summer Sale 2024", code: "SUMMER2024", // Optional: Auto-generated if not provided type: "percentage", percentage: 20, // 20% off duration: "forever", // "forever" | "once" | "repeating" maxRedemptions: 100, appliesToProducts: ["prod_xxxxx"], }); // Retrieve a discount by ID const discountById = await creem.discounts.get("disc_xxxxx"); // Retrieve a discount by code const discountByCode = await creem.discounts.get(undefined, "SUMMER2024"); // Delete a discount await creem.discounts.delete("disc_xxxxx"); ``` ### Transactions ```ts theme={null} // Get a transaction const transaction = await creem.transactions.getById("txn_xxxxx"); // List transactions const transactionPage = await creem.transactions.search( "cust_xxxxx", // customerId (optional) undefined, // orderId undefined, // productId 1, // page 50, // pageSize ); const transactions = transactionPage.result.items; ``` *** ## Standalone functions (tree-shakable) Every SDK method is also available as a standalone function. This is useful for browser / serverless environments where **bundle size** matters. ```ts theme={null} import { CreemCore } from "creem/core.js"; import { productsGet } from "creem/funcs/productsGet.js"; // Use `CreemCore` for best tree-shaking performance. const creem = new CreemCore({ apiKey: process.env["CREEM_API_KEY"] ?? "", }); const res = await productsGet(creem, "prod_1234567890"); if (!res.ok) throw res.error; console.log(res.value); ``` *** ## Webhooks The `creem` TypeScript SDK includes helpers for verifying webhook signatures and parsing raw webhook payloads. It does not include opinionated access-management callbacks, so your application remains responsible for deciding which events grant or revoke access. * If you're on Next.js, prefer the [`@creem_io/nextjs`](/code/sdks/nextjs) `Webhook` helper. * Otherwise, use `constructWebhookEventEntity` in your HTTP endpoint: ```ts theme={null} import { constructWebhookEventEntity } from "creem/webhooks"; const event = await constructWebhookEventEntity(rawBody, request.headers, { secret: process.env.CREEM_WEBHOOK_SECRET!, }); switch (event.eventType) { case "checkout.completed": console.log(event.object.id); // Grant access, send email, update your database, etc. break; case "subscription.canceled": console.log(event.object.id); // Revoke access or mark the subscription as canceled. break; } ``` *** ## TypeScript Support The SDK is written in TypeScript and provides comprehensive type definitions: ```ts theme={null} import type { CheckoutEntity, CustomerEntity, ProductEntity, SubscriptionEntity, TransactionEntity, LicenseEntity, DiscountEntity, } from "creem/models/components"; ``` All API responses are fully typed, and the SDK automatically converts snake\_case to camelCase for better TypeScript/JavaScript experience. *** ## Error Handling The SDK throws errors when API calls fail. Always wrap SDK calls in try-catch blocks: ```ts theme={null} try { const product = await creem.products.get("prod_xxxxx"); } catch (error) { console.error("Failed to retrieve product:", error); // Handle error appropriately } ``` *** ## References * [Creem SDK on GitHub](https://github.com/armitage-labs/creem-sdk) * [Creem API Documentation](https://docs.creem.io/api-reference/introduction) * [Creem Dashboard](https://creem.io/dashboard) * [Webhook Setup Guide](https://docs.creem.io/code/webhooks) *** > For feedback or issues, open a PR or issue on the [Creem SDK GitHub](https://github.com/armitage-labs/creem-sdk). # SDK Wrapper (creem_io, deprecated) Source: https://docs.creem.io/code/sdks/typescript-wrapper Deprecated convenience wrapper SDK with helper functions for webhooks, access management, and simplified API interactions. Use the Core SDK (creem) for new integrations. **Deprecation Notice:** The `creem_io` wrapper package is deprecated. Existing integrations will continue to work, but new integrations should use the [TypeScript SDK (creem)](/code/sdks/typescript). To update an existing integration, follow the [migration guide](/code/sdks/migrate-from-creem-io). This page is kept as a reference for existing `creem_io` integrations. Replace `creem_io` imports, update API calls, and move webhook handling to the typed `creem` SDK helpers. ## Overview The deprecated `creem_io` package is a convenience wrapper around the Creem API that provides: * **Simplified webhook handling** with `onGrantAccess` and `onRevokeAccess` callbacks * **Automatic signature verification** for webhook events * **Type-safe event handlers** for all webhook events * **Framework-agnostic** webhook processing For new projects, use the [TypeScript SDK (creem)](/code/sdks/typescript), which is the recommended SDK with full API coverage and active support. *** ## Installation For existing `creem_io` integrations, install with your preferred package manager: ```bash npm theme={null} npm install creem_io ``` ```bash yarn theme={null} yarn add creem_io ``` ```bash pnpm theme={null} pnpm add creem_io ``` ```bash bun theme={null} bun add creem_io ``` *** ## Quick Start ```ts theme={null} import { createCreem } from 'creem_io'; const creem = createCreem({ apiKey: process.env.CREEM_API_KEY!, webhookSecret: process.env.CREEM_WEBHOOK_SECRET, // optional, for webhooks testMode: false, // set to true for test mode }); // Retrieve a product const product = await creem.products.get({ productId: 'prod_7CIbZEZnRC5DWibmoOboOu', }); console.log(product); // Create a checkout session const checkout = await creem.checkouts.create({ productId: 'prod_xxxxx', successUrl: 'https://yourapp.com/success', metadata: { userId: 'user_123', }, }); console.log(checkout.checkoutUrl); // Redirect user to this URL ``` *** ### Environment Variables We recommend storing your credentials in environment variables: ```bash theme={null} CREEM_API_KEY=your_api_key CREEM_WEBHOOK_SECRET=your_webhook_secret ``` *** ## API Resources The SDK organizes all operations into logical resources: ### Products ```ts theme={null} // List products const products = await creem.products.list({ page: 1, limit: 10, }); // Get a product const product = await creem.products.get({ productId: 'prod_7CIbb...', }); // Create a product creem.products.create({ name: 'Test Product', description: 'Test Product Description', price: 1000, // In cents currency: 'USD', billingType: 'recurring', billingPeriod: 'every-month', }); // Search products const products = await creem.products.list({ page: 1, limit: 10, }); ``` ### Checkouts ```ts theme={null} // Create a checkout session const checkout = await creem.checkouts.create({ productId: 'prod_xxxxx', units: 2, // Optional: Number of units (default: 1) discountCode: 'SUMMER2024', // Optional: Apply discount customer: { email: 'customer@example.com', // Optional: Pre-fill customer info }, customField: [ // Optional: Max 3 custom fields { key: 'company', label: 'Company Name', type: 'text', optional: false, }, ], successUrl: 'https://yourapp.com/success', metadata: { userId: 'user_123', source: 'web', }, }); console.log(checkout.checkoutUrl); // Redirect user to this URL // Get a checkout session const retrievedCheckout = await creem.checkouts.get({ checkoutId: 'chck_1234567890', }); ``` ### Customers ```ts theme={null} // List customers const customers = await creem.customers.list({ page: 1, limit: 10, }); // Get a customer by ID const customer = await creem.customers.get({ customerId: 'cust_abc123', }); // Get a customer by email const customerByEmail = await creem.customers.get({ email: 'customer@example.com', }); // Create customer portal link const portal = await creem.customers.createPortal({ customerId: 'cust_abc123', }); console.log(portal.customerPortalLink); // Redirect user to portal ``` ### Subscriptions ```ts theme={null} // Get a subscription const subscription = await creem.subscriptions.get({ subscriptionId: 'sub_abc123', }); // Cancel a subscription const canceledSubscription = await creem.subscriptions.cancel({ subscriptionId: 'sub_abc123', }); // Update a subscription (change units/seats) const updated = await creem.subscriptions.update({ subscriptionId: 'sub_abc123', items: [ { id: 'item_abc123', // Subscription item ID units: 5, // Update to 5 seats }, ], updateBehavior: 'proration-charge-immediately', }); // Upgrade a subscription to a different product const upgraded = await creem.subscriptions.upgrade({ subscriptionId: 'sub_abc123', productId: 'prod_premium', // New product ID updateBehavior: 'proration-charge-immediately', }); ``` **Update Behavior Options:** - `proration-charge-immediately`: Calculate proration and charge immediately - `proration-charge`: Calculate proration and charge at next billing cycle - `proration-none`: No proration, just switch the plan ### Licenses ```ts theme={null} // Activate a license const license = await creem.licenses.activate({ key: 'license_key_here', instanceName: 'Production Server', }); console.log(license.instance?.id); // Use this instance ID for validation // Validate a license const validatedLicense = await creem.licenses.validate({ key: 'license_key_here', instanceId: 'inst_abc123', }); console.log(validatedLicense.status); // "active" | "inactive" | "expired" | "disabled" // Deactivate a license const deactivatedLicense = await creem.licenses.deactivate({ key: 'license_key_here', instanceId: 'inst_abc123', }); ``` ### Discounts ```ts theme={null} // Create a discount code const discount = await creem.discounts.create({ name: 'Summer Sale 2024', code: 'SUMMER2024', // Optional: Auto-generated if not provided type: 'percentage', percentage: 20, // 20% off duration: 'forever', // "forever" | "once" | "repeating" maxRedemptions: 100, }); // Retrieve a discount by ID const discount = await creem.discounts.get({ discountId: 'disc_xxxxx', }); // Retrieve a discount by code const discountByCode = await creem.discounts.get({ discountCode: 'SUMMER2024', }); // Delete a discount await creem.discounts.delete({ discountId: 'disc_xxxxx', }); ``` ### Transactions ```ts theme={null} // Get a transaction const transaction = await creem.transactions.get({ transactionId: 'txn_xxxxx', }); // List transactions const transactions = await creem.transactions.list({ customerId: 'cust_xxxxx', // Optional: filter by customer page: 1, limit: 50, }); ``` *** ## Webhooks Handle Creem webhook events in your application. The SDK provides automatic signature verification and type-safe event handlers. ### Basic Webhook Setup ```ts theme={null} import { createCreem } from 'creem_io'; const creem = createCreem({ apiKey: process.env.CREEM_API_KEY!, webhookSecret: process.env.CREEM_WEBHOOK_SECRET!, }); // In your webhook endpoint app.post('/webhook', async (req, res) => { try { await creem.webhooks.handleEvents( req.body, // raw body as string req.headers['creem-signature'], { onCheckoutCompleted: async (data) => { console.log('Checkout completed:', data.customer?.email); }, onGrantAccess: async (context) => { // Grant user access when subscription is active/trialing/paid const userId = context.metadata?.userId; await grantUserAccess(userId); }, onRevokeAccess: async (context) => { // Revoke access when subscription is paused/expired const userId = context.metadata?.userId; await revokeUserAccess(userId); }, } ); res.status(200).send('OK'); } catch (error) { console.error('Webhook error:', error); res.status(400).send('Invalid signature'); } }); ``` ### Access Management Callbacks The `onGrantAccess` and `onRevokeAccess` callbacks simplify subscription access management: ```ts theme={null} onGrantAccess: async ({ reason, customer, product, metadata }) => { // Called for: subscription.active, subscription.trialing, subscription.paid const userId = metadata?.userId as string; await db.user.update({ where: { id: userId }, data: { subscriptionActive: true }, }); console.log(`Granted ${reason} to ${customer.email}`); }, onRevokeAccess: async ({ reason, customer, product, metadata }) => { // Called for: subscription.paused, subscription.expired const userId = metadata?.userId as string; await db.user.update({ where: { id: userId }, data: { subscriptionActive: false }, }); console.log(`Revoked access (${reason}) from ${customer.email}`); }, ``` ### All Available Webhook Events ```ts theme={null} await creem.webhooks.handleEvents(body, signature, { // Checkout events onCheckoutCompleted: async (data) => {}, // Access management (simplified) onGrantAccess: async (context) => {}, onRevokeAccess: async (context) => {}, // Individual subscription events onSubscriptionActive: async (data) => {}, onSubscriptionTrialing: async (data) => {}, onSubscriptionCanceled: async (data) => {}, onSubscriptionPaid: async (data) => {}, onSubscriptionExpired: async (data) => {}, onSubscriptionUnpaid: async (data) => {}, onSubscriptionPastDue: async (data) => {}, onSubscriptionPaused: async (data) => {}, onSubscriptionUpdate: async (data) => {}, // Other events onRefundCreated: async (data) => {}, onDisputeCreated: async (data) => {}, }); ``` ### Framework-Specific Examples ```ts theme={null} import { NextRequest } from "next/server"; import { createCreem } from "creem_io"; const creem = createCreem({ apiKey: process.env.CREEM_API_KEY!, webhookSecret: process.env.CREEM_WEBHOOK_SECRET!, }); export async function POST(req: NextRequest) { try { const body = await req.text(); const signature = req.headers.get("creem-signature")!; await creem.webhooks.handleEvents(body, signature, { onCheckoutCompleted: async (data) => { // Handle checkout completion }, onGrantAccess: async (context) => { // Grant access to user }, }); return new Response("OK", { status: 200 }); } catch (error) { return new Response("Invalid signature", { status: 400 }); } } ``` ```ts theme={null} import express from "express"; app.post( "/webhook", express.raw({ type: "application/json" }), async (req, res) => { try { await creem.webhooks.handleEvents( req.body, req.headers["creem-signature"], { onCheckoutCompleted: async (data) => { // Handle checkout }, } ); res.status(200).send("OK"); } catch (error) { res.status(400).send("Invalid signature"); } } ); ``` ```ts theme={null} fastify.post("/webhook", async (request, reply) => { try { await creem.webhooks.handleEvents( request.rawBody, request.headers["creem-signature"], { onCheckoutCompleted: async (data) => { // Handle checkout }, } ); reply.code(200).send("OK"); } catch (error) { reply.code(400).send("Invalid signature"); } }); ``` ```ts theme={null} app.post("/webhook", async (c) => { try { const body = await c.req.text(); const signature = c.req.header("creem-signature"); await creem.webhooks.handleEvents(body, signature, { onCheckoutCompleted: async (data) => { // Handle checkout }, }); return c.text("OK"); } catch (error) { return c.text("Invalid signature", 400); } }); ``` *** ## TypeScript Support The SDK is written in TypeScript and provides comprehensive type definitions: ```ts theme={null} import type { Checkout, Customer, Product, Subscription, Transaction, License, Discount, WebhookOptions, CheckoutCompletedEvent, SubscriptionEvent, GrantAccessContext, RevokeAccessContext, } from "creem_io"; ``` All API responses are fully typed, and the SDK automatically converts snake\_case to camelCase for better TypeScript/JavaScript experience. *** ## Error Handling The SDK throws errors when API calls fail. Always wrap SDK calls in try-catch blocks: ```ts theme={null} try { const product = await creem.products.get({ productId: 'prod_xxxxx', }); } catch (error) { console.error('Failed to retrieve product:', error); // Handle error appropriately } ``` *** ## References * [Creem SDK on GitHub](https://github.com/armitage-labs/creem_io) * [Creem API Documentation](https://docs.creem.io/api-reference/introduction) * [Creem Dashboard](https://creem.io/dashboard) * [Webhook Setup Guide](https://docs.creem.io/code/webhooks) *** > For feedback or issues, open a PR or issue on the [Creem SDK GitHub](https://github.com/armitage-labs/creem_io). # Webhooks Source: https://docs.creem.io/code/webhooks Creem webhooks guide: receive real-time payment notifications, handle subscription lifecycle events, and verify webhook signatures securely. ## What is a webhook? Creem uses webhooks to push real-time notifications to you about your payments and subscriptions. All webhooks use HTTPS and deliver a JSON payload that can be used by your application. You can use webhook feeds to do things like: * Automatically enable access to a user after a successful payment * Automatically remove access to a user after a canceled subscription * Confirm that a payment has been received by the same customer that initiated it. In case webhooks are not successfully received by your endpoint, Creem automatically retries to send the request with a progressive backoff period of 30 seconds, 1 minute, 5 minutes and 1 hour. You can also resend webhook events manually from your Merchant dashboard under [Developers section](https://creem.io/dashboard/developers). ## Steps to receive a webhook You can start receiving real-time events in your app using the steps: * Create a local endpoint to receive requests * Register your development webhook endpoint on the Developers tab of the Creem dashboard * Test that your webhook endpoint is working properly using the test environment * Deploy your webhook endpoint to production * Register your production webhook endpoint on Creem live dashboard On Next.js projects, the @creem\_io/nextjs adapter exports a `Webhook` helper that verifies signatures and surfaces typed lifecycle callbacks. Use it as your default implementation before falling back to manual parsing. ### 1. Create a local endpoint to receive requests In your local application, create a new route that can accept POST requests. ```ts Next.js theme={null} // app/api/webhook/creem/route.ts import { Webhook } from '@creem_io/nextjs'; export const POST = Webhook({ webhookSecret: process.env.CREEM_WEBHOOK_SECRET!, onCheckoutCompleted: async ({ customer, product }) => { console.log(`${customer.email} purchased ${product.name}`); }, onGrantAccess: async ({ customer, metadata }) => { const userId = metadata?.referenceId as string; await grantAccess(userId, customer.email); }, onRevokeAccess: async ({ customer, metadata }) => { const userId = metadata?.referenceId as string; await revokeAccess(userId, customer.email); }, }); ``` ```ts Node.js theme={null} import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { if (req.method !== 'POST') { return res.status(405).end(); } const payload = req.body; console.log(payload); res.status(200).end(); } ``` On receiving an event, you should respond with an HTTP 200 OK to signal to Creem that the event was successfully delivered. ### 2. Register your development webhook endpoint Register your publicly accessible HTTPS URL in the Creem dashboard. You can create a tunnel to your localhost server using a tool like ngrok. For example: [https://8733-191-204-177-89.sa.ngrok.io/api/webhooks](https://8733-191-204-177-89.sa.ngrok.io/api/webhooks) ### 3. Test that your webhook endpoint is working properly Create a few test payments to check that your webhook endpoint is receiving the events. ### 4. Deploy your webhook endpoint After you're done testing, deploy your webhook endpoint to production. ### 5. Register your production webhook endpoint Once your webhook endpoint is deployed to production, you can register it in the Creem dashboard. ## Network Configuration Creem does not provide static source IP addresses for outbound webhooks in either Test Mode or production. If your firewall or WAF protects the webhook endpoint, do not rely on source-IP allowlists as the authentication mechanism. Keep the endpoint reachable over HTTPS and verify every request with the `creem-signature` header. Bot protection and WAF products can challenge webhook deliveries because webhooks are automated server-to-server requests. If this happens, add a route-level exception or skip rule for your webhook endpoint. On Cloudflare specifically, Bot Fight Mode cannot be skipped with custom rules; disable it or use Super Bot Fight Mode or Bot Management with a skip rule. ## Webhook Signatures ### How to verify Creem signature? Creem signature is sent in the `creem-signature` header of the webhook request. The signature is generated using the HMAC-SHA256 algorithm with the webhook secret as the key, and the request payload as the message. ```json theme={null} { 'creem-signature': 'dd7bdd2cf1f6bac6e171c6c508c157b7cd3cc1fd196394277fb59ba0bdd9b87b' } ``` Use the TypeScript SDK to verify the signature before processing the event payload. You can find your webhook secret on the Developers>Webhook page. ```typescript theme={null} import { verifyWebhookSignature } from 'creem/webhooks'; await verifyWebhookSignature(rawBody, request.headers, { secret: process.env.CREEM_WEBHOOK_SECRET!, }); ``` If you are not using the SDK, generate the signature with HMAC-SHA256 using the raw request body and compare it with the `creem-signature` header. ```typescript theme={null} import * as crypto from 'crypto'; generateSignature(payload: string, secret: string): string { const computedSignature = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return computedSignature; } ``` In the code snippet above, the `payload` is the request body, and the `secret` is the webhook secret. Simply compare the generated Signature with the one received on the header to complete the verification process. ## Event Types List of supported event types and their payloads. ### checkout.completed A checkout session was completed, returning all the information about the payment and the order created. ```json theme={null} { "id": "evt_5WHHcZPv7VS0YUsberIuOz", "eventType": "checkout.completed", "created_at": 1728734325927, "object": { "id": "ch_4l0N34kxo16AhRKUHFUuXr", "object": "checkout", "request_id": "my-request-id", "order": { "id": "ord_4aDwWXjMLpes4Kj4XqNnUA", "customer": "cust_1OcIK1GEuVvXZwD19tjq2z", "product": "prod_d1AY2Sadk9YAvLI0pj97f", "amount": 1000, "currency": "EUR", "status": "paid", "type": "recurring", "created_at": "2024-10-12T11:58:33.097Z", "updated_at": "2024-10-12T11:58:33.097Z", "mode": "local" }, "product": { "id": "prod_d1AY2Sadk9YAvLI0pj97f", "name": "Monthly", "description": "Monthly", "image_url": null, "price": 1000, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-month", "status": "active", "tax_mode": "exclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2024-10-11T11:50:00.182Z", "updated_at": "2024-10-11T11:50:00.182Z", "mode": "local" }, "customer": { "id": "cust_1OcIK1GEuVvXZwD19tjq2z", "object": "customer", "email": "customer@emaildomain", "name": "Tester Test", "country": "NL", "created_at": "2024-10-11T09:16:48.557Z", "updated_at": "2024-10-11T09:16:48.557Z", "mode": "local" }, "subscription": { "id": "sub_6pC2lNB6joCRQIZ1aMrTpi", "object": "subscription", "product": "prod_d1AY2Sadk9YAvLI0pj97f", "customer": "cust_1OcIK1GEuVvXZwD19tjq2z", "collection_method": "charge_automatically", "status": "active", "canceled_at": null, "created_at": "2024-10-12T11:58:45.425Z", "updated_at": "2024-10-12T11:58:45.425Z", "metadata": { "custom_data": "mycustom data", "internal_customer_id": "internal_customer_id" }, "mode": "local" }, "custom_fields": [], "status": "completed", "metadata": { "custom_data": "mycustom data", "internal_customer_id": "internal_customer_id" }, "mode": "local" } } ``` ### subscription.active Received when a new subscription is created, the payment was successful and Creem collected the payment creating a new subscription object in your account. Use only for synchronization, we encourage using `subscription.paid` for activating access. ```json theme={null} { "id": "evt_6EptlmjazyGhEPiNQ5f4lz", "eventType": "subscription.active", "created_at": 1728734325927, "object": { "id": "sub_21lfZb67szyvMiXnm6SVi0", "object": "subscription", "product": { "id": "prod_AnVJ11ujp7x953ARpJvAF", "name": "My Product - Product 01", "description": "Test my product", "image_url": null, "price": 10000, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-month", "status": "active", "tax_mode": "inclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2024-09-16T16:12:09.813Z", "updated_at": "2024-09-16T16:12:09.813Z", "mode": "local" }, "customer": { "id": "cust_3biFPNt4Cz5YRDSdIqs7kc", "object": "customer", "email": "customer@emaildomain", "name": "Tester Test", "country": "SE", "created_at": "2024-09-16T16:13:39.265Z", "updated_at": "2024-09-16T16:13:39.265Z", "mode": "local" }, "collection_method": "charge_automatically", "status": "active", "canceled_at": "2024-09-16T19:40:41.984Z", "created_at": "2024-09-16T19:40:41.984Z", "updated_at": "2024-09-16T19:40:42.121Z", "mode": "local" } } ``` ### subscription.paid A subscription transaction was paid by the customer ```json theme={null} { "id": "evt_21mO1jWmU2QHe7u2oFV7y1", "eventType": "subscription.paid", "created_at": 1728734327355, "object": { "id": "sub_6pC2lNB6joCRQIZ1aMrTpi", "object": "subscription", "product": { "id": "prod_d1AY2Sadk9YAvLI0pj97f", "name": "Monthly", "description": "Monthly", "image_url": null, "price": 1000, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-month", "status": "active", "tax_mode": "exclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2024-10-11T11:50:00.182Z", "updated_at": "2024-10-11T11:50:00.182Z", "mode": "local" }, "customer": { "id": "cust_1OcIK1GEuVvXZwD19tjq2z", "object": "customer", "email": "customer@emaildomain", "name": "Tester Test", "country": "NL", "created_at": "2024-10-11T09:16:48.557Z", "updated_at": "2024-10-11T09:16:48.557Z", "mode": "local" }, "collection_method": "charge_automatically", "status": "active", "last_transaction_id": "tran_5yMaWzAl3jxuGJMCOrYWwk", "last_transaction_date": "2024-10-12T11:58:47.109Z", "next_transaction_date": "2024-11-12T11:58:38.000Z", "current_period_start_date": "2024-10-12T11:58:38.000Z", "current_period_end_date": "2024-11-12T11:58:38.000Z", "canceled_at": null, "created_at": "2024-10-12T11:58:45.425Z", "updated_at": "2024-10-12T11:58:45.425Z", "metadata": { "custom_data": "mycustom data", "internal_customer_id": "internal_customer_id" }, "mode": "local" } } ``` ### subscription.canceled The subscription was canceled by the merchant or by the customer. ```json theme={null} { "id": "evt_2iGTc600qGW6FBzloh2Nr7", "eventType": "subscription.canceled", "created_at": 1728734337932, "object": { "id": "sub_6pC2lNB6joCRQIZ1aMrTpi", "object": "subscription", "product": { "id": "prod_d1AY2Sadk9YAvLI0pj97f", "name": "Monthly", "description": "Monthly", "image_url": null, "price": 1000, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-month", "status": "active", "tax_mode": "exclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2024-10-11T11:50:00.182Z", "updated_at": "2024-10-11T11:50:00.182Z", "mode": "local" }, "customer": { "id": "cust_1OcIK1GEuVvXZwD19tjq2z", "object": "customer", "email": "customer@emaildomain", "name": "Tester Test", "country": "NL", "created_at": "2024-10-11T09:16:48.557Z", "updated_at": "2024-10-11T09:16:48.557Z", "mode": "local" }, "collection_method": "charge_automatically", "status": "canceled", "last_transaction_id": "tran_5yMaWzAl3jxuGJMCOrYWwk", "last_transaction_date": "2024-10-12T11:58:47.109Z", "current_period_start_date": "2024-10-12T11:58:38.000Z", "current_period_end_date": "2024-11-12T11:58:38.000Z", "canceled_at": "2024-10-12T11:58:57.813Z", "created_at": "2024-10-12T11:58:45.425Z", "updated_at": "2024-10-12T11:58:57.827Z", "metadata": { "custom_data": "mycustom data", "internal_customer_id": "internal_customer_id" }, "mode": "local" } } ``` ### subscription.scheduled\_cancel The subscription was scheduled for cancellation at the end of the current billing period. The subscription remains active until `current_period_end_date`, after which it transitions to `canceled`. This event is triggered when a customer or merchant requests cancellation but opts to cancel at the end of the period rather than immediately. You can use this event to notify the customer about the upcoming cancellation or to offer retention incentives. The subscription can be resumed before the period ends using the [Resume Subscription](/api-reference/endpoint/subscriptions/resume-subscription) endpoint, which will change the status back to `active` and prevent the cancellation. ```json theme={null} { "id": "evt_4RfTc700qGW6FBzloh3Ms8", "eventType": "subscription.scheduled_cancel", "created_at": 1728734337932, "object": { "id": "sub_6pC2lNB6joCRQIZ1aMrTpi", "object": "subscription", "product": { "id": "prod_d1AY2Sadk9YAvLI0pj97f", "name": "Monthly", "description": "Monthly", "image_url": null, "price": 1000, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-month", "status": "active", "tax_mode": "exclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2024-10-11T11:50:00.182Z", "updated_at": "2024-10-11T11:50:00.182Z", "mode": "local" }, "customer": { "id": "cust_1OcIK1GEuVvXZwD19tjq2z", "object": "customer", "email": "customer@emaildomain", "name": "Tester Test", "country": "NL", "created_at": "2024-10-11T09:16:48.557Z", "updated_at": "2024-10-11T09:16:48.557Z", "mode": "local" }, "collection_method": "charge_automatically", "status": "scheduled_cancel", "last_transaction_id": "tran_5yMaWzAl3jxuGJMCOrYWwk", "last_transaction_date": "2024-10-12T11:58:47.109Z", "current_period_start_date": "2024-10-12T11:58:38.000Z", "current_period_end_date": "2024-11-12T11:58:38.000Z", "canceled_at": null, "created_at": "2024-10-12T11:58:45.425Z", "updated_at": "2024-10-12T11:59:15.827Z", "metadata": { "custom_data": "mycustom data", "internal_customer_id": "internal_customer_id" }, "mode": "local" } } ``` ### subscription.past\_due The subscription payment has failed and the subscription is now past due. This occurs when a payment attempt fails (e.g., card declined, insufficient funds). Creem will automatically retry the payment according to the retry schedule. If a retry succeeds, the subscription transitions back to `active`. If all retries are exhausted, the subscription is canceled. ```json theme={null} { "id": "evt_7HkTd800rHX7GCampi4Nt9", "eventType": "subscription.past_due", "created_at": 1728734337932, "object": { "id": "sub_6pC2lNB6joCRQIZ1aMrTpi", "object": "subscription", "product": { "id": "prod_d1AY2Sadk9YAvLI0pj97f", "name": "Monthly", "description": "Monthly", "image_url": null, "price": 1000, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-month", "status": "active", "tax_mode": "exclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2024-10-11T11:50:00.182Z", "updated_at": "2024-10-11T11:50:00.182Z", "mode": "local" }, "customer": { "id": "cust_1OcIK1GEuVvXZwD19tjq2z", "object": "customer", "email": "customer@emaildomain", "name": "Tester Test", "country": "NL", "created_at": "2024-10-11T09:16:48.557Z", "updated_at": "2024-10-11T09:16:48.557Z", "mode": "local" }, "collection_method": "charge_automatically", "status": "past_due", "last_transaction_id": "tran_5yMaWzAl3jxuGJMCOrYWwk", "last_transaction_date": "2024-10-12T11:58:47.109Z", "current_period_start_date": "2024-10-12T11:58:38.000Z", "current_period_end_date": "2024-11-12T11:58:38.000Z", "canceled_at": null, "created_at": "2024-10-12T11:58:45.425Z", "updated_at": "2024-11-12T12:05:30.827Z", "metadata": { "custom_data": "mycustom data", "internal_customer_id": "internal_customer_id" }, "mode": "local" } } ``` ### subscription.expired The subscription was expired, given that the `current_end_period` has been reached without a new payment. Payment retries can happen at this stage, and the subscription status will be terminal only when status is changed to `canceled`. ```json theme={null} { "id": "evt_V5CxhipUu10BYonO2Vshb", "eventType": "subscription.expired", "created_at": 1734463872058, "object": { "id": "sub_7FgHvrOMC28tG5DEemoCli", "object": "subscription", "product": { "id": "prod_3ELsC3Lt97orn81SOdgQI3", "name": "Subs", "description": "Subs", "image_url": null, "price": 1200, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-year", "status": "active", "tax_mode": "exclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2024-12-11T17:33:32.186Z", "updated_at": "2024-12-11T17:33:32.186Z", "mode": "local" }, "customer": { "id": "cust_3y4k2CELGsw7n9Eeeiw2hm", "object": "customer", "email": "customer@emaildomain", "name": "Alec Erasmus", "country": "NL", "created_at": "2024-12-09T16:09:20.709Z", "updated_at": "2024-12-09T16:09:20.709Z", "mode": "local" }, "collection_method": "charge_automatically", "status": "active", "last_transaction_id": "tran_6ZeTvMqMkGdAIIjw5aAcnh", "last_transaction_date": "2024-12-16T12:40:12.658Z", "next_transaction_date": "2025-12-16T12:39:47.000Z", "current_period_start_date": "2024-12-16T12:39:47.000Z", "current_period_end_date": "2024-12-16T12:39:47.000Z", "canceled_at": null, "created_at": "2024-12-16T12:40:05.058Z", "updated_at": "2024-12-16T12:40:05.058Z", "mode": "local" } } ``` ### refund.created A refund was created by the merchant ```json theme={null} { "id": "evt_61eTsJHUgInFw2BQKhTiPV", "eventType": "refund.created", "created_at": 1728734351631, "object": { "id": "ref_3DB9NQFvk18TJwSqd0N6bd", "object": "refund", "status": "succeeded", "refund_amount": 1210, "refund_currency": "EUR", "reason": "requested_by_customer", "transaction": { "id": "tran_5yMaWzAl3jxuGJMCOrYWwk", "object": "transaction", "amount": 1000, "amount_paid": 1210, "currency": "EUR", "type": "invoice", "tax_country": "NL", "tax_amount": 210, "status": "refunded", "refunded_amount": 1210, "order": "ord_4aDwWXjMLpes4Kj4XqNnUA", "subscription": "sub_6pC2lNB6joCRQIZ1aMrTpi", "description": "Subscription payment", "period_start": 1728734318000, "period_end": 1731412718000, "created_at": 1728734327109, "mode": "local" }, "subscription": { "id": "sub_6pC2lNB6joCRQIZ1aMrTpi", "object": "subscription", "product": "prod_d1AY2Sadk9YAvLI0pj97f", "customer": "cust_1OcIK1GEuVvXZwD19tjq2z", "collection_method": "charge_automatically", "status": "canceled", "last_transaction_id": "tran_5yMaWzAl3jxuGJMCOrYWwk", "last_transaction_date": "2024-10-12T11:58:47.109Z", "current_period_start_date": "2024-10-12T11:58:38.000Z", "current_period_end_date": "2024-11-12T11:58:38.000Z", "canceled_at": "2024-10-12T11:58:57.813Z", "created_at": "2024-10-12T11:58:45.425Z", "updated_at": "2024-10-12T11:58:57.827Z", "metadata": { "custom_data": "mycustom data", "internal_customer_id": "internal_customer_id" }, "mode": "local" }, "checkout": { "id": "ch_4l0N34kxo16AhRKUHFUuXr", "object": "checkout", "request_id": "my-request-id", "custom_fields": [], "status": "completed", "metadata": { "custom_data": "mycustom data", "internal_customer_id": "internal_customer_id" }, "mode": "local" }, "order": { "id": "ord_4aDwWXjMLpes4Kj4XqNnUA", "customer": "cust_1OcIK1GEuVvXZwD19tjq2z", "product": "prod_d1AY2Sadk9YAvLI0pj97f", "amount": 1000, "currency": "EUR", "status": "paid", "type": "recurring", "created_at": "2024-10-12T11:58:33.097Z", "updated_at": "2024-10-12T11:58:33.097Z", "mode": "local" }, "customer": { "id": "cust_1OcIK1GEuVvXZwD19tjq2z", "object": "customer", "email": "customer@emaildomain", "name": "Tester Test", "country": "NL", "created_at": "2024-10-11T09:16:48.557Z", "updated_at": "2024-10-11T09:16:48.557Z", "mode": "local" }, "created_at": 1728734351525, "mode": "local" } } ``` ### dispute.created A dispute was created by the customer ```json theme={null} { "id": "evt_6mfLDL7P0NYwYQqCrICvDH", "eventType": "dispute.created", "created_at": 1750941264812, "object": { "id": "disp_6vSsOdTANP5PhOzuDlUuXE", "object": "dispute", "amount": 1331, "currency": "EUR", "transaction": { "id": "tran_4Dk8CxWFdceRUQgMFhCCXX", "object": "transaction", "amount": 1100, "amount_paid": 1331, "currency": "EUR", "type": "invoice", "tax_country": "NL", "tax_amount": 231, "status": "chargeback", "refunded_amount": 1331, "order": "ord_57bf8042UmG8fFypxZrfnj", "subscription": "sub_5sD6zM482uwOaEoyEUDDJs", "customer": "cust_OJPZd2GMxgo1MGPNXXBSN", "description": "Subscription payment", "period_start": 1750941201000, "period_end": 1753533201000, "created_at": 1750941205659, "mode": "sandbox" }, "subscription": { "id": "sub_5sD6zM482uwOaEoyEUDDJs", "object": "subscription", "product": "prod_3EFtQRQ9SNIizK3xwfxZHu", "customer": "cust_OJPZd2GMxgo1MGPNXXBSN", "collection_method": "charge_automatically", "status": "active", "current_period_start_date": "2025-06-26T12:33:21.000Z", "current_period_end_date": "2025-07-26T12:33:21.000Z", "canceled_at": null, "created_at": "2025-06-26T12:33:23.589Z", "updated_at": "2025-06-26T12:33:26.102Z", "mode": "sandbox" }, "checkout": { "id": "ch_1bJMvqGGzHIftf4ewLXJeq", "object": "checkout", "product": "prod_3EFtQRQ9SNIizK3xwfxZHu", "units": 1, "custom_fields": [ { "key": "testing", "text": { "value": "asdfasdf", "max_length": 255 }, "type": "text", "label": "Testing", "optional": false } ], "status": "completed", "mode": "sandbox" }, "order": { "object": "order", "id": "ord_57bf8042UmG8fFypxZrfnj", "customer": "cust_OJPZd2GMxgo1MGPNXXBSN", "product": "prod_3EFtQRQ9SNIizK3xwfxZHu", "amount": 1100, "currency": "EUR", "sub_total": 1100, "tax_amount": 231, "amount_due": 1331, "amount_paid": 1331, "status": "paid", "type": "recurring", "transaction": "tran_4Dk8CxWFdceRUQgMFhCCXX", "created_at": "2025-06-26T12:32:41.395Z", "updated_at": "2025-06-26T12:32:41.395Z", "mode": "sandbox" }, "customer": { "id": "cust_OJPZd2GMxgo1MGPNXXBSN", "object": "customer", "email": "customer@emaildomain", "name": "Alec Erasmus", "country": "NL", "created_at": "2025-02-05T10:11:01.146Z", "updated_at": "2025-02-05T10:11:01.146Z", "mode": "sandbox" }, "created_at": 1750941264728, "mode": "local" } } ``` ### subscription.update A subscription object was updated ```json theme={null} { "id": "evt_5pJMUuvqaqvttFVUvtpY32", "eventType": "subscription.update", "created_at": 1737890536421, "object": { "id": "sub_2qAuJgWmXhXHAuef9k4Kur", "object": "subscription", "product": { "id": "prod_1dP15yoyogQe2seEt1Evf3", "name": "Monthly Sub", "description": "Test Test", "image_url": null, "price": 1000, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-month", "status": "active", "tax_mode": "exclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2025-01-26T11:17:16.082Z", "updated_at": "2025-01-26T11:17:16.082Z", "mode": "local" }, "customer": { "id": "cust_2fQZKKUZqtNhH2oDWevQkW", "object": "customer", "email": "customer@emaildomain", "name": "John Doe", "country": "NL", "created_at": "2025-01-26T11:18:24.071Z", "updated_at": "2025-01-26T11:18:24.071Z", "mode": "local" }, "items": [ { "object": "subscription_item", "id": "sitem_3QWlqRbAat2eBRakAxFtt9", "product_id": "prod_5jnudVkLGZWF4AqMFBs5t5", "price_id": "pprice_4W0mJK6uGiQzHbVhfaFTl1", "units": 1, "created_at": "2025-01-26T11:20:40.296Z", "updated_at": "2025-01-26T11:20:40.296Z", "mode": "local" } ], "collection_method": "charge_automatically", "status": "active", "current_period_start_date": "2025-01-26T11:20:36.000Z", "current_period_end_date": "2025-02-26T11:20:36.000Z", "canceled_at": null, "created_at": "2025-01-26T11:20:40.292Z", "updated_at": "2025-01-26T11:22:16.388Z", "mode": "local" } } ``` ### subscription.trialing A subscription started a trial period ```json theme={null} { "id": "evt_2ciAM8ABYtj0pVueeJPxUZ", "eventType": "subscription.trialing", "created_at": 1739963911073, "object": { "id": "sub_dxiauR8zZOwULx5QM70wJ", "object": "subscription", "product": { "id": "prod_3kpf0ZdpcfsSCQ3kDiwg9m", "name": "trail", "description": "asdfasf", "image_url": null, "price": 1100, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-month", "status": "active", "tax_mode": "exclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2025-02-19T11:18:07.570Z", "updated_at": "2025-02-19T11:18:07.570Z", "mode": "test" }, "customer": { "id": "cust_4fpU8kYkQmI1XKBwU2qeME", "object": "customer", "email": "customer@emaildomain", "name": "Alec Erasmus", "country": "NL", "created_at": "2024-11-07T23:21:11.763Z", "updated_at": "2024-11-07T23:21:11.763Z", "mode": "test" }, "items": [ { "object": "subscription_item", "id": "sitem_1xbHCmIM61DHGRBCFn0W1L", "product_id": "prod_3kpf0ZdpcfsSCQ3kDiwg9m", "price_id": "pprice_517h9CebmM3P079bGAXHnE", "units": 1, "created_at": "2025-02-19T11:18:30.690Z", "updated_at": "2025-02-19T11:18:30.690Z", "mode": "test" } ], "collection_method": "charge_automatically", "status": "trialing", "current_period_start_date": "2025-02-19T11:18:25.000Z", "current_period_end_date": "2025-02-26T11:18:25.000Z", "canceled_at": null, "created_at": "2025-02-19T11:18:30.674Z", "updated_at": "2025-02-19T11:18:30.674Z", "mode": "test" } } ``` ### subscription.paused A checkout session was completed, returning all the information about the payment and the order created. ```json theme={null} { "id": "evt_5veN2cn5N9Grz8u7w3yJuL", "eventType": "subscription.paused", "created_at": 1754041946898, "object": { "id": "sub_3ZT1iYMeDBpiUpRTqq4veE", "object": "subscription", "product": { "id": "prod_sYwbyE1tPbsqbLu6S0bsR", "object": "product", "name": "Prod", "description": "My Product Description", "price": 2000, "currency": "EUR", "billing_type": "recurring", "billing_period": "every-month", "status": "active", "tax_mode": "exclusive", "tax_category": "saas", "default_success_url": "", "created_at": "2025-08-01T09:51:26.277Z", "updated_at": "2025-08-01T09:51:26.277Z", "mode": "test" }, "customer": { "id": "cust_4fpU8kYkQmI1XKBwU2qeME", "object": "customer", "email": "customer@emaildomain", "name": "Test Test", "country": "NL", "created_at": "2024-11-07T23:21:11.763Z", "updated_at": "2024-11-07T23:21:11.763Z", "mode": "test" }, "items": [ { "object": "subscription_item", "id": "sitem_1ZIqcUuxKKDTj5WZPNsN6C", "product_id": "prod_sYwbyE1tPbsqbLu6S0bsR", "price_id": "pprice_1uM3Pi1vJJ3xkhwQuZiM42", "units": 1, "created_at": "2025-08-01T09:51:50.497Z", "updated_at": "2025-08-01T09:51:50.497Z", "mode": "test" } ], "collection_method": "charge_automatically", "status": "paused", "current_period_start_date": "2025-08-01T09:51:47.000Z", "current_period_end_date": "2025-09-01T09:51:47.000Z", "canceled_at": null, "created_at": "2025-08-01T09:51:50.488Z", "updated_at": "2025-08-01T09:52:26.822Z", "mode": "test" } } ``` # Code Blocks Source: https://docs.creem.io/essentials/code Display inline code and code blocks ## Basic ### Inline Code To denote a `word` or `phrase` as code, enclose it in backticks (\`). ``` To denote a `word` or `phrase` as code, enclose it in backticks (`). ``` ### Code Block Use [fenced code blocks](https://www.markdownguide.org/extended-syntax/#fenced-code-blocks) by enclosing code in three backticks and follow the leading ticks with the programming language of your snippet to get syntax highlighting. Optionally, you can also write the name of your code after the programming language. ```java HelloWorld.java theme={null} class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } } ``` ````md theme={null} ```java HelloWorld.java class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } } ``` ```` # Images and Embeds Source: https://docs.creem.io/essentials/images Add image, video, and other HTML elements ## Image ### Using Markdown The [markdown syntax](https://www.markdownguide.org/basic-syntax/#images) lets you add images using the following code ```md theme={null} ![title](/path/image.jpg) ``` Note that the image file size must be less than 5MB. Otherwise, we recommend hosting on a service like [Cloudinary](https://cloudinary.com/) or [S3](https://aws.amazon.com/s3/). You can then use that URL and embed. ### Using Embeds To get more customizability with images, you can also use [embeds](/writing-content/embed) to add images ```html theme={null} ``` ## Embeds and HTML elements ``` # Markdown Syntax Source: https://docs.creem.io/essentials/markdown Text, title, and styling in standard markdown ## Titles Best used for section headers. ```md theme={null} ## Titles ``` ### Subtitles Best use to subsection headers. ```md theme={null} ### Subtitles ``` Each **title** and **subtitle** creates an anchor and also shows up on the table of contents on the right. ## Text Formatting We support most markdown formatting. Simply add `**`, `_`, or `~` around text to format it. | Style | How to write it | Result | | ------------- | ----------------- | ----------------- | | Bold | `**bold**` | **bold** | | Italic | `_italic_` | *italic* | | Strikethrough | `~strikethrough~` | ~~strikethrough~~ | You can combine these. For example, write `**_bold and italic_**` to get ***bold and italic*** text. You need to use HTML to write superscript and subscript text. That is, add `` or `` around your text. | Text Size | How to write it | Result | | ----------- | ------------------------ | ---------------------- | | Superscript | `superscript` | superscript | | Subscript | `subscript` | subscript | ## Linking to Pages You can add a link by wrapping text in `[]()`. You would write `[link to google](https://google.com)` to [link to google](https://google.com). Links to pages in your docs need to be root-relative. Basically, you should include the entire folder path. For example, `[link to text](/writing-content/text)` links to the page "Text" in our components section. Relative links like `[link to text](../text)` will open slower because we cannot optimize them as easily. ## Blockquotes ### Singleline To create a blockquote, add a `>` in front of a paragraph. > Dorothy followed her through many of the beautiful rooms in her castle. ```md theme={null} > Dorothy followed her through many of the beautiful rooms in her castle. ``` ### Multiline > Dorothy followed her through many of the beautiful rooms in her castle. > > The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. ```md theme={null} > Dorothy followed her through many of the beautiful rooms in her castle. > > The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. ``` ### LaTeX Mintlify supports [LaTeX](https://www.latex-project.org) through the Latex component. 8 x (vk x H1 - H2) = (0,1) ```md theme={null} 8 x (vk x H1 - H2) = (0,1) ``` # Navigation Source: https://docs.creem.io/essentials/navigation The navigation field in mint.json defines the pages that go in the navigation menu The navigation menu is the list of links on every website. You will likely update `mint.json` every time you add a new page. Pages do not show up automatically. ## Navigation syntax Our navigation syntax is recursive which means you can make nested navigation groups. You don't need to include `.mdx` in page names. ```json Regular Navigation theme={null} "navigation": [ { "group": "Getting Started", "pages": ["quickstart"] } ] ``` ```json Nested Navigation theme={null} "navigation": [ { "group": "Getting Started", "pages": [ "quickstart", { "group": "Nested Reference Pages", "pages": ["nested-reference-page"] } ] } ] ``` ## Folders Simply put your MDX files in folders and update the paths in `mint.json`. For example, to have a page at `https://yoursite.com/your-folder/your-page` you would make a folder called `your-folder` containing an MDX file called `your-page.mdx`. You cannot use `api` for the name of a folder unless you nest it inside another folder. Mintlify uses Next.js which reserves the top-level `api` folder for internal server calls. A folder name such as `api-reference` would be accepted. ```json Navigation With Folder theme={null} "navigation": [ { "group": "Group Name", "pages": ["your-folder/your-page"] } ] ``` ## Hidden Pages MDX files not included in `mint.json` will not show up in the sidebar but are accessible through the search bar and by linking directly to them. # Reusable Snippets Source: https://docs.creem.io/essentials/reusable-snippets Reusable, custom snippets to keep content in sync One of the core principles of software development is DRY (Don't Repeat Yourself). This is a principle that apply to documentation as well. If you find yourself repeating the same content in multiple places, you should consider creating a custom snippet to keep your content in sync. ## Creating a custom snippet **Pre-condition**: You must create your snippet file in the `snippets` directory. Any page in the `snippets` directory will be treated as a snippet and will not be rendered into a standalone page. If you want to create a standalone page from the snippet, import the snippet into another file and call it as a component. ### Default export 1. Add content to your snippet file that you want to re-use across multiple locations. Optionally, you can add variables that can be filled in via props when you import the snippet. ```mdx snippets/my-snippet.mdx theme={null} Hello world! This is my content I want to reuse across pages. My keyword of the day is {word}. ``` The content that you want to reuse must be inside the `snippets` directory in order for the import to work. 2. Import the snippet into your destination file. ```mdx destination-file.mdx theme={null} --- title: My title description: My Description --- import MySnippet from '/snippets/path/to/my-snippet.mdx'; ## Header Lorem impsum dolor sit amet. ``` ### Reusable variables 1. Export a variable from your snippet file: ```mdx snippets/path/to/custom-variables.mdx theme={null} export const myName = 'my name'; export const myObject = { fruit: 'strawberries' }; ``` 2. Import the snippet from your destination file and use the variable: ```mdx destination-file.mdx theme={null} --- title: My title description: My Description --- import { myName, myObject } from '/snippets/path/to/custom-variables.mdx'; Hello, my name is {myName} and I like {myObject.fruit}. ``` ### Reusable components 1. Inside your snippet file, create a component that takes in props by exporting your component in the form of an arrow function. ```mdx snippets/custom-component.mdx theme={null} export const MyComponent = ({ title }) => (

{title}

... snippet content ...

); ``` MDX does not compile inside the body of an arrow function. Stick to HTML syntax when you can or use a default export if you need to use MDX. 2. Import the snippet into your destination file and pass in the props ```mdx destination-file.mdx theme={null} --- title: My title description: My Description --- import { MyComponent } from '/snippets/custom-component.mdx'; Lorem ipsum dolor sit amet. ``` # Global Settings Source: https://docs.creem.io/essentials/settings Mintlify gives you complete control over the look and feel of your documentation using the mint.json file Every Mintlify site needs a `mint.json` file with the core configuration settings. Learn more about the [properties](#properties) below. ## Properties Name of your project. Used for the global title. Example: `mintlify` An array of groups with all the pages within that group The name of the group. Example: `Settings` The relative paths to the markdown files that will serve as pages. Example: `["customization", "page"]` Path to logo image or object with path to "light" and "dark" mode logo images Path to the logo in light mode Path to the logo in dark mode Where clicking on the logo links you to Path to the favicon image Hex color codes for your global theme The primary color. Used for most often for highlighted content, section headers, accents, in light mode The primary color for dark mode. Used for most often for highlighted content, section headers, accents, in dark mode The primary color for important buttons The color of the background in both light and dark mode The hex color code of the background in light mode The hex color code of the background in dark mode Array of `name`s and `url`s of links you want to include in the topbar The name of the button. Example: `Contact us` The url once you click on the button. Example: `https://mintlify.com/contact` Link shows a button. GitHub shows the repo information at the url provided including the number of GitHub stars. If `link`: What the button links to. If `github`: Link to the repository to load GitHub information from. Text inside the button. Only required if `type` is a `link`. Array of version names. Only use this if you want to show different versions of docs with a dropdown in the navigation bar. An array of the anchors, includes the `icon`, `color`, and `url`. The [Font Awesome](https://fontawesome.com/search?s=brands%2Cduotone) icon used to feature the anchor. Example: `comments` The name of the anchor label. Example: `Community` The start of the URL that marks what pages go in the anchor. Generally, this is the name of the folder you put your pages in. The hex color of the anchor icon background. Can also be a gradient if you pass an object with the properties `from` and `to` that are each a hex color. Used if you want to hide an anchor until the correct docs version is selected. Pass `true` if you want to hide the anchor until you directly link someone to docs inside it. One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" Override the default configurations for the top-most anchor. The name of the top-most anchor Font Awesome icon. One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" An array of navigational tabs. The name of the tab label. The start of the URL that marks what pages go in the tab. Generally, this is the name of the folder you put your pages in. Configuration for API settings. Learn more about API pages at [API Components](/api-playground/demo). The base url for all API endpoints. If `baseUrl` is an array, it will enable for multiple base url options that the user can toggle. The authentication strategy used for all API endpoints. The name of the authentication parameter used in the API playground. If method is `basic`, the format should be `[usernameName]:[passwordName]` The default value that's designed to be a prefix for the authentication input field. E.g. If an `inputPrefix` of `AuthKey` would inherit the default input result of the authentication field as `AuthKey`. Configurations for the API playground Whether the playground is showing, hidden, or only displaying the endpoint with no added user interactivity `simple` Learn more at the [playground guides](/api-playground/demo) Enabling this flag ensures that key ordering in OpenAPI pages matches the key ordering defined in the OpenAPI file. This behavior will soon be enabled by default, at which point this field will be deprecated. A string or an array of strings of URL(s) or relative path(s) pointing to your OpenAPI file. Examples: ```json Absolute theme={null} "openapi": "https://example.com/openapi.json" ``` ```json Relative theme={null} "openapi": "/openapi.json" ``` ```json Multiple theme={null} "openapi": ["https://example.com/openapi1.json", "/openapi2.json", "/openapi3.json"] ``` An object of social media accounts where the key:property pair represents the social media platform and the account url. Example: ```json theme={null} { "x": "https://x.com/mintlify", "website": "https://mintlify.com" } ``` One of the following values `website`, `facebook`, `x`, `discord`, `slack`, `github`, `linkedin`, `instagram`, `hacker-news` Example: `x` The URL to the social platform. Example: `https://x.com/mintlify` Configurations to enable feedback buttons Enables a button to allow users to suggest edits via pull requests Enables a button to allow users to raise an issue about the documentation Customize the dark mode toggle. Set if you always want to show light or dark mode for new users. When not set, we default to the same mode as the user's operating system. Set to true to hide the dark/light mode toggle. You can combine `isHidden` with `default` to force your docs to only use light or dark mode. For example: ```json Only Dark Mode theme={null} "modeToggle": { "default": "dark", "isHidden": true } ``` ```json Only Light Mode theme={null} "modeToggle": { "default": "light", "isHidden": true } ``` A background image to be displayed behind every page. See example with [Infisical](https://infisical.com/docs) and [FRPC](https://frpc.io). # Abandoned Cart Recovery Source: https://docs.creem.io/features/addons/abandoned-cart-recovery Automatically recover lost sales with abandoned cart email reminders. # Abandoned Cart Recovery with Creem Welcome to Creem's Abandoned Cart Recovery documentation! This feature helps you automatically re-engage potential customers who start the checkout process but don't complete their purchase, significantly boosting your conversion rates and recovering lost sales. ## What is Abandoned Cart Recovery? Abandoned cart recovery is an automated email marketing strategy that targets customers who begin the checkout process but don't complete their purchase. With high checkout abandonment rates across industries, this feature is essential for maximizing your revenue. ## Key Benefits * **Recover Lost Sales:** Significantly boost conversion rates and recover previously lost sales * **Automated Process:** Set it and forget it - emails are sent automatically * **Competitive Advantage:** Stay competitive in the e-commerce market * **Increased Revenue:** Turn potential lost sales into actual revenue * **Customer Re-engagement:** Bring customers back to complete their intended purchase ## How It Works 1. **Enable Per Product:** Merchants enable abandoned cart recovery for specific products 2. **Customer Starts Checkout:** A customer begins the checkout process for your product 3. **Abandonment Detection:** If they leave without completing the purchase, the system detects the abandoned checkout 4. **Automatic Email:** After a set time period, an automated recovery email is sent 5. **Revenue Recovery:** Earn revenue from previously lost sales ## Getting Started Setting up abandoned cart recovery is straightforward and requires minimal configuration: 1. **Enable the Feature Per Product** Ensure that you create a checkout passing your customer email in the request: [Docs](https://docs.creem.io/features/checkout) * Log into your Creem Dashboard * Navigate to "Products" section * Select the product you want to use the feature for * Scroll to "Abandoned Cart Recovery" section * Toggle the feature to "On" * Save product updates * Feature will be enabled and start monitoring product checkouts **Important Note** - **Ensure you have consent to use customer emails for marketing** - **Recovered transactions will incur additional charges** ## Merchant Responsibilities Before enabling abandoned cart recovery, merchants must ensure proper customer consent and legal compliance: ### **Legal Compliance** * **Update Terms & Conditions** - include information about abandoned cart email processing * **Update Privacy Policy** - disclose how customer data is used for recovery emails * **GDPR Compliance** - ensure all data processing follows GDPR requirements * **Regional Laws** - comply with local email marketing regulations in your jurisdiction ## Billing Model Creem charges a **5% fee on recovered transactions** - you only pay when the feature actually works and generates revenue for you. This performance-based pricing ensures you're only charged when a customer completes checkout through an automatically emailed link. The 5% fee applies to the recovered transaction, including subscriptions and any subsequent renewals. Merchants keep 95% of the recovered revenue. Other transactions from the same user are unaffected, including future subscriptions to the same product (e.g., if the user cancels and resubscribes). ## Email Sequence The abandoned cart recovery system automatically sends a sequence of recovery emails to customers who abandon their checkout process. ## Automated Process Once enabled, the abandoned cart recovery system works automatically: * **24-Hour Detection:** After 24 hours, the system automatically marks checkouts as abandoned * **Automatic Emails:** Recovery emails are sent automatically without merchant intervention ## Common Use Cases * **Digital Products:** Re-engage customers interested in software, courses, or downloads * **SaaS Subscriptions:** Convert trial users who abandon signup * **Micro-SaaS:** Recover sales for small software products and tools **Need Help?** Our support team is ready to assist you with setting up abandoned cart recovery. [Contact us](https://www.creem.io/contact) # File Downloads Source: https://docs.creem.io/features/addons/file-downloads Allow customers to download protected files after product purchase." # File Downloads with Creem Welcome to Creem's File Downloads documentation! This feature enables you to easily distribute digital files to customers after their purchase through our secure customer portal. ## Getting Started Setting up file downloads for your product is straightforward and requires minimal configuration: 1. Navigate to Your Product Settings * Log into your Creem Dashboard * Go to "Products" section * Create a new product * Enable "File Downloads" feature 2. Configure Your File Download * Upload your digital file(s) * Save your configuration ## How It Works Once configured, the file download system works automatically. When a customer completes a purchase, they'll receive access to your files in multiple locations: * **Email Receipt:** A secure download link appears in the purchase confirmation email that will lead the user to the customer portal * **Customer Portal:** Customers can download files anytime through their portal ## Best Practices * Organize files with clear, descriptive names * Compress large files when possible * Include readme files for installation or usage instructions * Regularly verify file integrity **Pro Tips** * Consider providing multiple file formats when relevant * Include version numbers in file names if applicable ## Common Use Cases * **Digital Products:** eBooks, music, videos, or software * **Documentation:** User manuals, guides, or specifications * **Resources:** Templates, assets, or tools * **Educational Content:** Course materials or supplementary resources ## Security Features Creem's file download system implements several security measures: * Secure, expiring download links * Protected file storage * Download attempt monitoring * Automated abuse prevention **Need Help?** Our support team is ready to assist you with setting up file downloads. [Contact us](https://www.creem.io/contact) # License Keys Source: https://docs.creem.io/features/addons/licenses Use the license key feature to enable access to your products. # License Key Management with Creem Welcome to Creem's License Key documentation! As a Merchant of Record specializing in Micro-SaaS and AI Businesses, we've built a powerful license key system that's both flexible and secure. ## Getting Started Setting up license keys for your product is straightforward: 1. **Configuring** * Create a new product with a License key feature enabled * Configure settings related to the licenses * Set up your product integration or payment links for customer purchases 2. **Dealing with a license after purchases** * Enable the user to enter a license key in your application * Activate a license key instance * Validate a license key instance on subsequent usages ## Step-by-Step Tutorial: Implementing License Keys Let's walk through the complete process of implementing license keys in your application. We'll cover everything from initial setup to handling customer interactions. ### Step 1: Creating Your Product First, let's set up your product in the Creem dashboard: 1. **Navigate to Products:** Log into your Creem dashboard and click "Create New Product" 2. **Enable License Keys:** In the product settings, enable the "License Key Management" feature 3. **Configure License Settings:** * Set activation limits (e.g., 3 devices per license) * Define expiration periods (e.g., 1 year from purchase) ### Step 2: Customer Purchase Flow When a customer purchases your product, here's what happens automatically: * A unique license key is generated and associated with their purchase * The key appears in their order confirmation page * It's included in their email receipt * The key is accessible in their customer portal ## Activating Licenses The activation endpoint is used to register a new device or instance with a valid license key. This is typically done when a user first sets up your application. ### Common Use Cases * **Initial Software Setup:** When users first install your application and enter their license key * **Device Migration:** When users need to activate your software on a new device * **Multi-device Scenarios:** For users who need to use your software across multiple machines * **Cloud Instance Deployment:** When spinning up new cloud instances that require license validation ### Benefits of the Activation System * **Prevents Unauthorized Usage:** Each activation is tracked and counted against the license limit * **User Flexibility:** Allows users to manage their own device activations within their quota * **Usage Analytics:** Provides insights into how and where your software is being used * **Fraud Prevention:** Helps identify and prevent license key sharing or abuse ### Activation Flow Here's how a typical activation flow works: 1. User purchases your software and receives a license key 2. User installs your application on their device 3. Application prompts for license key during first launch 4. Application generates a unique instance name (usually based on device characteristics) 5. Activation request is sent to the API 6. Upon successful activation, the instance ID is stored locally for future validation ### Endpoint Details * **URL:** `https://test-api.creem.io/v1/licenses/activate` * **Method:** POST * **Authentication:** Requires API key in headers ### Request Parameters * **key** (required): The license key to activate * **instance\_name** (required): A unique identifier for the device/installation The InstanceName field is an arbitrary name of your choice. Merchants usually use the internal customer ID, or customer email for quality of life maintainability. ### Response Format ```json theme={null} { "id": "", "mode": "test", "object": "", "status": "active", "key": "ABC123-XYZ456-XYZ456-XYZ456", "activation": 5, "activation_limit": 1, "expires_at": "2023-09-13T00:00:00Z", "created_at": "2023-09-13T00:00:00Z", "instance": [ { "id": "", "mode": "test", "object": "license-instance", "name": "My Customer License Instance", "status": "active", "created_at": "2023-09-13T00:00:00Z" } ] } ``` ### Implementation Examples ```ts TypeScript SDK theme={null} import { Creem } from "creem"; const creem = new Creem({ apiKey: process.env.CREEM_API_KEY!, server: "test", }); const license = await creem.licenses.activate({ key: "ABC123-XYZ456-XYZ456-XYZ456", instanceName: "johns-macbook-pro", }); ``` ```bash cURL theme={null} curl -X POST https://test-api.creem.io/v1/licenses/activate \ -H "accept: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "key": "ABC123-XYZ456-XYZ456-XYZ456", "instance_name": "johns-macbook-pro" }' ``` ```jsx JavaScript theme={null} const activateLicense = async (licenseKey, instanceName) => { const response = await fetch("https://test-api.creem.io/v1/licenses/activate", { method: "POST", headers: { accept: "application/json", "x-api-key": "YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ key: licenseKey, instance_name: instanceName, }), }); return await response.json(); }; ``` ```python Python theme={null} import requests def activate_license(license_key, instance_name): url = "https://test-api.creem.io/v1/licenses/activate" headers = { "accept": "application/json", "x-api-key": "YOUR_API_KEY", "Content-Type": "application/json" } data = { "key": license_key, "instance_name": instance_name } response = requests.post(url, json=data, headers=headers) return response.json() ``` **Pro Implementation Tips** - Use the TypeScript SDK for automatic type safety and better error handling - Generate meaningful instance names that help users identify their devices - Store activation tokens securely using system keychains or encrypted storage - Implement automatic retry logic for failed activation attempts - Add clear user feedback for activation status and remaining device quota ## Validating Licenses The validation endpoint allows you to verify if a license key is still valid and active. This is crucial for maintaining software security and ensuring proper usage of your product. ### Key Validation Features * **Real-time Status:** Get immediate feedback on license validity * **Feature Access:** Check which features are enabled for the license * **Quota Management:** Track remaining usage quotas * **Expiration Checking:** Verify if the license is still within its valid period ### When to Validate To ensure continued valid usage, implement regular license checks: * Validate on application startup * Check before accessing premium features * Periodically verify license status (e.g., daily) * Handle network errors and retry scenarios appropriately ### Validation Flow Here's how the validation process typically works: 1. Application starts up or performs periodic check 2. Retrieves stored license key and instance ID 3. Sends validation request to Creem API 4. Processes response and updates application state 5. Handles any validation errors or expired licenses ### Endpoint Details * **URL:** `https://test-api.creem.io/v1/licenses/validate` * **Method:** POST * **Authentication:** Requires API key in headers ### Request Parameters * **key** (required): The license key to validate * **instance\_id** (required): The instance ID received during activation ### Response Format ```json theme={null} { "id": "", "mode": "test", "object": "", "status": "active", "key": "ABC123-XYZ456-XYZ456-XYZ456", "activation": 5, "activation_limit": 1, "expires_at": "2023-09-13T00:00:00Z", "created_at": "2023-09-13T00:00:00Z", "instance": [ { "id": "", "mode": "test", "object": "license-instance", "name": "My Customer License Instance", "status": "active", "created_at": "2023-09-13T00:00:00Z" } ] } ``` ### Implementation Examples ```ts TypeScript SDK theme={null} import { Creem } from "creem"; const creem = new Creem({ apiKey: process.env.CREEM_API_KEY!, server: "test", }); const validatedLicense = await creem.licenses.validate({ key: "ABC123-XYZ456-XYZ456-XYZ456", instanceId: "inst_xyz123", }); console.log(validatedLicense.status); // "active" | "inactive" | "expired" | "disabled" if (validatedLicense.status === "active") { // Grant access to premium features console.log(`License expires at: ${validatedLicense.expiresAt}`); } else { // Deny access or show upgrade prompt console.log("License is not active"); } ``` ```bash cURL theme={null} curl -X POST https://test-api.creem.io/v1/licenses/validate \ -H "accept: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "key": "ABC123-XYZ456-XYZ456-XYZ456", "instance_id": "inst_xyz123" }' ``` ```jsx JavaScript theme={null} const validateLicense = async (licenseKey, instanceId) => { const response = await fetch("https://test-api.creem.io/v1/licenses/validate", { method: "POST", headers: { accept: "application/json", "x-api-key": "YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ key: licenseKey, instance_id: instanceId, }), }); return await response.json(); }; ``` ```python Python theme={null} import requests def validate_license(license_key, instance_id): url = "https://test-api.creem.io/v1/licenses/validate" headers = { "accept": "application/json", "x-api-key": "YOUR_API_KEY", "Content-Type": "application/json" } data = { "key": license_key, "instance_id": instance_id } response = requests.post(url, json=data, headers=headers) return response.json() ``` **Implementation Best Practices** - Cache validation results locally to reduce API calls - Implement graceful degradation for offline scenarios - Add clear user feedback for validation status - Keep logs of validation attempts for troubleshooting ## Deactivating Licenses The deactivation endpoint allows you to remove a device's access to a license key. This is essential for managing device transfers, subscription cancellations, and maintaining security of your software. ### Key Deactivation Features * **Instance Management:** Remove specific device instances from active licenses * **Activation Slot Recovery:** Free up slots for new device activations * **Usage Tracking:** Monitor deactivation history and remaining slots * **Automatic Cleanup:** Clear associated device data upon deactivation ### Common Deactivation Scenarios There are several scenarios where you might need to deactivate a license: * User requests to transfer their license to a new device * Subscription cancellation * Suspicious activity detection * User switching between devices ### Deactivation Flow Here's how the deactivation process typically works: 1. User initiates deactivation (e.g., switching devices) 2. Application retrieves stored license key and instance ID 3. Sends deactivation request to Creem API 4. Cleans up local license data 5. Provides feedback to user about deactivation status ### Endpoint Details * **URL:** `https://test-api.creem.io/v1/licenses/deactivate` * **Method:** POST * **Authentication:** Requires API key in headers ### Request Parameters * **key** (required): The license key to deactivate * **instance\_id** (required): The instance ID to deactivate ### Response Format ```json theme={null} { "id": "", "mode": "test", "object": "", "status": "active", "key": "ABC123-XYZ456-XYZ456-XYZ456", "activation": 5, "activation_limit": 1, "expires_at": "2023-09-13T00:00:00Z", "created_at": "2023-09-13T00:00:00Z", "instance": [ { "id": "", "mode": "test", "object": "license-instance", "name": "My Customer License Instance", "status": "active", "created_at": "2023-09-13T00:00:00Z" } ] } ``` ### Implementation Examples ```ts TypeScript SDK theme={null} import { Creem } from "creem"; const creem = new Creem({ apiKey: process.env.CREEM_API_KEY!, server: "test", }); const deactivatedLicense = await creem.licenses.deactivate({ key: "ABC123-XYZ456-XYZ456-XYZ456", instanceId: "inst_xyz123", }); ``` ```bash cURL theme={null} curl -X POST https://test-api.creem.io/v1/licenses/deactivate \ -H "accept: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "key": "ABC123-XYZ456-XYZ456-XYZ456", "instance_id": "inst_xyz123" }' ``` ```jsx JavaScript theme={null} const deactivateLicense = async (licenseKey, instanceId) => { const response = await fetch("https://test-api.creem.io/v1/licenses/deactivate", { method: "POST", headers: { accept: "application/json", "x-api-key": "YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ key: licenseKey, instance_id: instanceId, }), }); return await response.json(); }; ``` ```python Python theme={null} import requests def deactivate_license(license_key, instance_id): url = "https://test-api.creem.io/v1/licenses/deactivate" headers = { "accept": "application/json", "x-api-key": "YOUR_API_KEY", "Content-Type": "application/json" } data = { "key": license_key, "instance_id": instance_id } response = requests.post(url, json=data, headers=headers) return response.json() ``` **Deactivation Best Practices** - Always confirm deactivation with users before proceeding - Clear all local license data after successful deactivation - Implement proper error handling for failed deactivations - Maintain deactivation logs for customer support ## Error Handling Common error responses across all license endpoints include: * **400 Bad Request:** Invalid or missing parameters * **401 Unauthorized:** Invalid API key * **403 Forbidden:** License key has reached activation limit (activation only) * **404 Not Found:** Invalid license key or instance ID * **409 Conflict:** Instance already deactivated (deactivation only) * **410 Gone:** License has been revoked or expired (validation only) ## Best Practices * **Security:** Store the instance\_id securely after successful activation * **Error Handling:** Implement graceful error handling for network issues * **User Experience:** Add clear user feedback for all license-related actions * **Offline Support:** Consider implementing an offline grace period * **Validation:** Always validate license keys on startup and critical operations * **Caching:** Cache validation results to prevent excessive API calls * **API Keys:** Securely store API keys and never expose them client-side ## Common Pitfalls to Avoid * Don't store API keys in client-side code * Never expose the full license validation logic to end users * Don't forget to handle edge cases (expired licenses, network errors) ## Security Considerations Creem's license key system implements several security measures: * Encrypted communication channels * Automatic suspicious activity detection * Regular security audits and updates ## API Reference For detailed API documentation, visit: * [License Key API Reference](http://docs.creem.io/api-reference/endpoint/validate-license) View the complete TypeScript SDK documentation with examples for licenses, subscriptions, and more. **Need Help?** Our support team is ready to assist you with license key implementation. [Contact us](https://www.creem.io/contact) # Private Notes Source: https://docs.creem.io/features/addons/private-notes Display private notes for users after they complete a purchase of your product." # Private Notes with Creem Welcome to Creem's Private Notes documentation! This feature allows you to seamlessly include private notes that are automatically shared with customers after their purchase. ## Getting Started Setting up private notes for your product is straightforward and requires minimal configuration: 1. Navigate to Your Product Settings * Log into your Creem Dashboard * Go to "Products" section * Create a new product * Enable "Private Notes" feature 2. Configure Your Private Note * Enter the note content that customers will receive * Save your configuration ## How It Works Once configured, the private note system works automatically. When a customer completes a purchase, they'll receive your private note in multiple locations: * **Email Receipt:** The private note appears in the purchase confirmation email * **Customer Portal:** Customers can access the note anytime through their portal * **Order Confirmation Page:** The note is displayed immediately after purchase (when no redirect URL is set) ## Best Practices * Keep notes clear and concise * Include relevant information for post-purchase actions * Consider adding support contact information * Use different notes as needed for different product versions **Pro Tips** * Use formatting to highlight important information * Include next steps if applicable * Consider different customer scenarios when writing your note ## Common Use Cases * **Service Purchases:** Share onboarding information or next steps * **Course Access:** Provide login credentials or access instructions * **Digital Content:** Password to spreadsheets * **Premium Customer Support:** Contact numbers, emails or other channels # Affiliate Program Source: https://docs.creem.io/features/affiliate-program Launch your own affiliate marketing program to grow revenue through partner referrals. Invite affiliates, set a program commission rate, and track performance from your dashboard. The Creem Affiliate Platform is a complete affiliate marketing solution that enables merchants to create referral programs and affiliates to earn commissions by promoting products. The platform handles tracking, attribution, payouts, and compliance automatically. Creem Affiliate Hub dashboard showing performance metrics, revenue chart, and partner management ## Key Features Create affiliate programs, invite partners, set commission rates, and track revenue from affiliate referrals Join programs, get unique referral links, track earnings in real-time, and request payouts Attribution automatically credits affiliates for referred sales Built-in KYC verification and multiple payout methods (bank transfer, crypto) ## How It Works The affiliate platform consists of two parts: | Component | URL | Purpose | | -------------------- | ---------------------------------- | ---------------------------------------- | | **Affiliate Hub** | `creem.io/dashboard/affiliate-hub` | Merchant dashboard for managing programs | | **Affiliate Portal** | `affiliates.creem.io` | Dedicated portal for affiliate partners | ```mermaid theme={null} %%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#FFBE98','primaryTextColor':'#000','primaryBorderColor':'#FFBE98','lineColor':'#B09CFB','fontSize':'12px'}}}%% flowchart TD A([Create a program]) --> B([Invite affiliates]) B --> C([Affiliate shares their referral link]) C --> D([Customer clicks link & purchases]) D --> E([Commission is applied for this purchase]) classDef default fill:#FFBE98,stroke:none,color:#000 linkStyle default stroke:#B09CFB,stroke-width:2px ``` *** ## For Merchants ### Creating an Affiliate Program Navigate to your Creem dashboard and access the Affiliate Hub under the **Growth** section. Creem dashboard sidebar showing Growth menu with Affiliate Hub option Go to **Growth** β†’ **Affiliate Hub** in your dashboard sidebar. If this is your first time, you'll see the program creation wizard. Fill in your program information: * **Program Name**: A descriptive name for your affiliate program * **Website URL**: Where affiliate links should redirect (your landing page) * **Description**: What affiliates should know about your program Affiliate program creation form showing program name, website URL, and description fields Set up your program's commission structure: * **Program Slug**: A unique URL identifier (e.g., `my-program` creates links like `?ref=my-program`) * **Commission Rate**: Percentage of each sale paid to affiliates (0-100%) Program settings showing slug configuration and commission rate percentage field Once your program is created, you can start inviting partners from the Affiliate Hub dashboard. ### Inviting Affiliates Click **Invite Partner** from the Affiliate Hub to send invitations to potential affiliates. Invite affiliate modal with email and name input fields To invite an affiliate: 1. Enter their **email address** 2. Enter their **name** 3. Click **Send Invite** The affiliate will receive an email invitation with a link to join your program. Pending invites appear in your Partners list with "Invited" status. ### Tracking Performance The Affiliate Hub provides comprehensive analytics for your program: | Metric | Description | | --------------------- | ------------------------------------------------ | | **Revenue** | Total revenue generated from affiliate referrals | | **Unique Leads** | Number of unique visitors from affiliate links | | **Total Clicks** | Total clicks on all affiliate links | | **Checkouts Created** | Checkout sessions started by referred visitors | | **Conversions** | Conversion rate (sales / unique leads) | | **Affiliates** | Number of active affiliate partners | ### Partners List The Partners list shows each affiliate in your program and their current performance at a glance: | Column | Description | | ------------------- | -------------------------------------------------- | | **Name** | Affiliate's display name | | **Email** | Affiliate's email address | | **Status** | Current partner status, such as Active or Invited | | **Clicks** | Total clicks tracked for this affiliate | | **Conversions** | Total referred purchases for this affiliate | | **Conversion Rate** | Percentage of clicks that converted into purchases | | **Earnings** | Total commissions earned by this affiliate | #### Limitations At this time, managing individual partners is not supported, including deleting pending affiliate invitations, setting per-affiliate commission rates, or configuring per-affiliate product restrictions. Want this workflow? Upvote and follow the [Manage affiliate partners feature request](https://creem.featurebase.app/en/p/manage-affiliate-partners) to get updates if it is implemented. *** ## For Affiliates ### Joining a Program When a merchant invites you to their affiliate program, you'll receive an email with an invitation link. Visit `affiliates.creem.io` and sign in using the email address the invitation was sent to. You can use Google sign-in or a magic link. Affiliate portal sign-in page with Google and email options Click the invitation link from your email. Review the program details and click **Join Program** to accept. First-time affiliates will be prompted to complete their profile: * **Display Name**: How merchants will see you * **Bio**: A brief description of yourself/your platform * **Website**: Your website or landing page (optional) * **Social Links**: Your social media profiles (optional) ### Your Affiliate Dashboard After joining a program, your dashboard shows: * **Your Referral Link**: Copy and share this unique URL to earn commissions * **Revenue**: Total commissions earned * **Customers**: Number of customers referred * **Clicks**: Total clicks on your affiliate links * **Conversion Rate**: Percentage of clicks that result in sales * **Commission Chart**: 30-day visual breakdown of your earnings ### Sharing Your Referral Link Your unique referral link is displayed on your dashboard. When someone clicks your link: 1. A tracking cookie is set on their browser 2. If they make a purchase within the cookie duration, you earn commission 3. The sale appears in your dashboard automatically ### Tracking Earnings View your earnings breakdown on the **Balance** page: | Balance Type | Description | | --------------------- | ------------------------------------- | | **Available Balance** | Funds ready to withdraw | | **On Hold** | Pending verification or review period | | **Pending Payouts** | Payout requests being processed | ### Requesting Payouts Navigate to the **Payouts** page to withdraw your earnings. Before requesting payouts, you must complete verification: Complete identity verification through Sumsub. This requires a government-issued ID and a selfie. Verification typically completes within 24 hours. Choose your preferred payout method: * **Bank Transfer**: Add your bank account details via Paysway * **Cryptocurrency**: Set up USDC payouts via Mural Once verified, you can request payouts from the Payouts page. ### Payout Schedule and Thresholds Affiliate payouts follow the same schedule as merchant payouts: | Detail | Value | | ------------------- | ------------------------------------------------------------ | | **Payout windows** | 1st and 15th of each month | | **Minimum balance** | 50 USD or 50 EUR | | **Hold period** | 7–12 days (required by payment partners for risk assessment) | Only commissions that have cleared the hold period by the payout date will be included. For example, if your payout is scheduled for the 15th, only commissions from sales processed before approximately the 8th will be available for that payout. When your available balance reaches the minimum threshold, click the **Withdraw** button on your Balance page. Your payout will be queued and processed in the next available payout window (1st or 15th of the month). If the payout date falls on a weekend or public holiday, the payout will be processed on the next business day. ### Payout Methods and Fees | Method | Provider | Fee | | ------------------------------------- | -------- | ----------------------------------------------------- | | **Bank Transfer** | Paysway | 7 USD/EUR or 1% of payout amount, whichever is higher | | **Cryptocurrency (USDC via Polygon)** | Mural | 2% of payout volume | If your bank account currency differs from the commission currency, a conversion fee may be applied by the payment provider. This is outside of Creem's control. After your payout is processed, a payout record will appear on the **Payout Activity** tab of your Balance page, with a reverse invoice available for download for tax purposes. ### Managing Your Profile Update your profile information on the **Profile** page: * **Email**: Your account email (read-only) * **Display Name**: How you appear to merchants * **Bio**: Describe yourself and your promotional methods (max 1,000 characters) * **Website**: Your primary website or landing page * **Social Links**: Add links to your social media profiles ### Multiple Program Memberships If you're an affiliate for multiple merchants, you can switch between programs using the membership switcher in the sidebar footer. Each program has its own stats, balance, and payout settings. *** ## Configuration Options ### Program Settings | Setting | Description | Default | | --------------------- | ------------------------------------------- | -------- | | **Commission Rate** | Percentage paid to affiliates per sale | Required | | **Cookie Duration** | How long referral tracking lasts (days) | Varies | | **Payout Threshold** | Minimum balance required for withdrawal | None | | **Requires Approval** | Whether new affiliates need manual approval | Yes | | **Public Program** | Whether anyone can join without invitation | No | *** ## Frequently Asked Questions Cookie duration is set by the merchant when creating the program. Typical durations range from 30 to 90 days. If a customer returns and purchases within the cookie window, you earn commission. Payouts are processed on the 1st and 15th of each month. You must reach a minimum balance of 50 USD/EUR, complete identity verification (KYC), and set up a payout method before requesting a withdrawal. Once you click Withdraw, your payout is queued for the next available window. Note that commissions have a 7–12 day hold period before they become available. Yes! You can join multiple affiliate programs and manage them all from your affiliate portal. Use the membership switcher to view stats and earnings for each program. Commission rates vary by merchant and product type. Software and digital products often offer 20-50% commissions, while physical products typically range from 5-20%. When someone clicks your affiliate link, a cookie is stored in their browser. This cookie attributes any purchases to you within the cookie duration period. Yes. When a merchant embeds the Creem checkout in their own site, the affiliate cookie isn't available inside the cross-site iframe (no browser sends it there) β€” so Creem carries attribution as a signed URL token (`creem_ref`) that the embed forwards automatically. Merchants don't need to wire anything for the common case. See [Embedded checkout β†’ Affiliate attribution](/features/checkout/embedded-checkout#affiliate-attribution). Yes, your dashboard shows conversion data. Merchants may also provide additional reporting on which products drive the most affiliate sales. Affiliates can receive payouts via bank transfer (processed through Paysway) or cryptocurrency (USDC via Mural). Set up your preferred method in the Payouts section. Yes, you need a minimum available balance of 50 USD or 50 EUR to request a withdrawal. Once you reach this threshold, the Withdraw button becomes available on your Balance page. *** ## Related Features Automatically distribute revenue between co-founders and partners Create promotional codes for affiliates to share with their audience Get notified of affiliate sales in real-time via webhooks Alternative: Use Affonso for external affiliate tracking *** Need help with your affiliate program? [Contact us](https://www.creem.io/contact) or join our [Discord community](https://discord.gg/q3GKZs92Av). # Checkout API Source: https://docs.creem.io/features/checkout/checkout-api Create dynamic checkout sessions programmatically with full control over payment flow and tracking. Checkout sessions give you programmatic control over the payment flow. Unlike static payment links, checkout sessions are generated dynamically, allowing you to: * Pass custom tracking IDs for each payment * Pre-fill customer information like email * Set dynamic success URLs based on your app's context * Apply discount codes programmatically * Add metadata for internal tracking ## Prerequisites Before creating checkout sessions, you'll need: * **A Creem account** with an API key ([Get your key](https://creem.io/dashboard/developers)) * **At least one product** created in your dashboard. One-time products can be paid or free with a `0` price. Find your product ID by going to the [Products tab](https://creem.io/dashboard/products), clicking on a product, and selecting "Copy ID" from the options menu. ## Creating a Checkout Session Choose the integration method that works best for your stack: The Next.js adapter provides a route handler and React component for seamless integration. ### Install the package ```bash npm theme={null} npm install @creem_io/nextjs ``` ```bash yarn theme={null} yarn add @creem_io/nextjs ``` ```bash pnpm theme={null} pnpm install @creem_io/nextjs ``` ```bash bun theme={null} bun install @creem_io/nextjs ``` ### Create the checkout route ```ts theme={null} // app/api/checkout/route.ts import { Checkout } from "@creem_io/nextjs"; export const GET = Checkout({ apiKey: process.env.CREEM_API_KEY!, testMode: process.env.NODE_ENV !== "production", defaultSuccessUrl: "/success", }); ``` ### Add a checkout button ```tsx theme={null} // app/page.tsx "use client"; // Optional: CreemCheckout also works in Server Components import { CreemCheckout } from "@creem_io/nextjs"; export function CheckoutButton() { return ( ); } ``` The `CreemCheckout` component automatically handles the checkout session creation and redirects the user to the payment page. Explore advanced features, server components, and webhook handling. The TypeScript SDK provides full type-safety and works with any JavaScript framework. ### Install the SDK ```bash npm theme={null} npm install creem ``` ```bash yarn theme={null} yarn add creem ``` ```bash pnpm theme={null} pnpm install creem ``` ```bash bun theme={null} bun install creem ``` ### Create a checkout session ```typescript theme={null} import { Creem } from "creem"; const creem = new Creem({ apiKey: process.env.CREEM_API_KEY!, server: process.env.NODE_ENV === "production" ? "prod" : "test", }); // Create a checkout session const checkout = await creem.checkouts.create({ productId: "prod_YOUR_PRODUCT_ID", requestId: "order_123", // Optional: Track this payment successUrl: "https://yoursite.com/success", customer: { email: "customer@example.com", // Optional: Pre-fill email }, }); // Redirect to the checkout URL console.log(checkout.checkoutUrl); // In the browser: window.location.href = checkout.checkoutUrl; ``` View the full SDK API reference and advanced usage examples. The Better Auth integration automatically syncs payments with your authenticated users. ### Install the plugin ```bash theme={null} npm install @creem_io/better-auth better-auth ``` ### Configure Better Auth ```typescript theme={null} // auth.ts import { betterAuth } from "better-auth"; import { creem } from "@creem_io/better-auth"; export const auth = betterAuth({ database: { // your database config }, plugins: [ creem({ apiKey: process.env.CREEM_API_KEY!, testMode: process.env.NODE_ENV !== "production", defaultSuccessUrl: "/dashboard", }), ], }); ``` ### Client setup ```typescript theme={null} // lib/auth-client.ts import { createAuthClient } from "better-auth/react"; import { creemClient } from "@creem_io/better-auth/client"; export const authClient = createAuthClient({ baseURL: process.env.NEXT_PUBLIC_APP_URL, plugins: [creemClient()], }); ``` ### Create a checkout ```typescript theme={null} "use client"; import { authClient } from "@/lib/auth-client"; export function CheckoutButton({ productId }: { productId: string }) { const handleCheckout = async () => { const { data, error } = await authClient.creem.createCheckout({ productId, successUrl: "/dashboard", }); if (data?.url) { window.location.href = data.url; } }; return ; } ``` The Better Auth integration automatically tracks the authenticated user and syncs subscription status with your database. Learn about database persistence, access management, and webhook handling. Use the REST API directly from any language or framework. ### Create a checkout session If you're in test mode, use `https://test-api.creem.io` instead of `https://api.creem.io`. Learn more about [Test Mode](/getting-started/test-mode). ```bash theme={null} curl -X POST https://api.creem.io/v1/checkouts \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_YOUR_PRODUCT_ID", "request_id": "order_123", "success_url": "https://yoursite.com/success" }' ``` ### Response ```json theme={null} { "id": "ch_1QyIQDw9cbFWdA1ry5Qc6I", "checkout_url": "https://checkout.creem.io/ch_1QyIQDw9cbFWdA1ry5Qc6I", "product_id": "prod_YOUR_PRODUCT_ID", "status": "pending" } ``` Redirect your user to the `checkout_url` to complete the payment. View the complete endpoint documentation with all available parameters. ## Handling Successful Payments After a successful payment, users are redirected to your `success_url` with payment details as query parameters: ``` https://yoursite.com/success?checkout_id=ch_xxx&order_id=ord_xxx&customer_id=cust_xxx&product_id=prod_xxx ``` | Query parameter | Description | | ----------------- | ------------------------------------------------------------------------------ | | `checkout_id` | The ID of the checkout session created for this payment. | | `order_id` | The ID of the order created after successful payment. | | `customer_id` | The customer ID, based on the email that executed the successful payment. | | `subscription_id` | The subscription ID of the product. | | `product_id` | The product ID that the payment is related to. | | `request_id` | Optional. The request/reference ID you provided when creating this checkout. | | `signature` | All previous parameters signed by creem using your API-key, verifiable by you. | For production applications, we recommend using [Webhooks](/code/webhooks) to handle payment events. ### Verifying Redirect Signatures The `signature` query parameter allows you to verify that the redirect came from Creem. This prevents malicious users from spoofing successful payment redirects. The signature is a SHA-256 hex digest of the redirect parameters joined with `|`, with `salt= {apiKey}` appended at the end. **Parameters appear in the order they arrive in the redirect URL** (not alphabetically sorted), and **null or empty values are excluded** β€” only include parameters that have actual values. The canonical string is built as: ```text theme={null} key1=value1|key2=value2|...|keyN=valueN|salt={apiKey} ``` Then hashed with SHA-256 and hex-encoded to produce the `signature` value. ```typescript theme={null} import * as crypto from "crypto"; interface RedirectParams { request_id?: string | null; checkout_id: string; order_id: string | null; customer_id: string | null; subscription_id: string | null; product_id: string; signature: string; } function verifyRedirectSignature(params: RedirectParams, apiKey: string): boolean { const { signature, ...rest } = params; // Keep insertion order; exclude null/undefined/empty values. const data = Object.entries(rest) .filter(([, value]) => value !== null && value !== undefined && value !== "") .map(([key, value]) => `${key}=${value}`) .concat(`salt=${apiKey}`) .join("|"); const expectedSignature = crypto.createHash("sha256").update(data).digest("hex"); return signature === expectedSignature; } // Usage in your success page export async function GET(request: Request) { const url = new URL(request.url); // Read fields in the order they appear in the redirect URL. const params: RedirectParams = { request_id: url.searchParams.get("request_id"), checkout_id: url.searchParams.get("checkout_id")!, order_id: url.searchParams.get("order_id"), customer_id: url.searchParams.get("customer_id"), subscription_id: url.searchParams.get("subscription_id"), product_id: url.searchParams.get("product_id")!, signature: url.searchParams.get("signature")!, }; const isValid = verifyRedirectSignature(params, process.env.CREEM_API_KEY!); if (!isValid) { return new Response("Invalid signature", { status: 401 }); } // Proceed with success page... } ``` ```python theme={null} import hashlib import hmac from urllib.parse import urlparse, parse_qsl def verify_redirect_signature(query_string: str, api_key: str) -> bool: """ Verify the redirect signature from Creem checkout. Args: query_string: The raw query string from the redirect URL. api_key: Your Creem API key. Returns: True if signature is valid, False otherwise. """ # parse_qsl preserves the order parameters appear in the URL. pairs = parse_qsl(query_string, keep_blank_values=False) signature = '' parts = [] for key, value in pairs: if key == 'signature': signature = value continue if value in (None, '', 'null'): continue parts.append(f'{key}={value}') parts.append(f'salt={api_key}') data = '|'.join(parts) expected_signature = hashlib.sha256(data.encode()).hexdigest() return hmac.compare_digest(signature, expected_signature) # Usage in Flask @app.route('/success') def success(): if not verify_redirect_signature(request.query_string.decode(), os.environ['CREEM_API_KEY']): return 'Invalid signature', 401 # Proceed with success page... ``` ```go theme={null} package main import ( "crypto/sha256" "crypto/subtle" "encoding/hex" "net/url" "strings" ) // verifyRedirectSignature checks the redirect signature using the raw query // string so parameter order matches what Creem signed. func verifyRedirectSignature(rawQuery, apiKey string) bool { var signature string var parts []string for _, pair := range strings.Split(rawQuery, "&") { if pair == "" { continue } key, value, _ := strings.Cut(pair, "=") decodedKey, err := url.QueryUnescape(key) if err != nil { return false } decodedValue, err := url.QueryUnescape(value) if err != nil { return false } if decodedKey == "signature" { signature = decodedValue continue } if decodedValue == "" || decodedValue == "null" { continue } parts = append(parts, decodedKey+"="+decodedValue) } parts = append(parts, "salt="+apiKey) data := strings.Join(parts, "|") sum := sha256.Sum256([]byte(data)) expected := hex.EncodeToString(sum[:]) return subtle.ConstantTimeCompare([]byte(signature), []byte(expected)) == 1 } ``` **Important:** Parameters with `null` or empty values (like `order_id` for subscription-only checkouts, or `subscription_id` for one-time payments) must be **excluded** from the signed string. Including them as `"order_id=null"` will cause verification to fail. *** ## Advanced Features ### Metadata Add custom metadata to track additional information with each payment. Metadata is included in webhook events and can be retrieved later. ```tsx theme={null} ``` ```typescript theme={null} const checkout = await creem.checkouts.create({ productId: "prod_YOUR_PRODUCT_ID", requestId: "order_123", metadata: { userId: "internal_user_id", planType: "premium", source: "marketing_campaign", }, }); ``` ```typescript theme={null} const { data } = await authClient.creem.createCheckout({ productId: "prod_YOUR_PRODUCT_ID", metadata: { planType: "premium", source: "marketing_campaign", }, }); ``` ```bash theme={null} curl -X POST https://api.creem.io/v1/checkouts \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_YOUR_PRODUCT_ID", "metadata": { "userId": "internal_user_id", "planType": "premium", "source": "marketing_campaign" } }' ``` Metadata is especially useful for tracking internal IDs, campaign sources, or any custom information you need to associate with a payment. ### Custom Success URL Override the default success URL on a per-checkout basis. This is useful for directing users to specific pages after payment based on context. ```tsx theme={null} ``` ```typescript theme={null} const checkout = await creem.checkouts.create({ productId: "prod_YOUR_PRODUCT_ID", successUrl: "https://yoursite.com/account/welcome", }); ``` ```typescript theme={null} const { data } = await authClient.creem.createCheckout({ productId: "prod_YOUR_PRODUCT_ID", successUrl: "/account/welcome", }); ``` ```bash theme={null} curl -X POST https://api.creem.io/v1/checkouts \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_YOUR_PRODUCT_ID", "success_url": "https://yoursite.com/account/welcome" }' ``` ### Pre-fill Customer Email Lock the customer email at checkout to ensure users complete payment with the email they registered with on your platform. ```tsx theme={null} ``` ```typescript theme={null} const checkout = await creem.checkouts.create({ productId: "prod_YOUR_PRODUCT_ID", customer: { email: "user@example.com", }, }); ``` ```typescript theme={null} // Email is automatically set from the authenticated user const { data } = await authClient.creem.createCheckout({ productId: "prod_YOUR_PRODUCT_ID", customer: { email: "user@example.com", // Optional: if you want to overwrite the session }, }); ``` The Better Auth integration automatically uses the authenticated user's email. ```bash theme={null} curl -X POST https://api.creem.io/v1/checkouts \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_YOUR_PRODUCT_ID", "customer": { "email": "user@example.com" } }' ``` ### Apply Discount Codes Apply discount codes programmatically to pre-fill them at checkout. ```tsx theme={null} ``` ```typescript theme={null} const checkout = await creem.checkouts.create({ productId: "prod_YOUR_PRODUCT_ID", discountCode: "LAUNCH50", }); ``` ```typescript theme={null} const { data } = await authClient.creem.createCheckout({ productId: "prod_YOUR_PRODUCT_ID", discountCode: "LAUNCH50", }); ``` ```bash theme={null} curl -X POST https://api.creem.io/v1/checkouts \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_YOUR_PRODUCT_ID", "discount_code": "LAUNCH50" }' ``` Learn how to create and manage discount codes in your dashboard. ### Seat-Based Billing Charge for multiple units or seats by specifying the `units` parameter. The total price will be calculated as `base_price Γ— units`. ```tsx theme={null} ``` ```typescript theme={null} const checkout = await creem.checkouts.create({ productId: "prod_YOUR_PRODUCT_ID", units: 5, // Charge for 5 seats }); ``` ```typescript theme={null} const { data } = await authClient.creem.createCheckout({ productId: "prod_YOUR_PRODUCT_ID", units: 5, // Charge for 5 seats }); ``` ```bash theme={null} curl -X POST https://api.creem.io/v1/checkouts \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_YOUR_PRODUCT_ID", "units": 5 }' ``` Learn more about implementing and managing seat-based pricing models. *** ## Next Steps Brand your checkout with custom colors, logos, and themes Collect additional information from customers during checkout Learn how to manage recurring billing and subscriptions Split revenue between multiple parties automatically # Checkout Custom Fields Source: https://docs.creem.io/features/checkout/checkout-custom-fields Enable custom fields on product checkout sessions. This feature allows you to collect additional information from customers during checkout by adding customizable fields to your product purchase flow. ## Getting Started Setting up custom fields for your product is straightforward and requires minimal configuration: 1. Navigate to Your Product Settings * Log into your Creem Dashboard * Go to "Products" section * Create a new product * Enable "Custom Fields" feature 2. Configure Your Custom Fields * Choose the field type (text, number, email, etc.) * Set the field name and label * Configure input validation rules * Save your configuration ## How It Works When custom fields are configured, they automatically appear during the checkout process. The collected information is then: * **Stored securely:** All custom field data is encrypted and stored securely * **Accessible via Webhook:** Data is included in the `checkout.completed` webhook event * **Available in Dashboard:** View responses in your merchant dashboard ## Common Use Cases * **Integration IDs:** Collect user IDs from other platforms or systems * **Contact Information:** Gather phone numbers, alternative email addresses, or social media handles * **Customization Details:** Collect preferences, sizes, or specifications * **Business Information:** Company names, tax IDs, or registration numbers * **Event Details:** Dates, attendance information, or dietary preferences ## Best Practices * Keep required fields to a minimum * Use clear, descriptive field labels * Select appropriate validation rules * Consider mobile user experience **Pro Tips** * Use conditional fields when appropriate * Group related fields together * Test the checkout flow thoroughly ## Webhook Integration Custom field data is automatically included in the `checkout.completed` webhook payload, making it easy to integrate with your systems. [Learn more about the checkout.completed webhook](https://docs.creem.io/code/webhooks). # Checkout Customization Source: https://docs.creem.io/features/checkout/checkout-customization Customize your checkout and email receipts with your brand logo, colors, and theme for a seamless customer experience. Deliver a seamless, on-brand experience from your application to the checkout and beyond. Creem lets you customize your checkout flow and email receipts with your store's logo, colors, and theme. Ensuring your customers always feel at home. Example of a branded checkout with custom logo and colors ## Why Customize Branding? * **Consistent brand experience** from your app to checkout and receipts * **Build trust** with your customers * **Increase conversion** by reducing friction and confusion Your logo and colors are used on both the checkout page and the email receipt sent after a successful payment. ## How to Update Your Store Branding Click your profile icon in the top right corner, then select Settings for your current store. In the settings sidebar, navigate to Branding.
  • Upload your logo (used on checkout and email receipts)
  • Select your default checkout theme (light or dark)
  • Pick your accent color (used for buttons, upsells, and field borders)
  • Set your accent hover color (for button hover states)
  • Choose your text color (for dynamic buttons and component text)
Save your changes. You can preview your checkout with the new branding instantly.
Creem branding settings UI with logo upload and color pickers ## Test Mode vs Live Mode You can safely experiment with different branding options in [Test Mode](/getting-started/test-mode). These changes won't affect your live checkout. When you're ready, switch to live mode and apply your final branding for real customers. ## Programmatic Theme Selection You can override the default checkout theme by appending ?theme=light or ?theme=dark to your checkout URL before redirecting your customers. Example: [https://www.creem.io/payment/prod\_3pcofZ4pTXtuvdDb1j2MMp?theme=dark](https://www.creem.io/payment/prod_3pcofZ4pTXtuvdDb1j2MMp?theme=dark) See the full list of URL parameters you can use with payment links, including discount codes and metadata. ## Best Practices * Use a high-contrast logo with a transparent background for best results * Choose accessible color combinations for text and buttons * Preview your checkout and email receipts in both light and dark themes * Test your branding in test mode before going live # Checkout Link Source: https://docs.creem.io/features/checkout/checkout-link Learn how to receive payments without any code ## Prerequisites To get the most out of this guide, you'll need to: * **Create an account on Creem.io** * **Have your API key ready** ## 1. Create a product Go over to the [products tab](https://creem.io/dashboard/products) and create a product. You can add a name, description, and price to your product. Optionally you can also add a picture to your product that will be shown to users. ## 2. Copy the payment link from the product After successfully creating your product, you can copy the payment link by clicking on the product Share button. Simply send this link to your users and they will be able to pay you instantly. ## 3. Customize with URL parameters Payment links support query parameters that let you customize the checkout experience without any code. Append them to your payment link URL: ``` https://creem.io/payment/prod_xxxxx?discount_code=LAUNCH50&theme=dark ``` ### Available parameters | Parameter | Example | Description | | --------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `discount_code` | `?discount_code=LAUNCH50` | Pre-applies a discount code to the checkout. The discount is validated and applied server-side when the checkout session is created. | | `theme` | `?theme=dark` | Sets the checkout theme to `light` or `dark`, overriding your store's default branding theme. | | `metadata[key]` | `?metadata[source]=twitter&metadata[campaign]=launch` | Passes custom metadata key-value pairs to the checkout session. Metadata is included in webhook events and can be retrieved via the API. Use bracket notation for each key. | You can combine multiple parameters: `?discount_code=SAVE20&theme=dark&metadata[source]=email` Parameters like `discount_code` and `metadata` are processed server-side and won't appear in the final checkout URL. The `theme` parameter and any other unrecognized parameters are forwarded to the checkout page as query strings. ### More use cases If you are not planning to do a no-code integration, we strongly encourage you to check out our other guides. Create checkout-sessions and prices dynamically, use webhooks to receive updates on your application automatically, and much more. Check out our guides to get the most out of Creem. Learn how to create and manage checkout sessions programmatically using the Creem API. Set up webhooks to receive updates on your application automatically. # Checkout Localization Source: https://docs.creem.io/features/checkout/checkout-localization Provide a native language checkout experience with automatic language detection and support for 42 languages worldwide. Creem automatically localizes your checkout interface to match your customer's language, helping you reach a global audience and increase conversion rates through familiar, native-language interactions. Localization applies only to the checkout interface elements (form labels, buttons, validation messages, payment UI). Your product names, descriptions, and other store content remain as you've entered them. ## Supported Languages Creem supports 42 languages and regional variants, ensuring comprehensive global coverage: ### European Languages Bulgarian, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hungarian, Italian, Latvian, Lithuanian, Maltese, Norwegian (BokmΓ₯l), Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish ### Regional Variants * **English:** English (US), English (UK) * **Spanish:** Spanish (Spain), Spanish (Latin America) * **French:** French (France), French (Canada) * **Portuguese:** Portuguese (Portugal), Portuguese (Brazil) * **Chinese:** Simplified Chinese, Traditional Chinese (Hong Kong), Traditional Chinese (Taiwan) ### Asian Languages Chinese (Simplified and Traditional), Filipino, Indonesian, Japanese, Korean, Malay, Thai, Turkish, Vietnamese ## How It Works **Automatic Detection:** Creem detects the customer's browser language on first visit. If supported, the checkout displays in that language; otherwise, it defaults to English. **Manual Override:** Customers can change languages using the language switcher in the checkout interface. Their preference is saved and persists across sessions. **What's Localized:** * Form labels and placeholders * Validation and error messages * Button text and calls-to-action * Payment interface elements * Order summary sections ## Fallback Behavior * **Unsupported languages:** Defaults to English * **Missing translations:** English text shown for incomplete translations * **Partial browser support:** Closest supported language variant is selected ## Testing Test different languages in [Test Mode](/getting-started/test-mode) by changing your browser's language preference or using the language switcher in the checkout interface. ## Frequently Asked Questions All 42 supported languages are automatically available to ensure the widest reach. Localization cannot be customized or disabled. No, only the checkout interface is localized. Your product names, descriptions, and other store content remain as you enter them. # Embedded Checkout Source: https://docs.creem.io/features/checkout/embedded-checkout Embed Creem checkout directly in your site β€” as a modal overlay or inline β€” without redirecting customers away. Embedded checkout runs the entire Creem payment flow **inside your own site** instead of sending customers to a hosted page. Drop in a small script, open checkout as a modal or inline iframe, and get a callback when payment completes. Creem embedded checkout as a modal overlay on a merchant's site ## How it works 1. Create a **checkout session** on your server with your secret API key (see [Checkout API](/features/checkout/checkout-api)) and read its `checkoutUrl`. 2. Load the Creem embed script on your page. 3. Open the checkout as an overlay or inline, and handle `onComplete`. You create the session server-side (secret key) and pass the resulting URL to the browser β€” the URL is safe to expose, and completion is always confirmed server-side via webhook. ## 1. Create a checkout session (server-side) Every embed needs a **checkout URL**, created on your server with your secret API key so the price and product can't be tampered with. Use the [Checkout API](/features/checkout/checkout-api) or one of its SDKs and read `checkoutUrl` (the raw REST API returns it as `checkout_url`): ```ts theme={null} // Server-side only β€” keep CREEM_API_KEY secret import { createCreem } from 'creem_io'; const creem = createCreem({ apiKey: process.env.CREEM_API_KEY! }); const checkout = await creem.checkouts.create({ productId: 'prod_YOUR_PRODUCT_ID', successUrl: 'https://yoursite.com/success', // optional }); // `checkoutUrl` is typed as optional in the SDK β€” assert (or guard) it: const checkoutUrl = checkout.checkoutUrl!; // Send `checkoutUrl` to the browser, then embed it (below). ``` Then embed that URL with **a framework SDK**, the **script loader**, or a **raw iframe** β€” pick one. ## 2. Choose an embed path Use exactly **one** of the three paths below β€” framework SDKs, the script loader, or a raw iframe. ### Framework SDKs First-class packages for **React (β‰₯18), Vue (β‰₯3), and Svelte (β‰₯4)** with typed props and lifecycle events. They share a framework-agnostic core, [`@creem_io/embed`](https://www.npmjs.com/package/@creem_io/embed), which you can also use directly in vanilla JS. ```bash npm theme={null} npm install @creem_io/react ``` ```bash yarn theme={null} yarn add @creem_io/react ``` ```bash pnpm theme={null} pnpm add @creem_io/react ``` ```bash bun theme={null} bun add @creem_io/react ``` ```tsx theme={null} import { CreemCheckout, CreemCheckoutInline } from '@creem_io/react'; // Overlay β€” wrap any clickable element console.log('paid', d)}> // Inline β€” mount in place ``` Also available: the `useCreemCheckout()` hook and the `CreemEmbedCheckout.create()` promise API. [Full reference β†’](https://www.npmjs.com/package/@creem_io/react) ```bash npm theme={null} npm install @creem_io/vue ``` ```bash yarn theme={null} yarn add @creem_io/vue ``` ```bash pnpm theme={null} pnpm add @creem_io/vue ``` ```bash bun theme={null} bun add @creem_io/vue ``` ```vue theme={null} ``` Also available: the `useCreemCheckout()` composable and `CreemEmbedCheckout.create()`. [Full reference β†’](https://www.npmjs.com/package/@creem_io/vue) ```bash npm theme={null} npm install @creem_io/svelte ``` ```bash yarn theme={null} yarn add @creem_io/svelte ``` ```bash pnpm theme={null} pnpm add @creem_io/svelte ``` ```bash bun theme={null} bun add @creem_io/svelte ``` ```svelte theme={null} ``` Low-level: the `{@attach}` attachments (Svelte 5.29+) or `use:` actions (Svelte 4). [Full reference β†’](https://www.npmjs.com/package/@creem_io/svelte) Every SDK takes the same options as the loader below (`theme`, `locale`) and emits the same `ready` + `completed` events. On completion the embed behaves exactly like the hosted checkout's return page: * **Product has a Return URL** β†’ a short confirmation screen, then the top window navigates there (\~3s). * **No Return URL** β†’ a "View order" button; the embed stays open until the customer closes it. To keep customers fully inline, call `close()` inside `onComplete` β€” it dismisses the embed **and cancels the pending redirect**. Cancelling the redirect from `close()` requires `@creem_io/embed` β‰₯ 0.3.3 (or `@creem_io/react` / `/vue` / `/svelte` β‰₯ 0.2.3); on older versions `close()` dismisses the modal but the redirect still fires. Embedded checkout success screen: 'Thank you for your payment' with a 'Returning to Merchant in 2s' countdown button Embedded checkout success screen: 'Thank you for your payment' with a 'View Order' button #### Open on click (dynamic sessions) The components above need the `checkoutUrl` at render time. For a **pricing grid** β€” many products, where you don't want to pre-create a session for each one on page load β€” create the session **on demand** and open it imperatively with the `useCreemCheckout()` hook: ```tsx theme={null} import { useCreemCheckout } from '@creem_io/react'; function BuyButton({ productId }: { productId: string }) { const openCheckout = useCreemCheckout(); async function buy() { // Create the session on YOUR server (keeps the secret key off the client), // then open the returned URL β€” no need to pre-create sessions on load. const res = await fetch('/api/checkout', { method: 'POST', body: JSON.stringify({ productId }), }); const { checkoutUrl } = await res.json(); openCheckout({ checkoutUrl, onComplete: (detail) => console.log('paid', detail) }); } return ; } ``` Vue exposes the same `useCreemCheckout()` composable. In vanilla JS (or any framework), use the promise-based `CreemEmbedCheckout.create({ checkoutUrl })`, which resolves once the checkout has rendered. ### Script loader For non-framework apps, or when you want a global `Creem` object. No build step β€” drop in the loader script and open checkout from any framework or plain HTML. #### Overlay ```html theme={null} ``` ```html theme={null} ``` The overlay shows the confirmation screen on success; call `Creem.close()` from `onComplete` to dismiss it β€” this also **cancels the pending redirect** to the Return URL, keeping the customer on your page. #### Inline Mount checkout inside a container on your page: ```html theme={null}
``` **`onComplete` is UX-only.** It fires in the browser and can be spoofed β€” use it to close the modal or show a success state. Grant entitlements / fulfil orders from your **[webhook handler](/code/webhooks)** (verified server-side), never from `onComplete`. #### Declarative data attributes Any element with `data-creem-checkout` opens the overlay on click β€” no JS wiring, but it still relies on the loader script above: ```html theme={null} Buy now ``` Optionally set the theme and language with `data-creem-theme` and `data-creem-locale`: ```html theme={null} Buy now ``` ### Raw iframe The lowest-level option β€” no loader, no SDK. Use it when you only need inline display and will handle the lifecycle yourself, or don't need callbacks: ```html theme={null} ``` The `allow="payment *; publickey-credentials-get *"` attribute is required β€” without it, digital wallets, passkeys, and 3-D Secure challenges can't run inside the iframe. (The framework SDKs and the script loader set this for you.) ## Presentation β€” theme & language Works with the framework SDKs and the script loader. `openCheckout` and `mount` accept two presentation options, appended to the checkout URL for you: ```js theme={null} Creem.openCheckout({ checkoutUrl: 'CHECKOUT_URL', theme: 'dark', // 'light' | 'dark' locale: 'pt-BR', // BCP47 tag β€” forces the checkout language }); ``` By default the checkout follows the customer's **browser language**. Pass `locale` to force a specific one (e.g. to match your own site's language). Unsupported locales fall back to English. See the [supported languages](/features/checkout/checkout-api) for the full list. ## Affiliate attribution If you run the Creem [Affiliate Program](/features/affiliate-program), embedded checkout still credits referred sales to the right affiliate β€” and the SDKs and script loader handle it for you. Here's what happens, and the one edge case worth knowing. **How it works** * An affiliate link (`creem.io/affiliate?code=…`) sends the visitor to your site and appends a `creem_ref` token to the landing URL. * On the **hosted** checkout, attribution rides a first-party cookie on Creem's domain β€” nothing to do. * Inside the **embed**, the checkout runs in a cross-site iframe, so the browser doesn't send that cookie there β€” in any browser. Attribution instead rides the token: the SDK/loader reads `creem_ref` from your page, **persists it in your site's own first-party storage**, and forwards it into the checkout iframe, so it works uniformly everywhere. No code needed for the common case. `creem_ref` is an **opaque, signed token** β€” it identifies the click, not the affiliate. Don't try to parse an affiliate code out of it, and you don't need to read or forward it yourself: the SDKs and loader do it automatically. (It mirrors `client_reference_id` in Stripe-based tools like Rewardful and Tolt.) **Edge case: separate landing and checkout pages** The token arrives on whatever page the affiliate link points to. The SDK captures it automatically when it runs on that page. But if a visitor lands on `/?creem_ref=…`, then **navigates** to another page (say `/pricing`) before opening checkout, and your app drops the query string on that navigation, the token is no longer on the URL. If it wasn't captured before that navigation, attribution is lost β€” in every browser, since the embed relies on the token, not the cookie. To cover this, call `captureAffiliateRef()` once early in your app (e.g. a root layout) so the token is captured on the landing page and stored for later: ```tsx theme={null} // Root layout / top-level component β€” runs on every page 'use client'; import { useEffect } from 'react'; import { captureAffiliateRef } from '@creem_io/react'; // also in /vue, /svelte, /embed export function AffiliateRefCapture() { useEffect(() => { captureAffiliateRef(); }, []); return null; } ``` The **script loader** (`creem.io/embed.js`) captures the token automatically on every page it loads on β€” so if you include the ` ``` This script is essential for Affonso to function. When a user visits your website through an affiliate link, it automatically creates a referral with the status "Visited link" and stores a referral cookie on their device. The script creates a global window\.Affonso object that you'll use in the next step to track successful signups. ```html theme={null} // After successful registration window.Affonso.signup(userEmail); ``` When this function is called, Affonso system will: Create a new referral with status "LEAD" if a valid referral ID cookie exists Make the referral visible in both your and your affiliate's statistics Note: If your platform allows payments without user registration (e.g., direct checkout), you can skip this step and proceed to the next one for payment tracking. Best Practice: Call this function for all signups, regardless of the traffic source. The system will only create referrals when a valid referral ID cookie is present. Place the code: After successful registration for immediate tracking After email verification if you use double opt-in (DOI) For more advanced tracking documentation, or further examples in several languages, visit [Affonso](https://affonso.io) documentation. ## Best Practices * Always test the integration in a development environment first * Implement proper error handling for affiliate tracking * Monitor webhook deliveries and set up retry mechanisms * Regularly verify commission calculations # Evendeals Source: https://docs.creem.io/integrations/evendeals Add purchase parity pricing to your Creem products and boost international conversions. ## Overview [Evendeals](https://www.evendeals.com) is a purchase parity pricing platform that helps you adjust prices based on your customers' location. Combined with Creem's payment processing and tax compliance, you get a complete global sales stack. A single price doesn't work for a global audience. \$49/mo might be reasonable in the US, but it could represent days of work in other countries. Parity pricing consistently drives **20-30% more international sales** by showing location-based discounts to visitors from lower-income regions. How to integrate Evendeals' purchase parity pricing with Creem's payment processing to automatically offer regional discounts and capture revenue from visitors who would otherwise bounce. * A Creem account * An Evendeals account ([sign up free](https://www.evendeals.com/signin)) * Your Creem API keys ## How It Works Evendeals detects your visitor's country, shows a discount banner with a region-appropriate price, and automatically creates and manages discount codes in Creem. When a visitor applies the code at checkout, they pay the adjusted price through Creem's standard checkout flow. **Key features:** * **Automatic discount sync** β€” Discount codes are created and managed in Creem automatically. No manual coupon work. * **Code rotation** β€” Codes rotate by time or view count. Leaked coupons expire automatically. * **VPN detection** β€” Block discount abuse from users masking their real location. ## Integration Steps Five steps, about 10 minutes. ### 1. Create a Creem API key In your [Creem dashboard](https://www.creem.io/dashboard/developers), create an API key with the right permissions. Use **Full access**, or enable Products, Subscriptions, and Transactions read + Discounts read/write. ### 2. Create a webhook in Creem Create a webhook in [Creem Webhooks](https://www.creem.io/dashboard/developers/webhooks), paste the URL from Evendeals, and select all events. Copy the signing secret for the next step. ### 3. Connect in Evendeals Paste your API key and webhook secret in the Evendeals connect dialog. The connection validates instantly. ### 4. Set regional discounts Choose percentage or fixed-amount discounts per country group. Evendeals creates the discount codes in Creem automatically. ### 5. Add the script to your site Add one line of code to your website. Visitors from lower-income countries will see a discount banner and can apply the code at Creem checkout. For detailed step-by-step instructions with screenshots, visit the [Evendeals Creem integration guide](https://www.evendeals.com/integrations/creem). ## Best Practices * Start with conservative discounts (15-25%) and adjust based on conversion data * Test the integration in Creem's test mode before going live * Monitor which regions are driving the most conversions * Review discount redemption rates regularly to optimize pricing tiers ## Resources Detailed setup instructions with screenshots on the Evendeals site. Learn more about purchase parity pricing and sign up. # Framer Source: https://docs.creem.io/integrations/framer Add Creem checkout buttons and pricing tables to your Framer site with a no-code plugin, then style everything on the canvas. ## Overview The [Creem plugin for Framer](https://www.framer.com/community/marketplace/plugins/creem/) lets you add **checkout buttons** and **pricing tables** to any Framer site without writing code. Connect your Creem account, pick your products, and insert a component. The plugin drops a live, fully styleable element straight onto your canvas. Creem acts as your Merchant of Record, so VAT, GST, and sales tax across 190+ countries are calculated, collected, and remitted for you. That makes this pairing a fast way to start selling from a Framer landing page, template, or marketing site. How to install the Creem plugin from the Framer Marketplace, connect your account, insert a checkout button and a pricing table, customize both directly on the canvas, and switch from test mode to live. * A [Creem](https://creem.io/) account * A Framer project (with edit access) ## Install the plugin You can install Creem from the [Framer Marketplace](https://www.framer.com/community/marketplace/plugins/creem/), or use it directly inside your Framer project with the following steps: In your Framer project, open **Canvas** β†’ **Plugins** β†’ **Browse all**. Opening the Plugins menu in Framer Search for **Creem** and install it. Once installed, open the plugin to get started. ## Connect your Creem account When you open the plugin for the first time, you can enter your **Live** Creem Store API Key, **Test** Creem Store API Key, or both, so you can browse either catalog and switch between them at any time. Connect your Creem account in the Framer plugin In the [Creem dashboard](https://www.creem.io/dashboard/developers), go to **Developers** β†’ **API Keys** and copy your keys. Live and test keys are separate (test keys are prefixed with `creem_test_`). Enter a **Store name** so you can tell your stores apart later. Add at least one key. Paste your live key into **Live API Key** and your test key into **Test API Key**. You can add the other environment later. The plugin routes each key to the right environment by its prefix, so a key pasted into the wrong field is flagged. Click **Connect**. The plugin validates the key, loads your products, and drops you into the component picker. Your API keys are stored locally in the plugin and used only to read your product list. They are never embedded in the components you insert onto the canvas. ## Manage stores and switch environments Once connected, the header shows a **store switcher** with the active store's name and a **Live** or **Test** badge. Open it to switch stores, switch environments, or manage your keys. Store and environment switcher in the Framer plugin From the switcher you can: * **Switch environment**: choose **Live** or **Test** for the active store. If that store has no key for the environment yet, you're prompted to paste one inline. Product lists refresh automatically when you switch. * **Switch store**: select any other store to browse its products. * **Add a new store**: connect another Creem account or workspace. * **Rename** or **Remove** a store (you can't remove your only store). * **Sign out**: remove all stores and return to the connect screen. When the active environment is **Test**, the whole plugin gets a peach frame and a **Test mode on** bar at the bottom, the same unmistakable signal as the Creem dashboard. See [Test mode and going live](#test-mode-and-going-live). ## Choose a component After connecting, choose the component to be added to your canvas. Pick a **Checkout Button** for a single product, or a **Pricing Table** to list pricing plans on your page. Choosing between a Checkout Button and a Pricing Table ## Insert a Checkout Button A checkout button helps you sell a single product. It can either open checkout in a new tab or open it in a modal on the same page (the embed version). Search your products and select one. Picking a product advances you straight to configuration. Selecting a product for the checkout button Choose how checkout opens, set the button text, and preview the result. Configuring the checkout button Click **Insert Button**. The button appears on your canvas, ready to style. See [Customize on the canvas](#customize-on-the-canvas) for every option. ## Insert a pricing table A pricing table lists several products side by side. You can mix one-time and subscription products in the same table. Search and select the products to include. Each product becomes its own tier. Selecting products for the pricing table Choose a **Grid**, **Horizontal**, or **Vertical** layout. For a grid, set the number of **Columns** (1 to 5). A live preview reflects your choices. Choosing the pricing table layout and columns Add a **Heading** and **Subheading** for the table. Leave both empty to hide the header entirely. Setting the pricing table heading and subheading Reorder tiers with the up/down arrows, and expand any tier to edit it. Reordering pricing table tiers Each tier has a **Tier Name**, a **Description**, a **CTA Text**, and a **Feature this tier** toggle. The description takes the same Markdown you use for product descriptions in the Creem dashboard: `- item` for a bulleted feature list, plus headings, links, bold or italic text, etc... Editing a pricing table tier Turn on **Feature this tier** to highlight a plan. The featured card gets a stronger border and shadow so it stands out. You can restyle featured cards on the canvas under **Featured Tier**. Click **Insert Pricing Table**. The table appears on your canvas, ready to style. ## Product types and billing intervals The plugin supports every Creem product type and shows the correct price label for each. | Type | Description | Price label | | ---------------- | --------------------------------------- | --------------------------------------------------- | | **One-time** | A single purchase, no recurring billing | No suffix | | **Subscription** | Recurring billing on a set schedule | `/day`, `/month`, `/3 months`, `/6 months`, `/year` | When a pricing table contains **two or more subscription intervals** (for example a Monthly and a Yearly plan), the component automatically shows a billing-interval toggle so visitors can switch between them. One-time products always stay visible. Tables with a single interval show no toggle. Pricing table with a monthly/yearly interval toggle Interval tabs are labeled Daily, Monthly, Quarterly, Semi-annual, and Yearly. You can restyle the toggle (Pill or Segmented, plus colors) on the canvas under **Billing Toggle**. ## Customize on the canvas The plugin inserts each component with sensible defaults, then hands the rest to Framer. Colors, spacing, fonts, button styles, and copy all live in Framer's property panel on the right, so you never reopen the plugin to restyle. Select the component on the canvas and the panel groups its controls by the part of the component they affect. Every change previews live, and the values you set travel with the component when you publish. ### Checkout button controls The button is one group of controls. The plugin fills in the product and a starting style (**CreemCheckoutButton**) at insert time, and everything below is yours to brand. Checkout button property controls in the Framer panel | Control | What it controls, and when to reach for it | | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Variant** | The button's visual style. Seven presets ship: Default (solid fill), Outline, Ghost (text only), Gradient, Shadow, Shimmer (animated sheen), and Icon Slide (an arrow that slides across on hover). All of them use the colors you set below, so choose the shape first and brand it after. | | **Type** | Whether checkout opens as an Embed (a modal over the current page) or in a New Tab. Embed keeps buyers on your site, while New Tab is the safer choice when the button sits inside a restrictive embed or you want a full checkout window. | | **Product ID** | The Creem product this button charges for. The plugin sets it at insert time, so you normally leave it untouched. Edit it only to repoint the button at a different product without re-inserting. | | **Button Text** | The label on the button, such as "Buy now" or "Get the template". Keep it short and action-led. | | **Background** and **Text Color** | The fill and label colors. Defaults are Creem peach on white. Set both to match your brand or the section the button sits in. | | **Radius**, **Font Size**, **Padding X**, **Padding Y** | The button's shape and size. Radius rounds the corners (0 is square), Padding X and Y set the space around the label (its width and height), and Font Size scales the text. | | **Full Width** | Stretches the button to fill its container. Turn it on for full-width calls to action in narrow columns or on mobile. | | **Discount Code** | A Creem discount code applied automatically when checkout opens, so buyers never type it. Handy for launch or campaign buttons that should always carry the offer. | | **Success URL** | Where the buyer lands after paying. Point it at a thank-you or onboarding page to continue the flow, or leave it empty to use the product's default redirect. | Success URLs are optional. When set, they must be valid HTTPS URLs; unsupported or malformed redirect targets are blocked before checkout opens. ### Pricing table controls The pricing table splits its controls into groups (in the **CreemPricingTable** style), one per area of the table, matching the rows in the panel. Pricing table property controls in the Framer panel For an easier editing flow, make sure **Table** shape is as per your requirements, then style the **Card**, then set apart the **Featured Tier** and its buttons. Sets the table's overall shape. **Layout** switches between a Grid, a Horizontal scroll row, and a Vertical stack. For a grid, **Grid Columns** caps how many cards sit per row, while **Min Card Width** and **Grid Gap** decide when cards wrap on smaller screens. **Max Width** stops the table stretching too wide on large monitors, and **Page Background** paints the area behind the cards. Start here to get the structure right before styling anything else. The title and subtitle above the cards, pre-filled from the heading you set when inserting. Toggle the header off to drop it entirely, or set the **Title** and **Description** text, **Alignment** (left, center, right), font sizes, and colors to match your page's typography. The list of plans, one entry per card. Each tier holds its **Name**, **Price**, **Currency**, and billing (a **One-time** purchase or a recurring **Billing Period**), the **Product ID** it charges, the **Button Text** and **Button Variant**, optional per-tier button colors, a Markdown **Description**, and a **Featured** flag. This is where you edit plan copy, correct a price or its interval label, reorder cards, or add and remove tiers after inserting. The Monthly/Yearly switch that appears automatically when the table holds two or more subscription intervals (see [Product types and billing intervals](#product-types-and-billing-intervals)). Choose its **Style** (Pill or Segmented) and its colors, or hide it when you want a single interval on show. The look every card shares: **Background**, **Border**, and **Divider** colors and widths, corner **Radius**, inner **Padding** and **Gap**, the text colors for headings, muted body copy, and links, and the **Title**, **Description**, and **Price** font sizes. Set your neutral card style here, and the featured card inherits it and overrides only its highlighted parts. The extra styling for whichever tier you marked **Featured**, covering its button colors and a heavier border. Use it to make your recommended plan stand out from the standard cards without restyling every card. The default call-to-action style for non-featured tiers: button colors (fill, text, border), **Height**, **Radius**, and **Font Size**. Featured tiers use the **Featured Tier** colors instead, so set the everyday button look here and the highlight there. ## Embed vs. New Tab checkout Both components let you choose how checkout opens. | Option | What happens | | ----------- | -------------------------------------------------- | | **Embed** | Opens checkout in a modal overlay on the same page | | **New Tab** | Opens checkout in a new browser tab | Both options use Creem-hosted checkout at runtime. Test components open the test checkout URL and Live components open the production checkout URL. If Creem or the visitor's network is temporarily unavailable, checkout cannot open or complete until connectivity is restored. Creem embed checkout modal Checkout opens on your published site, not on the Framer canvas. Publish or preview your site to test the full flow. ## Test mode and going live Test mode lets you build and preview without real charges. Switch a store to **Test** in the [store switcher](#manage-stores-and-switch-environments) to browse your test catalog. A peach frame and a **Test mode on** bar make it obvious you're in test. The environment is captured on each component **at insert time**. A component inserted while you're in Test opens test checkout, and one inserted in Live opens live checkout. Switching a store's environment does **not** retroactively change components you already inserted. When you're ready to go live, switch the store to **Live** in the switcher and **re-insert** your buttons and tables so they point at your live products. **Unconfigured products are blocked, not broken.** If a button or tier's **Product ID** is still the placeholder (`prod_abc123`) or left empty, most often after adding a tier by hand in the property panel instead of through the plugin, its checkout is blocked and the visitor sees an "isn't available yet" message rather than a broken checkout. Fix it by setting a real **Product ID** on that tier or button (copy the ID from your product in the Creem dashboard), or re-insert the component through the plugin to pull in a valid product. ## Troubleshooting Inserting writes a code file and drops a component onto the canvas, which both need edit access. Ask the project owner for edit permission on the Framer project. Framer is still building the component's code file. Wait a moment and click Insert again. That tier or button's **Product ID** is still the placeholder (`prod_abc123`) or empty, usually from adding a tier directly in the property panel. Set a valid **Product ID** on it (copy the ID from your product in the Creem dashboard), or re-insert the component through the plugin to select a product from your list. The plugin lists active products. Make sure the product is active in your Creem dashboard, then use the refresh button in the plugin to re-sync. ## Resources Install the plugin and view its listing. Deliver a private remix link automatically after purchase. React to payments with verified webhook events. Get your first API key and create a product. # Strapi Source: https://docs.creem.io/integrations/strapi Manage Creem products and checkout directly from your Strapi 5 admin panel. ## Overview [Strapi](https://strapi.io/) is a leading open-source headless CMS for structuring content and building flexible APIs. The [`@creem_io/strapi`](https://www.npmjs.com/package/@creem_io/strapi) plugin brings Creem's billing capabilities directly into your Strapi 5 admin panel, so you can create products, configure checkout, and receive verified webhooks without leaving your CMS. Creem acts as the legal seller of record. VAT, GST, and sales tax across 190+ countries are calculated, collected, and remitted for you, making this pairing especially useful when your Strapi project is the operational hub for a product you sell globally. How to install and configure the Creem plugin for Strapi 5, manage products from the Strapi admin, wire up a front-end checkout through Strapi's content API, and receive verified Creem webhook events. * A [Creem account](https://creem.io/) with at least one API key * A Strapi 5 project (or create one during this guide) * Node.js v22 or later ## Create a Strapi project Open your terminal and scaffold a new Strapi project with their CLI: ```bash theme={null} npx create-strapi@latest my-strapi-app ``` When prompted, configure the CLI options (such as database setup) according to your preferences. Once that is done, move into the project directory and start the app in development mode by executing the following command: ```bash theme={null} cd my-strapi-app npm run develop ``` The Strapi admin panel will be available at `http://localhost:1337/admin`. Complete the initial registration so you can sign in after installing the plugin. ## Install the Strapi plugin To install the plugin, run the following command: ```bash theme={null} npm i @creem_io/strapi ``` Then, restart Strapi instance after installation: ```bash theme={null} npm run develop ``` After restarting, you should see the Creem plugin appear in the left sidebar. Strapi admin home with Creem plugin in the sidebar ## Configure environment variables ### API Keys Get at least one API key from the [Creem dashboard](https://creem.io/dashboard) under **Developers**. Test and production keys are separate; test keys are typically prefixed with `creem_test_`. | Variable | When you need it | | --------------------------- | ------------------------------------------ | | `STRAPI_CREEM_TEST_API_KEY` | Test Mode (`https://test-api.creem.io/v1`) | | `STRAPI_CREEM_API_KEY` | Production (`https://api.creem.io/v1`) | ### Webhook Secret (optional) | Variable | Purpose | | ----------------------------- | ---------------------------------------------------------------------------------------------- | | `STRAPI_CREEM_WEBHOOK_SECRET` | Signing secret from **Developers β†’ Webhook** so Strapi can verify the `creem-signature` header | Once obtained, add these variables to your Strapi project's `.env`: ```bash theme={null} # API Keys STRAPI_CREEM_TEST_API_KEY="creem_test_..." STRAPI_CREEM_API_KEY="creem_..." # Webhook Secret STRAPI_CREEM_WEBHOOK_SECRET="..." ``` Restart your Strapi project for changes to take effect: ```bash theme={null} npm run develop ``` ## Access the plugin Open the admin panel again and then open **Strapi 5 Plugin for Creem** in the left sidebar. Creem plugin products page, empty initial state When you first open the Creem panel, it fetches and displays all products from [the Creem API](https://docs.creem.io/api-reference/endpoint/search-products). You can then manage these products directly within your Strapi instance. ## Manage products Click **+ New Product** to open the create form. Create product modal in the Strapi Creem plugin Supported options include: * **One-time** and **subscription** products (including free products with price `0`) * **Billing interval** for subscriptions (daily, monthly, every 3 months, every 6 months, yearly) * **Currency** selection (USD or EUR) * The list view excludes archived products **Edit** and **archive** open the [Creem dashboard](https://www.creem.io/dashboard) directly. The Creem API does not support those operations through this plugin yet. ## Front-end checkout The Strapi plugin exposes a checkout route through Strapi's [Content API](https://docs.strapi.io/cms/api/content-api). ``` POST /api/@creem_io/strapi/checkout ``` Checkout integration modal with embed snippet and JavaScript Your front end talks to **Strapi**, not directly to Creem, so API keys never reach the browser. The server creates a Creem checkout session and returns `{ "url": "..." }` for redirect. **Example request body:** ```json theme={null} { "productId": "prod_abc123", "customer_email": "customer@example.com", "success_url": "https://your-site.com/success", "metadata": { "order_id": "ORDER_123" } } ``` The plugin also generates a ready-to-use **embed snippet** per product. Copy it from the product's embed dialog and drop it into your site with no extra dependencies. ## Configure environment and webhook forwarding To configure the environment and webhook forwarding settings in Strapi, open the Strapi admin sidebar and click on **Settings**. Settings entry in the Strapi admin sidebar Click on **Configuration** within the Creem section to open the configuration panel for the plugin. Creem Configuration under Settings in the Strapi admin On this page, you'll be able to set the environment, default checkout success URL, and webhook forwarding options. Creem plugin Configuration page | Setting | Description | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Environment** | Choose **Test mode** or **Production**. Only environments with a matching `.env` key are selectable. | | **Checkout success URL** | Default redirect after checkout. Per-request `success_url` is used when this is empty. Must be HTTPS in production. | | **Webhook forward URL** | After HMAC-SHA256 verification, the plugin POSTs the parsed event JSON to this URL. Useful for provisioning access, updating user records, or triggering email automation. | ## Register the webhook in Creem 1. In the [Creem dashboard](https://creem.io/dashboard), go to **Developers β†’ Webhook**. 2. Add your public HTTPS endpoint: **Production / staging:** ``` https://your-deployed-strapi-instance.com/api/@creem_io/strapi/webhook ``` **Local development** (Creem cannot reach `localhost` directly, so expose your local Strapi with a tunnel first): ```bash theme={null} ngrok http 1337 ``` Then use the tunnel URL: ``` https://abcd.ngrok.io/api/@creem_io/strapi/webhook ``` 3. Copy the signing secret and set `STRAPI_CREEM_WEBHOOK_SECRET` in your Strapi `.env`. 4. Restart Strapi. The plugin responds with **HTTP 200** on successful verification. If a **Webhook Forward URL** is configured, the verified payload is forwarded there automatically. Forwarded Creem webhook event received at a webhook forward URL See the [Creem webhooks guide](/code/webhooks) for all supported events (`checkout.completed`, `subscription.active`, `subscription.paid`, `subscription.canceled`, `refund.created`, and more). ## Resources Install the plugin and view release history. Signature verification, event types, and payload examples. Strapi's REST content API reference. Get your first API key and create a test product. # Account Reviews Source: https://docs.creem.io/merchant-of-record/account-reviews/account-reviews Learn how account reviews work on Creem and what you need to get approved. Before you can accept live payments through Creem, your store needs to pass an account review. This page gives you the core checklist. If you need next-step guidance after a rejection, use the [Re-Review Guide](/merchant-of-record/account-reviews/re-review-guide). If you're building an AI image or video product, also read [AI Wrapper Compliance](/merchant-of-record/account-reviews/ai-wrapper-compliance). The fastest approvals happen when your product is already live, your legal pages are visible, and your support email matches what appears on your website. ## Approval checklist | Requirement | Details | | ------------------------------------- | -------------------------------------------------------------------------------------------------------- | | **Product is live** | Your product is ready for production. Still building? Use [Test Mode](/getting-started/test-mode) first. | | **No false information** | No fake reviews, testimonials, or inflated user/customer counts on your website. | | **Privacy Policy & Terms of Service** | Both legal pages must be present and accessible on your website. | | **Product clearly visible** | We must be able to understand what you're selling from your website or landing page. | | **No trademark conflicts** | Your product name must not infringe existing trademarks or create customer confusion. | | **Pricing is visible** | Pricing must be clearly displayed and easy for users to find. | | **Acceptable use** | No high-risk, shady, or illegitimate use cases. | | **Customer support email** | A reachable support email must be set up and shown on your website and receipts. | | **Moderation API** | AI image/video generation products must integrate the [CREEM Moderation API](/features/moderation). | | **Not on prohibited list** | Your product must not fall under our [prohibited product list](#prohibited-products). | ## Review process ### How long does the review take? Account reviews are typically completed within **24-48 hours**. During peak periods, it may take up to 72 hours. You'll receive an email notification once the review is complete or if changes are requested. ### What happens after the review? * **Approved** - Your store can start accepting live payments. * **Changes requested** - Fix the flagged issues, then use the **Request re-review** button on the **Balance β†’ Payout Account** page. Step-by-step guide for fixing issues and using the Request re-review button. ### Where do I start the review? Go to **Balance β†’ Payout Account** and click **Set up Payout Account** to submit your details. Creem Balance page showing Payout Account tab with test mode notice ### What information is needed? * Your full individual name and/or your business entity name * Your store or product name * The product URL of your store * A description of your business and how you operate * A description of the products you intend to sell through Creem * Your country of tax residence ### Common reasons for requests for changes 1. **Support email mismatch** - The email in your Business Details doesn't match what's on your website. 2. **Website not accessible** - Your site is down, password-protected, or returning errors during review. 3. **Missing legal pages** - Your website needs a Privacy Policy and Terms of Service. 4. **False information** - Fake reviews, testimonials, or inflated user counts on your website. 5. **Product not ready** - If your product isn't live yet, use [Test Mode](/getting-started/test-mode) until it's ready. 6. **AI compliance issues** - AI image/video products are missing moderation, AUP, or clear product disclosures. What to fix and how to request another review. Extra rules for AI image and video generation products. ## Why do we review accounts? We review accounts to ensure stores are legitimate and in compliance with our terms. This helps prevent fraud, misuse, malicious activity, and high-risk accounts. ## Product guidelines ### Acceptable products We allow digital goods that can be fulfilled through Creem. Examples include: * Software & SaaS * eBooks * PDFs * Design assets * Photos * Audio * Video ### Prohibited products If you attempt to sell prohibited products or violate our terms, your account may be placed in review or suspended. * Sexually-oriented or pornographic content of any kind, including AI-generated content and NSFW chatbots * Face-swap, deepfake, and face-manipulation tools of any kind * IPTV services * Physical goods of any kind * Spyware or parental control apps * Donations or charity giving where no product exists or where the price is greater than the product value * Products or content for which you do not hold a proper license or intellectual property rights * Third-party content downloaders and rippers that violate platform Terms of Service * Marketplaces where you use your Creem store to partner to sell others' products * Dating sites * PLR or MRR products where you do not hold the original IP rights * Counterfeit goods * Illegal or age-restricted products such as drugs, alcohol, tobacco, vaping products, or weapons * Regulated services such as gambling, lending, telemarketing, debt relief, or banking/financing services * Timeshares * Pharmacies, pharmaceuticals, and nutraceuticals * Homework/essay mills * Multi-level marketing, pyramid, or IBO schemes * NFT & crypto asset products * In-game items, currencies, and virtual goods tied to third-party games * Any other products that our providers and partners deem too risky ### Restricted products * Services of any kind, including marketing, design, web development, consulting, and similar work * Job boards * Advertising in newsletters, on websites, or in social media posts * API resellers. We can only support established resellers, who must provide their previous payment processor, chargeback rate (with screenshots of the rate and transaction volume), and reason for moving to Creem. If you are unsure whether your content is prohibited, contact Creem support with a description or example before you start selling. ## Customer experience and support Providing excellent customer support is a core requirement for all merchants on Creem. * **A visible support email is mandatory.** This email must be accessible on your public website and within the user dashboard. * **Use a branded support email.** If your product is `MintAI`, your support email should be `support@mintai.com`, not a generic address. * **Users must be able to cancel subscriptions directly from your product.** You can do this via the Cancel Subscription API or by redirecting users to the Creem Customer Portal. * **Respond to customer requests within 3 business days.** If you do not respond within that timeframe, Creem may issue a refund on your behalf. # AI Wrapper Compliance Source: https://docs.creem.io/merchant-of-record/account-reviews/ai-wrapper-compliance Extra review requirements for AI image and video generation products on Creem. AI image and video generation products have extra compliance requirements on top of the standard [Account Reviews](/merchant-of-record/account-reviews/account-reviews) checklist. Failure to comply with these policies can result in your payment processing being restricted or suspended. ## Branding and naming Your product's brand identity must be distinct from the underlying AI models it uses. ### Not allowed * Using AI model brand names directly in your product name, such as `VEO3Studio` or `GeminiVideo` * Creating branding that implies affiliation with the model creator when there is none ### Required * Use independent branding for your product. Choose a name that is unique and does not directly reference the AI models. Examples of compliant names include `MintAI`, `RenderZen`, or `SlateVidAI`. * If you mention supported models in your app or marketing, make it clear they are integrations, not your brand * SEO-focused domains are fine if they redirect to your properly branded main site ## Transparency and marketing Be explicit about what your product is and what it does. * Clearly explain that your platform is an independent wrapper or interface built on top of third-party AI models * Advertise only the features you actually deliver * If you mention model names in ads or marketing, include a disclaimer that your product is not affiliated with or endorsed by the model creators **Example disclaimer:** `This platform is an independent product and is not affiliated with Google. We provide access to the VEO3 model through our custom interface.` ## Moderation API requirement If your product generates images or videos from user prompts, you must integrate the [CREEM Moderation API](/features/moderation). This requirement applies to AI **image and video generation** products only. It does not apply to image upscaling, background removal, audio/music generation, text generation, or other non-generative use cases. Full integration guide, endpoint reference, code examples, and go-live checklist. If users type a text prompt and your product generates an image or video from it, you need the Moderation API. ## Content policy requirements Even with the Moderation API integrated, the following are still not allowed on CREEM: * Gallery or showcase content featuring suggestive, borderline, or sexually provocative material * Marketing that uses terms like `uncensored`, `no filter`, `NSFW`, `18+`, or `unfiltered generation` * Face-swap, deepfake, and face-manipulation tools ### Additional required policies Your site must include: * A visible **Acceptable Use Policy** that explicitly prohibits NSFW and harmful content generation * Terms of Service that explicitly prohibit NSFW, explicit, or sexually suggestive content generation * Clear user-facing language about what is and is not allowed CREEM conducts ongoing compliance monitoring and may test AI generation outputs at any time. Merchants are responsible for the content their product enables users to generate. ## Before you request review or re-review Make sure all of the following are true: 1. Your product is live and accessible 2. Your branding is independent from model brand names 3. Your site includes Terms of Service, Privacy Policy, and Acceptable Use Policy 4. Your Moderation API integration is active in production 5. Your marketing does not promise "uncensored" or prohibited output If you were already flagged, use the [Re-Review Guide](/merchant-of-record/account-reviews/re-review-guide) after making the required changes. # How to Request a Re-Review Source: https://docs.creem.io/merchant-of-record/account-reviews/re-review-guide Your account review came back with changes requested. Here is exactly what to do next. If your account review comes back with **Changes Requested**, don't start from scratch. Fix the flagged issues, then request a re-review from your dashboard. Re-reviews are requested from **Balance β†’ Payout Account** using the **Request re-review** button. If you need help or the feedback is unclear, contact [Creem support](https://creem.io/contact) and include your Store ID. ## Step 1 - Review the feedback Read the review feedback carefully and make a checklist of every issue you need to fix before requesting another review. The most common requests, and how to fix them: | Re-review reason | What to do | | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | **Missing or inaccessible legal pages** | Add a Privacy Policy and Terms of Service to your website. Both must load without authentication. | | **Support email mismatch** | Update your email in **Settings β†’ Business Details** to match what is shown on your website. | | **Moderation API not integrated** | See the [full integration guide](/features/moderation). Your integration must be running in production, not just sandbox. | | **Product not live** | Your product must be accessible and functional - not a placeholder or "coming soon" page. | | **Missing Acceptable Use Policy (AI products)** | Add an AUP to your website that explicitly prohibits NSFW and harmful content generation. | | **Website inaccessible during review** | Remove any password protection, maintenance mode, or bot wall that blocks the review team. | | **NSFW or "unfiltered" marketing language** | Remove terms like "uncensored," "no filter," "NSFW," or "18+" from your website, marketing pages, and product UI. | For AI image and video generation products, the most common failure is that the Moderation API is integrated in sandbox mode only, not in production. See [Verify your integration is live](/features/moderation#verify-your-integration-is-live). ## Step 2 - Find your Store ID You will need your Store ID whenever you contact support about a review. Go to **Settings** in your dashboard. Your Store ID starts with `sto_` and is displayed at the top of the page. Save your Store ID somewhere handy. Leading with it makes support much faster. ## Step 3 - Request the re-review Once you've made the required changes: 1. Go to **Balance β†’ Payout Account** 2. Review the **Changes Requested** card 3. Click **Request re-review** 4. If needed, contact [Creem support](https://creem.io/contact) with your Store ID and a short summary of what changed Balance page showing the Request re-review button ## What happens next Re-reviews are typically completed within **24-48 hours**. During peak periods, it may take up to 72 hours. During the re-review, the team will: * Verify the changes you made are live on your website * For AI products: check that your Moderation API integration is active in production * Confirm no new issues were introduced If more changes are still needed, you'll get another request with specific feedback. ## Common questions Usually this means one or more changes were incomplete, not visible to the review team, or new issues were introduced. Double-check the exact feedback and make sure every fix is live before requesting another review. This is usually caused by maintenance mode, password protection, Cloudflare bot protection, or a regional access block during the review window. Remove those restrictions before requesting a re-review. Yes. If the feedback is unclear, contact [Creem support](https://creem.io/contact) with your Store ID and ask what needs to change before clicking the button. ## Related Full checklist and review requirements. Extra requirements for AI image and video products. # Payments Source: https://docs.creem.io/merchant-of-record/finance/payment-methods What happens when a payment is processed through Creem ## Benefits Creem democratizes SaaS financial operations by serving as your merchant of record, enabling immediate payment acceptance, handling all the headaches with tax compliance, VAT requirements, and fraud prevention, while supporting global transactions with competitive, transparent pricing. ## Merchant of Record As your merchant of record, Creem eliminates the complexities of managing international sales and compliance. We handle all the intricate details of tax collection, VAT requirements, and regulatory compliance, allowing you to focus on growing your business while we manage the financial backend. Our commitment to transparency means no hidden fees or surprise charges - just clear, competitive rates that help you scale confidently. Learn what is a Merchant of Record, and how that can help your business In essence, you can focus entirely on growing your business while we meticulously handle every aspect of your financial operations, ensuring seamless transactions across borders. Your business will appreciate our highly competitive rates and straightforward fee structure, making international expansion more accessible than ever. ## Payment Methods Creem supports a wide range of payment methods to help you reach customers globally. Below is a list of currently supported payment methods, though this is not exhaustive as we are constantly working to add new options to our capabilities. You can expect new payment methods to be added frequently. ### Currently Supported Payment Methods * Credit Cards * Apple Pay * Google Pay The payment methods displayed on a checkout page vary significantly based on several factors: - The type of product (One-Time Payment vs Subscription) - Your customer's location - Your customer's billing address - The price of your product - The device your customer is using to access the checkout page We automatically optimize the checkout experience to show the most relevant payment methods for each customer, increasing conversion rates and providing a seamless payment experience. Accept payments from customers worldwide with localized payment methods. We show the right payment methods to the right customers at the right time. ## Learn more about Creem Finance operations Create customers and subscriptions, manage your products, and much more. Check out our guides to get the most out of Creem. Receive payments without any code or integration. Create checkout sessions dynamically in your app # Payout Accounts Source: https://docs.creem.io/merchant-of-record/finance/payout-accounts How to set up, change, and manage your payout accounts on Creem. ## Setting Up a Payout Account Before you can receive payouts, you need to add a payout account: 1. Go to **Balance** β†’ **Payout Account** in your dashboard 2. Complete your **KYC/KYB verification** (identity and/or business verification) 3. Add your bank account or crypto wallet details 4. Wait for Creem team approval Creem Balance page showing balance summary and payout options The full onboarding flow is: **Business Details** β†’ **KYC/KYB Verification** β†’ **Payout Account Setup** β†’ **Account Review by Creem Team** β†’ **Live Payments Enabled**. ## Available Payout Methods | Method | Details | | --------------------------------- | ----------------------------------------------------------------- | | **Bank Transfer** | \$7 or 1% of payout (whichever is higher) | | **Stablecoin (USDC via Polygon)** | 2% of payout volume | | **Alipay** | Available for China-based merchants (up to 50,000 CNY per payout) | For full fee details, see [Payouts](/merchant-of-record/finance/payouts). ## Changing Your Payout Account To change your bank account or payout method: 1. Go to **Balance** β†’ **Payout Account** in your dashboard 2. Add your new bank account or wallet details 3. Set the new account as your **default payout method** ## Setting a Default Payout Account If you have multiple payout accounts connected, make sure to set the correct one as your **default**: 1. Go to **Balance** β†’ **Payout Account** 2. Click on the payout method you want to use 3. Set it as the default Payouts will always be sent to the default account. ## Multiple Stores If you have multiple Creem stores, each store has its own payout account settings. You can use the same bank account across stores, but you'll need to configure it in each store separately. ## Common Issues After submitting your payout account, our compliance team reviews it within 24-48 hours. If it's been longer, contact support with your Store ID. Add the new payout method in your dashboard and set it as default. Your next payout will use the new method. Payouts are processed in the currency of your registered bank account. If it differs from the currency you charge in, a conversion fee from our banking partners will apply automatically. # Payouts Source: https://docs.creem.io/merchant-of-record/finance/payouts How payouts from Creem work. ## Fees and Payout Schedule Get familiar with the fees and payout schedule associated with using Creem. ## Platform Fee When you make a sale using Creem, we take a small fee, known as the "platform fee", to cover the costs of credit card transaction fees, currency conversion fees, taxes (yes, we cover taxes) etc. The net sales will be paid out to your bank account. [Learn more about our pricing](https://www.creem.io/pricing). The platform fee is calculated on the total order value and collected when the order is placed. Here's an example breakdown where someone in France (20% VAT) buys a digital product with a card. | Description | Amount | | --------------------------------------- | ------- | | Product price | \$20.00 | | Tax (20% VAT) | \$4.00 | | Total | \$24.00 | | Platform fee (3.9% + 0.40c) | \$1.33 | | Net profit (total - tax - platform fee) | \$18.67 | ## Additional Product Fees Certain products and features incur additional fees beyond the standard platform fee. These fees are applied before any commission calculations and affect your final payout amount. ### Splits Payment Functionality When using Creem's splits payment feature, an additional **2% fee** is applied to the transaction amount before any commission is distributed to the participating parties. **Example:** * Transaction amount: \$100.00 * Splits fee (2%): \$2.00 * Amount available for splits: \$98.00 * Commission distribution is then calculated on the \$98.00 ### Affiliate Marketing Platform When a transaction is processed through Creem's Affiliate Marketing platform, an additional **2% fee** is applied to the transaction amount. This fee covers the infrastructure and tracking capabilities that power the affiliate system. **Example:** * Transaction amount: \$100.00 * Affiliate platform fee (2%): \$2.00 * Amount after affiliate fee: \$98.00 * Affiliate commission is then calculated on the \$98.00 ### Abandoned Cart Recovery For transactions recovered through abandoned cart functionality, an additional **5% fee** is applied to the recovered transaction amount. **Example:** * Recovered transaction: \$50.00 * Recovery fee (5%): \$2.50 * Net amount after recovery fee: \$47.50 * Platform fee is then calculated on the \$47.50 These additional fees help cover the specialized infrastructure and processing costs associated with these advanced features. ## Payout Fees Creem charges 7 USD/EUR or 1% of the payout amount, whichever is higher, to cover bank transfer costs. Conversion rates are automatically applied by our banking partners if your registered bank account uses a different currency than the one you charge customers in. In that case, a small conversion fee from our Partners will be applied, which is outside of our control. ### Stablecoin Payouts (USDC via Polygon) Creem also supports payouts in USDC using the Polygon Network. This allows you to receive your funds quickly and securely in stablecoins, directly to your compatible wallet address. * Supported stablecoin: **USDC** * Network: **Polygon** * Fee: **2% of the payout volume** To use this option, ensure your wallet supports USDC on Polygon. When registering a payout account, select the stablecoin payout method and provide your wallet address. The payout will be processed in the next available payout window, subject to the 2% fee. ## Payout Schedule Payouts are always executed twice per month: * On the 1st day of the month * On the 15th day of the month To be eligible for a payout, you need to achieve a minimum balance of 50 USD or 50 EUR. Once you reach this threshold, the "withdraw" button will be enabled for you on your balance page. When you click on the withdraw button, your store will be automatically added to our payout schedule queue, and your payout will be executed on the next available window (1st or 15th of the month). After the payout is processed, you will see a new payout item on the payout activity tab of your balance page, with a reverse invoice available for download for tax purposes. If the payout day falls on a weekend or a public holiday, delays might occur due to our banking partners, and the payout will be executed on the next business day. ## Transfer Limits Creem is actively working to increase the number of banking partners it operates with. At the moment, some countries have transfer limits or bank transfer partner restrictions. For the current country-by-country list, see [Supported Countries](/merchant-of-record/supported-countries). ### China * Individual recipient: Alipay * Business recipient: Local Bank Account Receiving via Alipay: You can receive up to 50,000 CNY per payout and between 300,000β€”600,000 CNY per year Receiving via Local Bank account: Unlimited ## Important Note on Payout Availability Please note that if you have applied for a payout, we will only be able to execute your available balance on that date. Payments may be held for 7-12 days for risk assessment before they become available for payout. For example, if you are getting your payout executed on the 15th, only funds that were processed via payments before the 8th day of the calendar month will be available for withdrawal on that specific payout. ## What to do if your payout fails If a payout fails and is returned to your balance, the issue is usually one of these: ### Bank account issue We tried to send the payout to your selected payout instrument, but the bank could not process it. Please make sure: * your bank account details are correct * the bank account can receive international payments * your default payout account is the one you want us to use for the next payout If setting up a bank account is difficult in your region, we also support **USDC payouts**. ### Identity mismatch There is a mismatch between your selected payout instrument and the identity you onboarded with, so we cannot release the payout. For your next withdrawal: * if you onboarded as a **business**, the payout account must be a business account and the beneficiary name must match the onboarded business entity * if you onboarded as an **individual**, the payout account must be an individual account and the beneficiary name must match your KYC identity ## Managing Your Payout Account For information on setting up, changing, or managing your payout accounts, see [Payout Accounts](/merchant-of-record/finance/payout-accounts). # Refunds and Chargebacks Source: https://docs.creem.io/merchant-of-record/finance/refunds-and-chargebacks How Creem handles refunds and chargebacks. Creem empowers sellers with the flexibility to establish their own refund policies while maintaining the right to process refunds within 60 days to prevent chargebacks. ## Refunds At Creem, we believe in giving sellers the autonomy to determine refund policies that align with their business objectives and requirements. If you opt to offer refunds, they can be processed at any time through the Creem dashboard. The refunded amount will be deducted from your upcoming payout. **Refund Fees:** Creem does not charge any fees for processing refunds. However, the original transaction processing fees remain charged against your merchant balance in case of a refund, as these are transaction processing costs that Creem itself pays to our providers and partners. However, to protect against chargebacks, Creem reserves the right to issue refunds within 60 days of purchase at our discretion. Even if you maintain a "no refunds" policy, please note that customers retain the ability to initiate chargebacks against their purchases at any time. ## Chargebacks A chargeback (also known as a charge reversal or dispute) occurs when a customer requests their credit card provider to reverse a charge on their statement. These disputes can arise for various reasons, with fraud being a common trigger. As part of our commitment to transparent financial operations, Creem takes responsibility for managing chargebacks against your sales. When a chargeback occurs, we typically process a full refund on your behalf, deducting the refunded amount. **Chargeback Fees:** A fee of 25 USD/EUR is charged for each chargeback. It is important to note that this fee is due to the providers and partners that Creem uses, and that Creem does not profit from such fees. We always do our best to avoid such occurrences. Common reasons for chargebacks include: * **Fraudulent transactions using stolen credit card information, leading to charge cancellation by the credit card provider** * **Customers failing to recognize the charge on their statement and requesting a reversal** * **Customers disputing product delivery and bypassing the refund process by directly contacting their credit card provider** In the event of a chargeback, Creem will provide comprehensive information to the payment provider to advocate on your behalf. However, our involvement is limited by legal constraints, and the final decision rests with the payment provider. To maintain the integrity of our platform and protect all users, Creem may take action, including account suspension, if a store experiences an excessive number of chargebacks. # Supported Countries Source: https://docs.creem.io/merchant-of-record/supported-countries Creem supports merchants and affiliates in hundreds of countries. Find out if your country is supported for payouts and purchases. Creem supports purchases from all countries except those in the [unsupported list](#unsupported-countries-for-purchases) below. We provide payouts to merchants in **86 countries**. If you don't see your country listed below, sorry, you won't be able to use Creem at this time. We are always expanding our region support, and would love to hear from you. ### Payout Methods Available in **all 86 supported countries**. Payout fee: 7 EUR/USD or 1% of the payout amount, whichever is higher. Some countries have Wise transfer restrictions, listed below. ### Supported Countries (86) | Country | Local Bank | | :------------------------------------------------------------- | :-------------------: | | Albania | | | Andorra | | | Argentina | | | Australia | | | Austria | | | [Bangladesh\*\*](#bank-transfer-partner-restrictions) | | | Belgium | | | Bosnia and Herzegovina | | | Brazil | | | Bulgaria | | | Canada | | | Cayman Islands | | | Chile | | | [China\*](/merchant-of-record/finance/payouts#transfer-limits) | | | [Colombia\*\*](#bank-transfer-partner-restrictions) | | | Costa Rica | | | Croatia | | | Cyprus | | | Czech Republic | | | Denmark | | | Dominican Republic | | | Egypt | | | Estonia | | | Finland | | | France | | | Georgia | | | Germany | | | Gibraltar | | | Greece | | | Guatemala | | | Hong Kong | | | Hungary | | | Iceland | | | India | | | Indonesia | | | Ireland | | | Israel | | | Italy | | | Japan | | | Kenya | | | Latvia | | | Liechtenstein | | | Lithuania | | | Luxembourg | | | Malaysia | | | Malta | | | Mexico | | | Moldova | | | Monaco | | | Montenegro | | | Morocco | | | [Nepal\*\*](#bank-transfer-partner-restrictions) | | | Netherlands | | | New Zealand | | | Nigeria | | | North Macedonia | | | Norway | | | [Pakistan\*\*](#bank-transfer-partner-restrictions) | | | Peru | | | Philippines | | | Poland | | | Portugal | | | Romania | | | San Marino | | | Serbia | | | Singapore | | | Slovakia | | | Slovenia | | | South Africa | | | South Korea | | | Spain | | | Sri Lanka | | | Sweden | | | Switzerland | | | Taiwan | | | [Tanzania\*\*](#bank-transfer-partner-restrictions) | | | Thailand | | | Turkey | | | [Ukraine\*\*](#bank-transfer-partner-restrictions) | | | United Arab Emirates | | | United Kingdom | | | United States of America | | | Uruguay | | | Vietnam | | | Zambia | | ### Bank Transfer Partner Restrictions Some local bank payouts are subject to additional restrictions from our bank transfer partner. Countries marked with a double asterisk (\*\*) in the table above may have restrictions that affect payouts - for example, only individual (personal) bank accounts being supported, or business transfers not being available. These restrictions come from our bank transfer partner and may change over time. For the most up-to-date, country-specific details, please check the partner's [live availability page](https://wise.com/help/articles/2571942/what-countriesregions-can-i-send-to). ### Unsupported Countries for Purchases

We cannot accept payments from customers or Merchants in the following countries:

  • Afghanistan
  • Antarctica
  • Belarus
  • Burma (Myanmar)
  • Central African Republic
  • Cuba
  • Crimea (Region of Ukraine)
  • Democratic Republic of Congo
  • Donetsk (Region of Ukraine)
  • Haiti
  • Iran
  • Kherson (Region of Ukraine)
  • Libya
  • Luhansk (Region of Ukraine)
  • Mali
  • Netherlands Antilles
  • Nicaragua
  • North Korea
  • Russia
  • Somalia
  • South Sudan
  • Sudan
  • Syria
  • Venezuela
  • Yemen
  • Zaporizhzhia (Region of Ukraine)
  • Zimbabwe
# What is a Merchant of Record Source: https://docs.creem.io/merchant-of-record/what-is What is a Merchant of Record (MoR)? Learn how Creem handles global tax compliance, payment processing, and SaaS billing as your MoR partner. A merchant of record (sometimes shortened to β€œMoR”) is a legal entity that takes on the responsibility of selling goods and services to end customers, handling everything from payments to compliance. ## What is a Merchant of Record? A Merchant of Record (MoR) is the legal entity responsible for selling goods or services to end customers. When customers make a purchase through Creem, they are technically buying from us as the Merchant of Record. This means we handle all aspects of the transaction, including payment processing, sales tax collection, refund management, chargeback handling, etc. ## Is Creem a Merchant of Record? Yes! Creem acts as your Merchant of Record, taking on all the complex financial and legal responsibilities so you can focus on what matters most - building and growing your SaaS business. We handle: * **Payment processing and tax compliance across different markets** * **Management of refunds and chargebacks** * **Sales tax collection and remittance** ## Frequently Asked Questions A Merchant of Record (MoR) is the legal entity responsible for selling goods or services to end customers. The MoR appears on customer bank statements and invoices, and is responsible for all tax collection, remittance, and regulatory compliance. When you use Creem as your MoR, we handle all of this complexity so you can focus on building your product. A payment processor (like Stripe) only handles the technical side of moving money. You remain the seller of record and are responsible for tax compliance, refunds, and regulatory issues. A Merchant of Record like Creem takes on the legal responsibility of being the seller, handling VAT/GST collection, tax remittance, compliance, and customer disputes on your behalf. If you sell to customers globally, you face complex tax requirements in 190+ countries. Each jurisdiction has different VAT/GST rates, registration thresholds, and compliance rules. A MoR handles all of this automatically, letting you sell globally without setting up legal entities or tax registrations in every country. Yes! Creem automatically calculates and collects the correct VAT, GST, or sales tax based on your customer's location. We handle tax remittance to authorities in 190+ countries, provide compliant invoices to your customers, and manage all tax reporting requirements. ## Further reading Want to learn more about how the Merchant of Record model works? [Learn more about MoR](https://www.creem.io/blog/what-is-a-merchant-of-record). Read our detailed guide on Understanding the Merchant of Record Business Model, where we break down the key benefits and explain why it's crucial for modern and lean SaaS businesses.