VibeCoding Purchases SDK for React Native and Expo apps
npm install vibecoding-purchasesA comprehensive purchases SDK for React Native and web applications that integrates with your VibeCoding backend API.
- ✅ 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
``bash`
npm install vibecoding-purchasesor
yarn add vibecoding-purchases
The SDK works in multiple environments with different capabilities:
#### For Expo Go (Development)
`typescript
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)
`typescript
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 restore
`
#### For Web/React (Future Stripe Support)
`typescript
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 sessions
`
The SDK automatically handles anonymous users. When a user first opens your app, they get an anonymous ID:
`typescript`
// This will create an anonymous user automatically
const result = await purchases.logIn();
console.log(result.customerInfo.originalAppUserId); // "$AnonymousUser:abc123..."
When a user logs in, their anonymous purchases are automatically transferred:
`typescript`
// Login with a real user ID - anonymous purchases will be linked
const result = await purchases.logIn("user123");
console.log("Purchases transferred:", result.created);
`typescript`
const offerings = await purchases.getOfferings();
const currentOffering = offerings.offerings.all["main"];
const packages = currentOffering?.availablePackages || [];
`typescript
// 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 (
);
}
`
Your backend now supports these endpoints:
#### POST /api/purchases/login
Creates/authenticates user with automatic anonymous user handling.
`typescript`
{
"app_user_id": "user123",
"project_id": "your-project-id"
}
#### POST /api/purchases/link-alias
Links anonymous user to identified user.
`typescript`
{
"old_id": "$AnonymousUser:abc123",
"new_id": "user123",
"project_id": "your-project-id"
}
#### 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.
`typescript`
{
"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.
1. First Launch: User gets an anonymous ID like $AnonymousUser:abc123def456
2. Anonymous Purchases: User can make purchases while anonymous
3. User Login: When user logs in with real ID, anonymous purchases are transferred
4. Security: If stored ID is custom but no custom ID provided, resets to new anonymous ID
`typescript
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);
`
Choose the setup that matches your environment:
#### Expo Go Setup (Development)
`tsx
import { VibeCodingPurchasesProvider } from "vibecoding-purchases";
function App() {
return (
projectId: "your-project-id",
apiKey: "your-api-key",
environment: "development",
}}
// No expoIAPResult needed - will work for basic features
>
);
}
`
#### Development Build Setup (Full Features)
`tsx
import { VibeCodingPurchasesProvider } from "vibecoding-purchases";
import { useIAP } from "expo-iap";
function App() {
const expoIAPResult = useIAP(); // Enable native purchases
return (
projectId: "your-project-id",
apiKey: "your-api-key",
environment: "production",
}}
expoIAPResult={expoIAPResult} // Enables native purchases & restore
>
);
}
`
The hook automatically detects your environment and enables appropriate features:
`tsx
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
}
return (
💡 Native purchases require a development build. Showing demo pricing.
{canMakePurchases && (
)}
{error &&
Error: {error.message}
}Restore Purchases
The SDK provides different restore behavior based on platform:
$3
When expo-iap is configured,
restorePurchases() performs a full transaction history sync:`typescript
// Syncs all purchase history from device with backend
const customerInfo = await purchases.restorePurchases();
`What happens:
1. Queries native store (App Store/Google Play) for all purchase history
2. Extracts transaction IDs from purchase receipts
3. Sends transaction data to backend for validation
4. Updates customer info with restored purchases
5. Clears any pending transactions
$3
On web,
restorePurchases() simply refreshes customer info (no native transactions exist):`typescript
// Just refreshes customer info from backend
const customerInfo = await purchases.restorePurchases();
`$3
`typescript
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
`typescript
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:
1. The
CustomerInfo` structure is compatibleMIT License - see LICENSE file for details.