Kitty Flutter SDK

Unified Flutter SDK for the Kitty Launch platform — combines Flare (device fingerprint attribution) and Account (authentication, user management, licenses, subscriptions) in a single package.

Install

dependencies:
  kitty_sdk: ^0.9.0

Quick Start

import 'package:kitty_sdk/kitty_sdk.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await KittySdk.initialize(
    config: KittySdkConfig(
      projectId: 'proj_xxx',
      accountBaseUrl: '<your-account-api-url>',
      flareBaseUrl: '<your-flare-api-url>',
    ),
  );

  runApp(const MyApp());
}

Usage

Flare — fingerprint identification

final match = await KittySdk.flare.identify();
if (match != null) {
  print('Matched! uid=${match.uid} type=${match.matchType}');
}

Account — authentication

final account = await KittySdk.account.loginWithPassword(
  email: 'user@example.com',
  password: 'secret',
);

KittySdk.account.accountStream.listen((account) {
  // React to auth state changes
});

Account — licenses

final user = KittySdk.account.currentAccount;
final license = user?.bestLicense;
if (license != null && license.isActive) {
  // User has active license
}

Account UI — theming

Set the base SDK UI theme once:

await KittySdk.initialize(
  config: KittySdkConfig(
    projectId: 'proj_xxx',
    accountBaseUrl: '...',
    flareBaseUrl: '...',
    theme: KittyTheme(
      themeData: ThemeData(
        useMaterial3: true,
        fontFamily: 'DM Sans',
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.purple),
      ),
    ),
  ),
);

Customize auth and bind-email screens separately:

final authTheme = KittyAuthTheme(
  backgroundColor: Colors.white,
  loginHeaderWidget: Image.asset('assets/logo.png', height: 64),
  codeHeaderWidget: Image.asset('assets/logo.png', height: 48),
  loginBodyPadding: EdgeInsets.symmetric(horizontal: 24),
  primaryButtonStyle: ElevatedButton.styleFrom(
    minimumSize: Size(double.infinity, 48),
    shape: StadiumBorder(),
  ),
  inputDecoration: InputDecorationTheme(
    border: OutlineInputBorder(
      borderRadius: BorderRadius.all(Radius.circular(16)),
    ),
  ),
);

KittyAuthFlow(
  account: KittySdk.account,
  theme: authTheme,
);

KittyBindEmailFlow(
  account: KittySdk.account,
  theme: authTheme,
);

Customize settings screens by logical blocks:

KittySettingsFlow(
  account: KittySdk.account,
  onLoginPressed: () {},
  onRenewSubscription: () {},
  theme: KittySettingsTheme(
    page: KittySettingsPageTheme(
      backgroundColor: Colors.white,
      contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 24),
    ),
    menuItem: KittySettingsMenuItemTheme(
      borderRadius: BorderRadius.all(Radius.circular(16)),
      padding: EdgeInsets.symmetric(horizontal: 16, vertical: 14),
      iconColor: Colors.black54,
    ),
    buttons: KittySettingsButtonsTheme(
      primaryButtonSize: Size(240, 52),
      primaryButtonStyle: ElevatedButton.styleFrom(
        shape: StadiumBorder(),
      ),
    ),
    dialog: KittySettingsDialogTheme(
      destructiveActionStyle: TextStyle(color: Colors.red),
    ),
    bindEmail: KittySettingsBindEmailTheme(
      authTheme: authTheme,
    ),
  ),
);

All theme fields are optional. If a field is null, the SDK uses its default style from Theme.of(context) / the built-in Kitty UI.

Buy Now — web paywall with mobile prices

Requires Common Module v13.4.0+ on the web side.

final products = <ProductDetails>{...}; // from InAppPurchase

router.push(MaterialPageRoute(
  builder: (_) => KittyWebBuyNowPage(
    url: 'https://your-domain.com/buy-now', // Kitty Flow url
    products: products,
    onPaymentSuccess: () {
      router.pop();
    },
  ),
));

Modules

Module Access Description
Flare KittySdk.flare Device fingerprint identification & purchase attribution
Account KittySdk.account Auth, user management, licenses, subscriptions
Tokens KittySdk.tokens Token balance and operations (requires Account)
Buy Now KittySdk.buyNow Web paywall with mobile price bridging

Tokens — balance and operations

// 1. Enable tokens in KittySdkConfig
await KittySdk.initialize(
  config: KittySdkConfig(
    projectId: 'proj_xxx',
    accountBaseUrl: '...',
    flareBaseUrl: '...',
    tokens: const KittyTokensConfig(isDebug: true),
  ),
);

// 2. Use the module (user must be logged in via KittySdk.account)
//    By default the SDK uses the first usable license of the current user.
//    Pass `licenseId:` explicitly when you need to target a specific license.
final balance = await KittySdk.tokens.getBalance();
print('Tokens: ${balance.balance}');

// Get operations history
final ops = await KittySdk.tokens.getOperations(skip: 0, limit: 20);

// Token mutations (add/remove) are server-side only — call them from your
// backend with an internal API key or a per-project `kap_` bearer token
// against `POST /api/internal/tokens/add` and `/api/internal/tokens/remove`.

// 3. Use the Cubit in your UI
BlocProvider(
  create: (_) => TokensCubit(tokens: KittySdk.tokens)..loadBalance(),
  child: BlocBuilder<TokensCubit, TokensState>(
    builder: (context, state) {
      if (state.isLoading) return const CircularProgressIndicator();
      return Text('Balance: ${state.tokenCount}');
    },
  ),
)

Backend token mutations — important notes

add/remove are server-side only (call them from your backend with a per-project kap_ bearer token). Before you build against them, mind these three behaviours (full guide: kitty-launch-account/docs/backend-token-api.md):

  1. /add and /remove hit DIFFERENT buckets. /add credits the persistent balance bucket; /remove debits the renewable subscriptionBalance bucket (which has no floor and can go negative). A naive "grant then spend" will not net out — for a "tokens per operation" model, confirm with the platform team which bucket you should be debiting.
  2. No idempotency on /add / /remove. Calling twice applies twice. Deduplicate on your side (fire exactly once per operation, e.g. guard by your own operation id).
  3. A kap_ token cannot read balance. GET /balance and GET /operations require the internal API key — a kap_ bearer gets 401 there. Decide how your backend will verify results (e.g. read balance in the client via the SDK, or request read access from the platform team).

Libraries

kitty_sdk
Unified Kitty Flutter SDK — Flare (fingerprint attribution) + Account (auth, licenses, subscriptions) + Analytics (PostHog) in a single package.