---
name: creem
description: Use when building payment integrations, managing subscriptions,
  handling webhooks, creating products, or automating billing workflows. Agents
  should reach for this skill when a user needs to accept payments, manage
  recurring billing, issue licenses, track affiliates, or integrate payment
  processing into an application.
metadata:
  mintlify-proj: creem
  version: "1.0"
---

# Creem Skill

## Product Summary

Creem is a Merchant of Record (MoR) platform for developers selling software globally. It handles payments, subscriptions, tax compliance (VAT/GST/sales tax in 190+ countries), chargebacks, and payouts. Agents use Creem to build payment flows, manage products, handle webhooks, and automate billing workflows.

**Key files and commands:**
- API key: `x-api-key` header (find in dashboard → Developers)
- CLI: `creem` (install via Homebrew or npm)
- SDKs: TypeScript (`creem`), Next.js (`@creem_io/nextjs`), Better Auth (`@creem_io/better-auth`)
- Webhook secret: Found in dashboard → Developers → Webhook
- Base URLs: `https://api.creem.io/v1` (production), `https://test-api.creem.io/v1` (test mode)
- Primary docs: https://docs.creem.io

## When to Use

Reach for this skill when:
- Building a checkout flow (one-time or recurring payments)
- Creating or managing products programmatically
- Setting up webhooks to handle payment events
- Managing subscriptions (pause, resume, cancel, upgrade)
- Issuing or validating license keys
- Tracking affiliate commissions or revenue splits
- Implementing customer portals for subscription management
- Testing payment flows without real charges
- Migrating from another payment provider (LemonSqueezy, Stripe, etc.)
- Automating store operations via CLI or API
- Handling refunds or chargebacks
- Implementing usage-based or seat-based billing

## Quick Reference

### API Endpoints (Core)

| Task | Method | Endpoint | Notes |
|------|--------|----------|-------|
| Create checkout | POST | `/v1/checkouts` | Returns `checkoutUrl` for redirect |
| Get checkout | GET | `/v1/checkouts?checkout_id=...` | Retrieve checkout status |
| Create product | POST | `/v1/products` | One-time or recurring |
| List products | GET | `/v1/products` | Search and filter |
| Get subscription | GET | `/v1/subscriptions?subscription_id=...` | View status, billing cycle |
| Update subscription | POST | `/v1/subscriptions/{id}` | Change seats, units, pricing |
| Cancel subscription | POST | `/v1/subscriptions/{id}/cancel` | Immediate or end-of-period |
| Create webhook | POST | `/v1/webhooks` | Register endpoint for events |
| Refund payment | POST | `/v1/transactions/{id}/refund` | Full or partial refund |

### CLI Commands

```bash
# Authentication
creem login --api-key creem_test_YOUR_KEY
creem whoami --json

# Products
creem products list --json
creem products create --name "Pro" --price 1999 --currency USD --billing-type recurring --billing-period every-month

# Checkouts
creem checkouts create --product prod_123 --customer-email user@example.com --json

# Subscriptions
creem subscriptions list --json
creem subscriptions update sub_123 --units 5 --yes --json

# Webhooks
creem webhooks create --url https://example.com/webhooks/creem --event checkout.completed --json
creem listen --forward-to http://localhost:3000/api/webhooks

# Transactions
creem transactions list --json
creem transactions refund tran_123 --amount 1000 --yes --json
```

### Environment Variables

```bash
CREEM_API_KEY=creem_test_YOUR_KEY          # API key (test or prod)
CREEM_WEBHOOK_SECRET=whsec_YOUR_SECRET     # Webhook signing secret
NEXT_PUBLIC_APP_URL=http://localhost:3000  # App URL for redirects
NODE_ENV=development                        # Controls test vs prod mode
```

### Test Mode

Use test mode for development without real charges.

| 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 |

All test cards work with any future expiry and any CVV.

### Webhook Events

| Event | When | Use Case |
|-------|------|----------|
| `checkout.completed` | Payment successful | Grant access, send confirmation |
| `subscription.active` | Subscription created | Sync to database |
| `subscription.paid` | Renewal charged | Log transaction |
| `subscription.canceled` | Subscription ended | Revoke access |
| `subscription.paused` | Subscription paused | Suspend features |
| `subscription.trialing` | Trial started | Track trial users |
| `refund.created` | Refund issued | Update accounting |
| `dispute.created` | Chargeback filed | Alert merchant |

