Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

192 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

PayCraft

CI Maven Central npm Kotlin License

Craft your own billing. Any provider. Any platform. 15 minutes.

Self-hosted, provider-agnostic billing library for Kotlin Multiplatform apps. Uses Supabase as the source of truth — your app never talks to a payment provider directly. Open-source SDK + optional hosted dashboard for subscriber management and analytics.

Client App ──→ PayCraft SDK ──→ Supabase (source of truth)
                                  ↑
Payment Provider ──webhook──────┘
                                  ↑
Dashboard ──────────────────────┘

Quick Start

Option A: CLI (fastest)

npx paycraft init

The CLI scaffolds your Supabase schema, Edge Functions, and app configuration interactively.

Option B: Claude AI (recommended for KMP apps)

The fastest way to add PayCraft billing to your KMP app — no cloning, no setup, one prompt.

Step 1 — Open Claude Code in your KMP app

cd /path/to/your-kmp-app
claude

Step 2 — Paste this one prompt

Fetch https://raw.githubusercontent.com/mobilebytelabs/paycraft/main/client-skills/paycraft-adopt.md
Save it to .claude/commands/paycraft-adopt.md in this project, then run /paycraft-adopt.

That's it. Claude handles everything from here:

Phase What Claude does What you do
Bootstrap Searches for PayCraft locally, offers to clone it if not found — asks where on your system Pick a location (or press Enter for ~/paycraft/)
Phase 1 — ENV Creates .env, walks you through each credential Answer ~8 questions (Supabase keys, Stripe key, plans)
Phase 2 — Supabase Applies migrations, creates RPCs, deploys webhook, verifies every step Nothing
Phase 3 — Stripe Creates test product, prices, payment links automatically via Stripe MCP 2 browser steps: add webhook endpoint + enable portal
Phase 4 — Client Adds dependency, writes PayCraft.configure(), wires Koin + paywall UI Nothing
Phase 5 — Verify Writes real DB row, calls is_premium(), confirms true, cleans up Nothing

Result: fully operational billing in test mode. No real charges until you opt in.

Re-run individual phases anytime

After setup, these commands are available in your project:

/paycraft-adopt-env        ← re-collect credentials (key rotation)
/paycraft-adopt-supabase   ← re-deploy webhook or re-apply migrations
/paycraft-adopt-stripe     ← create live products when ready to ship
/paycraft-adopt-client     ← re-integrate into a different app
/paycraft-adopt-verify     ← re-verify after any config change
/paycraft-adopt-migrate    ← migrate to new Supabase/Stripe account or switch providers

Deployment context

After setup completes, your app contains a .paycraft/ directory — a complete record of how PayCraft is configured in your project:

your-app/
├── .env                      ← gitignored (auto-added by setup) — all PayCraft keys
└── .paycraft/
    ├── config.json           ← setup answers — safe to commit
    ├── deployment.json       ← resource IDs, no secrets — safe to commit
    ├── supabase/             ← SQL + Edge Function backup — safe to commit
    └── backups/              ← gitignored — timestamped .env copies

Step 5 automatically adds .env and .paycraft/backups/ to your .gitignore. Everything else in .paycraft/ is safe to commit as deployment documentation.

Prerequisites

  • Claude Code CLI (npm install -g @anthropic-ai/claude-code)
  • KMP app with Koin DI
  • Supabase project (free tier works)
  • Stripe or Razorpay account (test mode for setup)

Migrate later

Moving to a new Supabase org, rotating Stripe accounts, or switching from Stripe to Razorpay?

/paycraft-adopt-migrate

Claude shows your current deployment, asks what's changing, backs up your .env, collects only the new credentials, re-deploys only the affected components, and re-verifies end-to-end. No full re-setup. Subscriber data migration included (optional).

Migration Command handles
New Supabase project Re-deploys migrations + webhook, migrates subscriber data
New Stripe account Re-creates products, prices, payment links, webhook
New Razorpay account Re-creates plans, payment links, webhook
Stripe → Razorpay Full provider switch, updates app config
Razorpay → Stripe Full provider switch, updates app config

Features

  • Multi-provider — Stripe, Razorpay, Paddle, PayPal, LemonSqueezy, Flutterwave, Paystack, Midtrans, BTCPay, or bring your own
  • No fees — zero per-transaction cuts (beyond your payment provider)
  • Self-hosted or Cloud — own your data in Supabase, or use the hosted dashboard
  • Multi-tenant — single deployment serves multiple apps with isolated data
  • KMP + Compose — works on Android, iOS, macOS, JVM, JS, and Wasm
  • Device binding — per-device premium verification with conflict resolution
  • Paywall UI includedPayCraftSheet, PayCraftBanner, PayCraftRestore out of the box
  • Plugin system — community-contributed providers as separate Maven artifacts
  • Web dashboard — subscriber management, revenue analytics, webhook monitoring
  • CLI toolingnpx paycraft init scaffolds everything in minutes
  • Koin DI — drop in PayCraftModule, get BillingManager everywhere

Manual Setup

If you prefer to set up without Claude AI, see docs/QUICK_START.md.

Add dependency

# gradle/libs.versions.toml
[versions]
paycraft = "LATEST_VERSION"   # check Maven Central badge above

