vibecoding-purchases
v1.1.2
Published
VibeCoding Purchases SDK for React Native and Expo apps
Maintainers
Readme
VibeCoding Purchases SDK
A comprehensive purchases SDK for React Native and web applications that integrates with your VibeCoding backend API.
Features
- ✅ Anonymous user system with automatic linking
- ✅ Cross-platform support (iOS, Android, Web)
- ✅ Native mobile payments (Apple App Store, Google Play)
- ✅ Subscription management
- ✅ Purchase restoration
- ✅ React hooks for easy integration
- ✅ TypeScript support
Installation
npm install vibecoding-purchases
# or
yarn add vibecoding-purchasesQuick Start
1. Configure the SDK
The SDK works in multiple environments with different capabilities:
For Expo Go (Development)
import { VibeCodingPurchases } from "vibecoding-purchases";
// Basic configuration for Expo Go - no native purchases
const purchases = VibeCodingPurchases.configure({
projectId: "your-project-id",
apiKey: "your-api-key",
baseUrl: "https://your-api.com",
environment: "development", // or 'production'
});
// Will work for: user management, offerings, customer info
// Won't work: native purchases (will throw helpful errors)For Development Builds (Native Features)
import { VibeCodingPurchases } from "vibecoding-purchases";
import { useIAP } from "expo-iap";
// With expo-iap for full native purchase support
const expoIAPResult = useIAP();
const purchases = VibeCodingPurchases.configure(
{
projectId: "your-project-id",
apiKey: "your-api-key",
baseUrl: "https://your-api.com",
environment: "production",
},
expoIAPResult // Optional - enables native purchases & restore
);
// Will work: everything including native purchases and restoreFor Web/React (Future Stripe Support)
import { VibeCodingPurchases } from "vibecoding-purchases";
// Web configuration - Stripe integration planned
const purchases = VibeCodingPurchases.configure({
projectId: "your-project-id",
apiKey: "your-api-key",
baseUrl: "https://your-api.com",
environment: "production",
});
// Currently works: user management, offerings, customer info
// Coming soon: Stripe checkout sessions2. Anonymous User System
The SDK automatically handles anonymous users. When a user first opens your app, they get an anonymous ID:
// This will create an anonymous user automatically
const result = await purchases.logIn();
console.log(result.customerInfo.originalAppUserId); // "$AnonymousUser:abc123..."3. User Login with Account Linking
When a user logs in, their anonymous purchases are automatically transferred:
// Login with a real user ID - anonymous purchases will be linked
const result = await purchases.logIn("user123");
console.log("Purchases transferred:", result.created);4. Get Available Offerings
const offerings = await purchases.getOfferings();
const currentOffering = offerings.offerings.all["main"];
const packages = currentOffering?.availablePackages || [];5. Make a Purchase (React Native)
// For React Native apps, use the hook for native purchases
import { useVibeCodingPurchases } from 'vibecoding-purchases';
function PurchaseButton({ package: pkg }) {
const { purchasePackage, loading } = useVibeCodingPurchases();
const handlePurchase = async () => {
try {
const result = await purchasePackage(pkg);
console.log('Purchase successful:', result.customerInfo);
} catch (error) {
console.error('Purchase failed:', error);
}
};
return (
<button onClick={handlePurchase} disabled={loading}>
{loading ? 'Processing...' : `Buy for ${pkg.product.price}`}
</button>
);
}API Endpoints
Your backend now supports these endpoints:
User Management
POST /api/purchases/login
Creates/authenticates user with automatic anonymous user handling.
{
"app_user_id": "user123",
"project_id": "your-project-id"
}POST /api/purchases/link-alias
Links anonymous user to identified user.
{
"old_id": "$AnonymousUser:abc123",
"new_id": "user123",
"project_id": "your-project-id"
}Purchase & Subscription
GET /api/purchases/{PROJECT_ID}/offerings
Fetches available packages and offerings for the project.
GET /api/purchases/customer/{APP_USER_ID}
Gets customer subscription info and entitlements.
POST /api/purchases/purchase
Validates native purchase receipts.
{
"app_user_id": "user123",
"product_id": "premium_monthly",
"transaction_receipt": "base64-receipt-data",
"apple_transaction_id": "1000000123456789" // for iOS
}POST /api/purchases/{PROJECT_ID}/payment-sheet
Creates payment sheet for web (currently deprecated - use native mobile payments).
Native Restore via SDK
Purchases are restored automatically through the native platform integration (expo-iap). No separate API call needed - the SDK handles this internally.
Subscription Management
Subscription management is handled through the native platform stores (App Store/Google Play). Users manage subscriptions directly in their device settings.
Anonymous User System Details
How It Works
- First Launch: User gets an anonymous ID like
$AnonymousUser:abc123def456 - Anonymous Purchases: User can make purchases while anonymous
- User Login: When user logs in with real ID, anonymous purchases are transferred
- Security: If stored ID is custom but no custom ID provided, resets to new anonymous ID
Storage Functions
import { VibeCodingPurchasesStorage } from "vibecoding-purchases";
// Generate anonymous ID
const anonymousId = VibeCodingPurchasesStorage.generateAnonymousId();
// Returns: "$AnonymousUser:abc123def456"
// Check if ID is anonymous
const isAnon = VibeCodingPurchasesStorage.isAnonymousUserId(userId);
// Core user management
const result = await VibeCodingPurchasesStorage.getOrCreateUserId(
customUserId, // null for anonymous, string for login
projectId,
environment
);
// Storage operations
await VibeCodingPurchasesStorage.setUserId(userId, projectId);
const userId = await VibeCodingPurchasesStorage.getUserId(projectId);
await VibeCodingPurchasesStorage.clearUserId(projectId);React Integration
Provider Setup
Choose the setup that matches your environment:
Expo Go Setup (Development)
import { VibeCodingPurchasesProvider } from "vibecoding-purchases";
function App() {
return (
<VibeCodingPurchasesProvider
config={{
projectId: "your-project-id",
apiKey: "your-api-key",
environment: "development",
}}
// No expoIAPResult needed - will work for basic features
>
<YourApp />
</VibeCodingPurchasesProvider>
);
}Development Build Setup (Full Features)
import { VibeCodingPurchasesProvider } from "vibecoding-purchases";
import { useIAP } from "expo-iap";
function App() {
const expoIAPResult = useIAP(); // Enable native purchases
return (
<VibeCodingPurchasesProvider
config={{
projectId: "your-project-id",
apiKey: "your-api-key",
environment: "production",
}}
expoIAPResult={expoIAPResult} // Enables native purchases & restore
>
<YourApp />
</VibeCodingPurchasesProvider>
);
}Using Hooks
The hook automatically detects your environment and enables appropriate features:
import { useVibeCodingPurchases, useEntitlement } from "vibecoding-purchases";
function PremiumFeature() {
const {
customerInfo,
offerings,
purchasePackage,
restorePurchases,
isLoading,
canMakePurchases, // false in Expo Go, true in dev builds
isExpoGo, // true if running in Expo Go
error,
} = useVibeCodingPurchases();
const isPremium = useEntitlement("premium");
if (isPremium) {
return <PremiumContent />;
}
return (
<div>
<h2>Upgrade to Premium</h2>
{/* Show appropriate UI based on platform */}
{isExpoGo && (
<p>💡 Native purchases require a development build. Showing demo pricing.</p>
)}
{offerings?.all?.["main"]?.availablePackages.map((pkg) => (
<button
key={pkg.identifier}
onClick={() => purchasePackage(pkg)}
disabled={isLoading || !canMakePurchases}
>
{pkg.product.identifier} - ${pkg.product.price}
{!canMakePurchases && " (Dev Build Required)"}
</button>
))}
{canMakePurchases && (
<button onClick={restorePurchases} disabled={isLoading}>
Restore Purchases
</button>
)}
{error && <p style={{color: 'red'}}>Error: {error.message}</p>}
</div>
);
}Restore Purchases
The SDK provides different restore behavior based on platform:
Native Platforms (iOS/Android)
When expo-iap is configured, restorePurchases() performs a full transaction history sync:
// Syncs all purchase history from device with backend
const customerInfo = await purchases.restorePurchases();What happens:
- Queries native store (App Store/Google Play) for all purchase history
- Extracts transaction IDs from purchase receipts
- Sends transaction data to backend for validation
- Updates customer info with restored purchases
- Clears any pending transactions
Web Platform
On web, restorePurchases() simply refreshes customer info (no native transactions exist):
// Just refreshes customer info from backend
const customerInfo = await purchases.restorePurchases();Using with React Hooks
const { restorePurchases, isLoading, error } = useVibeCodingPurchases({
config,
expoIAPResult: useIAP(), // Required for native restore
});
const handleRestore = async () => {
try {
await restorePurchases();
console.log("Purchases restored successfully");
} catch (err) {
console.error("Restore failed:", err);
}
};Error Handling
import {
VibeCodingPurchasesError,
VibeCodingPurchasesErrorCode,
} from "vibecoding-purchases";
try {
await purchases.logIn("user123");
} catch (error) {
if (error instanceof VibeCodingPurchasesError) {
switch (error.code) {
case VibeCodingPurchasesErrorCode.NETWORK_ERROR:
console.log("Network issue, try again");
break;
case VibeCodingPurchasesErrorCode.INVALID_CREDENTIALS_ERROR:
console.log("Invalid API credentials");
break;
case VibeCodingPurchasesErrorCode.USER_NOT_LOGGED_IN_ERROR:
console.log("User needs to log in first");
break;
}
}
}Platform Support
| Platform | User Management | Offerings | Native Purchases | Restore | |----------|----------------|-----------|------------------|---------| | Expo Go | ✅ | ✅ | ❌ | ❌ | | iOS Dev Build | ✅ | ✅ | ✅ (App Store) | ✅ | | Android Dev Build | ✅ | ✅ | ✅ (Google Play) | ✅ | | Web | ✅ | ✅ | 🚧 (Stripe planned) | 🚧 |
Key Notes:
- Expo Go: Perfect for development - shows pricing, handles users, won't crash on purchase attempts
- Development Builds: Full native functionality with expo-iap
- Web: Basic functionality now, Stripe integration coming soon
- expo-iap is optional: SDK works without it, just disables native features gracefully
Security Features
- Automatic anonymous user reset if security mismatch detected
- Server-side receipt validation
- Project-scoped API keys
- Environment-specific configurations
Migration from Other SDKs
If you're migrating from RevenueCat or similar:
- The
CustomerInfostructure is compatible - Anonymous user system works automatically
- Entitlements are based on your product configuration
- Use the same product IDs from your app store configuration
License
MIT License - see LICENSE file for details.