## Decision Guidance

### When to Use X vs Y

| Scenario | Use | Why |
|----------|-----|-----|
| Simple product, no code | Checkout link (dashboard) | No integration needed, instant |
| Dynamic pricing or tracking | Checkout API | Full control, metadata support |
| Next.js app | `@creem_io/nextjs` adapter | Built-in components, routes |
| Any JavaScript framework | TypeScript SDK | Type-safe, flexible |
| User authentication needed | Better Auth plugin | Automatic user sync |
| Convex backend | Convex component | Database sync, widgets included |
| One-time payment | `billing_type: onetime` | No renewal |
| Recurring billing | `billing_type: recurring` | Auto-renew, manage lifecycle |
| Immediate cancellation | `cancel_behavior: immediate` | Stop access now |
| End-of-period cancellation | `cancel_behavior: end_of_period` | Let customer finish cycle |
| Webhook testing locally | `creem listen` | No tunnel needed, real signatures |
| Webhook testing in CI | Register HTTPS endpoint | Persistent, automated |

## Workflow

### 1. Set Up Authentication

1. Sign up at https://creem.io
2. Go to dashboard → Developers
3. Copy your test API key (starts with `creem_test_`)
4. Store in `.env` as `CREEM_API_KEY`
5. Copy webhook secret and store as `CREEM_WEBHOOK_SECRET`
6. Verify with `creem whoami --json` or `curl -H "x-api-key: ..." https://test-api.creem.io/v1/products`

### 2. Create a Product

**Via CLI:**
```bash
creem products create \
  --name "Pro Plan" \
  --price 2999 \
  --currency USD \
  --billing-type recurring \
  --billing-period every-month \
  --json
```

**Via API:**
```bash
curl -X POST https://test-api.creem.io/v1/products \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Pro Plan",
    "price": 2999,
    "currency": "USD",
    "billing_type": "recurring",
    "billing_period": "every-month"
  }'
```

Copy the returned `id` (starts with `prod_`).

### 3. Create a Checkout Session

**Next.js:**
```tsx
import { CreemCheckout } from "@creem_io/nextjs";

export default function Page() {
  return (
    <CreemCheckout productId="prod_YOUR_ID">
      <button>Subscribe Now</button>
    </CreemCheckout>
  );
}
```

**TypeScript SDK:**
```typescript
const creem = new Creem({ apiKey: process.env.CREEM_API_KEY, server: "test" });
const checkout = await creem.checkouts.create({
  productId: "prod_YOUR_ID",
  successUrl: "https://yourapp.com/success",
  customer: { email: "user@example.com" },
});
window.location.href = checkout.checkoutUrl;
```

### 4. Register a Webhook

**Via CLI:**
```bash
creem webhooks create \
  --url https://yourapp.com/api/webhooks/creem \
  --event checkout.completed \
  --event subscription.paid \
  --json
```

Copy the returned `secret`.

**Via API:**
```bash
curl -X POST https://test-api.creem.io/v1/webhooks \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/api/webhooks/creem",
    "events": ["checkout.completed", "subscription.paid"]
  }'
```

### 5. Handle Webhook Events

**Next.js:**
```typescript
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}`);
    // Grant access, send email, update database
  },
  onGrantAccess: async ({ customer, metadata }) => {
    const userId = metadata?.referenceId;
    await grantAccess(userId, customer.email);
  },
});
```

**Manual verification:**
```typescript
import { verifyWebhookSignature } from "creem/webhooks";

const event = await verifyWebhookSignature(rawBody, headers, {
  secret: process.env.CREEM_WEBHOOK_SECRET!,
});
```

### 6. Test the Flow

1. Run `creem listen --forward-to http://localhost:3000/api/webhooks`
2. Visit your checkout page
3. Use test card `4111 1111 1111 1111`
4. Verify webhook received and processed
5. Check dashboard for transaction

### 7. Deploy to Production

1. Switch API key to production (remove `creem_test_` prefix)
2. Update webhook URL to production domain
3. Test with real payment (then refund)
4. Monitor dashboard for transactions

## Common Gotchas

