Entitlements

Control access to features with entitlements

What are Entitlements?

Entitlements represent the features or content that users can unlock through purchases. Instead of checking for specific product purchases, you check if a user has a specific entitlement. This abstraction provides several benefits:

  • Change products without updating app code
  • Multiple products can grant the same entitlement
  • Grant entitlements manually for promotions
  • Cleaner code focused on features, not products

How Entitlements Work

┌─────────────────────────────────────────────────────────┐
│                      Products                            │
├─────────────────┬─────────────────┬─────────────────────┤
│ Monthly Premium │ Annual Premium  │ Lifetime Premium    │
│    $9.99/mo     │    $79.99/yr    │      $199.99        │
└────────┬────────┴────────┬────────┴──────────┬──────────┘
         │                 │                   │
         │   All grant:    │                   │
         ▼                 ▼                   ▼
         ┌─────────────────────────────────────┐
         │         "premium" entitlement        │
         └─────────────────────────────────────┘
                           │
                           ▼
         ┌─────────────────────────────────────┐
         │   hasEntitlement('premium') = true   │
         │                                     │
         │   • Ad-free experience              │
         │   • Exclusive content               │
         │   • Advanced features               │
         └─────────────────────────────────────┘

Creating Entitlements

In the Dashboard

  1. Navigate to Products

    Go to your app's Products section in the dashboard

  2. Click "Create Entitlement"

    Find the Entitlements tab and create a new one

  3. Set the identifier

    Use a simple, descriptive identifier like "premium" or "pro_features"

  4. Add display name and description

    These are for your reference in the dashboard

Via API

Create entitlement via API
POST /api/v1/entitlements
{
  "identifier": "premium",
  "displayName": "Premium Access",
  "description": "Full access to all premium features"
}

Linking Entitlements to Products

Each product can grant one or more entitlements when purchased. When a user purchases the product, they automatically receive all linked entitlements.

Example: Simple App

Monthly Premium ($9.99/mo)→ grants "premium"
Annual Premium ($79.99/yr)→ grants "premium"

Example: Multi-Tier App

Plus Subscription→ grants "plus"
Pro Subscription→ grants "plus", "pro"
Enterprise Subscription→ grants "plus", "pro", "enterprise"

Checking Entitlements in Your App

Using the SDK

React Native
import { usePurchases } from '@croissantpay/react-native';

function MyComponent() {
  const { hasEntitlement, entitlements } = usePurchases();
  
  // Simple check
  const isPremium = hasEntitlement('premium');
  
  // Check with details
  const premiumEntitlement = entitlements['premium'];
  if (premiumEntitlement?.isActive) {
    console.log('Expires:', premiumEntitlement.expiresAt);
    console.log('From product:', premiumEntitlement.productId);
  }
  
  return (
    <View>
      {isPremium ? (
        <PremiumContent />
      ) : (
        <UpgradePrompt />
      )}
    </View>
  );
}

Server-Side Check

API Request
GET /api/v1/subscribers/user_123/entitlements
Authorization: X-API-Key: mx_live_xxx

// Response
{
  "entitlements": {
    "premium": {
      "isActive": true,
      "expiresAt": "2024-02-15T00:00:00Z",
      "productId": "com.app.premium_monthly",
      "purchaseDate": "2024-01-15T00:00:00Z"
    }
  }
}

Granting Entitlements Manually

Sometimes you need to grant entitlements without a purchase—for promotions, customer support, or testing.

Grant via API
POST /api/v1/entitlements/grant
{
  "appUserId": "user_123",
  "entitlementId": "premium",
  "expiresAt": "2024-12-31T23:59:59Z",  // Optional, omit for permanent
  "reason": "Customer support compensation"
}

Note: Manually granted entitlements are marked as such in the subscriber record, so you can distinguish them from purchase-based entitlements.

Best Practices

Use descriptive identifiers

Choose identifiers that describe the feature, not the product. "premium_features" is better than "monthly_subscription".

Plan for growth

Create entitlements for feature groups you might separate later. It's easier to merge than to split.

Cache entitlements client-side

The SDK caches entitlements automatically. Only refresh when needed (app launch, after purchase, pull-to-refresh).

Verify server-side for sensitive operations

For actions with real consequences (unlocking content, accessing APIs), verify entitlements server-side as well.

Example: Feature Gating Pattern

FeatureGate.tsx
import { usePurchases } from '@croissantpay/react-native';
import { useNavigation } from '@react-navigation/native';

interface FeatureGateProps {
  entitlement: string;
  children: React.ReactNode;
  fallback?: React.ReactNode;
}

export function FeatureGate({ 
  entitlement, 
  children, 
  fallback 
}: FeatureGateProps) {
  const { hasEntitlement } = usePurchases();
  const navigation = useNavigation();
  
  if (hasEntitlement(entitlement)) {
    return <>{children}</>;
  }
  
  if (fallback) {
    return <>{fallback}</>;
  }
  
  return (
    <View style={styles.locked}>
      <Lock size={24} />
      <Text>This feature requires {entitlement}</Text>
      <Button 
        title="Upgrade" 
        onPress={() => navigation.navigate('Paywall')} 
      />
    </View>
  );
}

// Usage
<FeatureGate entitlement="premium">
  <AdvancedAnalytics />
</FeatureGate>

<FeatureGate 
  entitlement="pro" 
  fallback={<BasicExport />}
>
  <AdvancedExport />
</FeatureGate>

Next Steps