[libraries]
paycraft = { module = "io.github.mobilebytelabs:paycraft", version.ref = "paycraft" }
// shared/build.gradle.kts — commonMain ONLY
commonMain.dependencies {
    implementation(libs.paycraft)
}

Configure (before Koin)

PayCraft.configure {
    supabase(
        url = BuildConfig.SUPABASE_URL,
        anonKey = BuildConfig.SUPABASE_ANON_KEY,
    )
    provider(
        StripeProvider(
            paymentLinks = mapOf(
                "monthly"   to BuildConfig.STRIPE_MONTHLY_LINK,
                "quarterly" to BuildConfig.STRIPE_QUARTERLY_LINK,
                "yearly"    to BuildConfig.STRIPE_YEARLY_LINK,
            ),
            customerPortalUrl = BuildConfig.STRIPE_PORTAL_URL,
        )
    )
    plans(
        BillingPlan(id = "monthly",   name = "Monthly",   price = "₹99",  interval = "/month"),
        BillingPlan(id = "quarterly", name = "Quarterly", price = "₹249", interval = "/3 months"),
        BillingPlan(id = "yearly",    name = "Yearly",    price = "₹799", interval = "/year", isPopular = true),
    )
    benefits(
        BillingBenefit(icon = Icons.Default.Block,    text = "Ad-free experience"),
        BillingBenefit(icon = Icons.Default.Download, text = "Unlimited downloads"),
    )
    supportEmail("support@yourdomain.com")
}

Add Koin module

startKoin {
    modules(yourModules, PayCraftModule)
}

Add UI

var showPaywall by remember { mutableStateOf(false) }
var showRestore by remember { mutableStateOf(false) }

PayCraftBanner(
    onClick = { showPaywall = true },
    onRestoreClick = { showRestore = true },
)

PayCraftSheet(visible = showPaywall, onDismiss = { showPaywall = false })
PayCraftRestore(visible = showRestore, onDismiss = { showRestore = false })

Gate premium features

val isPremium by billingManager.isPremium.collectAsState()

if (isPremium) PremiumContent() else FreeContent()

Providers

Provider Status Checkout Webhook
Stripe Stable Payment Links stripe-webhook
Razorpay Stable Payment Links razorpay-webhook
Paddle Ready Overlay Checkout paddle-webhook
PayPal Ready Smart Buttons paypal-webhook
LemonSqueezy Ready Hosted Checkout lemonsqueezy-webhook
Flutterwave Ready Standard Checkout flutterwave-webhook
Paystack Ready Popup Checkout paystack-webhook
Midtrans Ready Snap midtrans-webhook
BTCPay Ready Invoice btcpay-webhook
Custom Stable Any URL Implement PaymentProvider

UI Components

Component Description
PayCraftSheet Conditional bottom-sheet paywall
PayCraftPaywall Full-screen paywall
PayCraftBanner Settings row — upgrade CTA or premium status
PayCraftRestore Email-based restore purchases dialog
PayCraftPremiumGuard Gate any composable behind premium

Supported Platforms

Platform Targets
Android android
iOS iosX64, iosArm64, iosSimulatorArm64
macOS macosX64, macosArm64
JVM jvm
JavaScript js (Browser, Node.js)
WebAssembly wasmJs (Browser)

Dashboard

The PayCraft web dashboard provides tenant admins with:

  • Subscriber management — search, filter, export, manual actions
  • Revenue analytics — MRR, churn, cohorts, LTV
  • Webhook monitoring — delivery status, payload inspection, manual retry
  • Provider configuration — manage keys, test connectivity
  • Usage & billing — for multi-tenant cloud deployments

Live: paycraft.mobilebytesensei.com


Architecture

PayCraft uses a multi-tenant architecture where each app gets isolated data within a shared Supabase deployment:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  App A      │     │  App B      │     │  App C      │
│  (SDK)      │     │  (SDK)      │     │  (SDK)      │
└──────┬──────┘     └──────┬──────┘     └──────┬──────┘
       │                   │                   │
       │  X-PayCraft-API-Key header            │
       └───────────┬───────┴───────────────────┘
                   ▼
          ┌────────────────┐
          │   Supabase     │
          │  (RPCs + RLS)  │◄──── Webhooks (per-tenant URLs)
          └────────┬───────┘
                   ▼
          ┌────────────────┐
          │   Dashboard    │
          │  (Next.js)     │
          └────────────────┘

Self-hosted users: omit the API key — RPCs default to single-tenant mode.


Documentation


Platform Examples

See paycraft-sample/ for minimal per-platform projects:


Plugin System

Create custom provider plugins as separate Maven artifacts:

class MyGatewayPlugin : ProviderPlugin {
    override val providerId = "my-gateway"
    override fun createProvider(config: PluginConfig): PaymentProvider { ... }
}

See plugin-template/ for a starter template.


Building

./gradlew jvmTest          # run tests
./gradlew :sample-app:run  # desktop sample
./gradlew spotlessApply    # format
./gradlew detekt           # lint

Releasing

./scripts/release.sh
# or: /lib-release in Claude Code

Live Services

Service URL
Documentation mobilebytelabs.github.io/PayCraft
Dashboard paycraft.mobilebytesensei.com
CLI npmjs.com/package/paycraft
SDK Maven Central

Contributing

See CONTRIBUTING.md.

License

Copyright 2026 MobileByteLabs

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.