- **API key in client code**: Never expose API keys in frontend code. Keep them server-side only. Use `x-api-key` header in server requests.
- **Test vs production isolation**: Test and production environments are completely separate. Data created in test mode does not affect production. API keys are not interchangeable.
- **Webhook signature verification**: Always verify the `creem-signature` header before processing events. Failing to do so allows spoofed webhooks.
- **Idempotency**: Webhooks can be delivered multiple times. Make your handlers idempotent (safe to run twice). Use `event.id` to deduplicate.
- **Webhook retry limits**: Creem retries for 24 hours max (5 attempts total). After that, manually resend from dashboard if needed.
- **Metadata is not encrypted**: Metadata is visible in webhooks and API responses. Don't store sensitive data (passwords, tokens) in metadata.
- **Subscription status transitions**: A subscription can be `active`, `paused`, `canceled`, `trialing`, `past_due`, `unpaid`, `expired`, or `scheduled_cancel`. Not all transitions are valid. Check docs for allowed state changes.
- **Refunds are not instant**: Refunds take time to process. Check transaction status, don't assume immediate reversal.
- **Tax is calculated by Creem**: You don't control tax calculation. Creem handles it based on customer location and product tax category. Prices can be inclusive or exclusive of tax.
- **Discount codes are one-time setup**: Create discount codes in dashboard or via API. Apply them at checkout with `discount_code` parameter. They don't auto-apply.
- **License keys are per-feature**: If a product has multiple license key features, one key is issued per feature per unit purchased. Always treat `license_keys` as an array.
- **Custom fields are optional by default**: Custom fields on products are optional unless you set `optional: false`. Customers can skip them.
- **Webhook endpoint must be HTTPS**: Creem only sends webhooks to HTTPS endpoints. Use ngrok or similar for local testing.
- **No static IP allowlist**: Creem doesn't provide static IPs for webhooks. Don't rely on IP allowlists. Verify signatures instead.
- **CLI writes are not retried**: If a CLI command fails ambiguously (network error, timeout), inspect the outcome before retrying manually.
- **Pagination defaults to 10 items**: Use `--limit` and `--page` flags to control pagination. Use `--all` to fetch everything.

## Verification Checklist

Before submitting work with Creem integration:

- [ ] API key is stored in environment variable, not hardcoded
- [ ] Webhook secret is stored in environment variable
- [ ] Webhook signature is verified before processing events
- [ ] Webhook handler is idempotent (safe to run multiple times)
- [ ] Product ID is correct and exists in the environment (test or prod)
- [ ] Checkout success URL is set and reachable
- [ ] Test mode is used for development (API key starts with `creem_test_`)
- [ ] Production mode uses live API key for real payments
- [ ] Webhook endpoint is registered in dashboard
- [ ] Webhook endpoint responds with HTTP 200 on success
- [ ] Subscription lifecycle is handled (active, canceled, paused events)
- [ ] Refund logic is implemented if needed
- [ ] Customer portal link is generated for subscription management
- [ ] Error handling wraps API calls in try-catch
- [ ] Redirect signature is verified if using checkout redirects
- [ ] Metadata is used for tracking (not sensitive data)
- [ ] Test payment flow works end-to-end
- [ ] Webhook events are logged for debugging
- [ ] Rate limits are respected (429 responses handled)
- [ ] Documentation links are current (no broken references)

## Resources

**Comprehensive navigation:** https://docs.creem.io/llms.txt

**Critical documentation pages:**
1. [API Reference](https://docs.creem.io/api-reference/introduction) — Authentication, endpoints, test mode, error codes
2. [Webhooks Guide](https://docs.creem.io/code/webhooks) — Setup, signature verification, event types, retry policy
3. [Checkout API](https://docs.creem.io/features/checkout/checkout-api) — Creating sessions, metadata, discount codes, verification

**Additional resources:**
- [CLI Reference](https://docs.creem.io/code/cli) — Commands, authentication, local webhooks
- [TypeScript SDK](https://docs.creem.io/code/sdks/typescript) — Type-safe API wrapper
- [Next.js Adapter](https://docs.creem.io/code/sdks/nextjs) — Drop-in components and routes
- [Subscriptions](https://docs.creem.io/features/subscriptions/introduction) — Lifecycle, trials, upgrades
- [Test Mode](https://docs.creem.io/getting-started/test-mode) — Test cards, sandbox environment

---

> For additional documentation and navigation, see: https://docs.creem.io/llms.txt