This guide explains how to link subscriptions to users in your application and manage subscription ownership.
Link During Checkout
The simplest way to associate a user is during checkout:
await iaptic.createStripeCheckout({
offerId: 'stripe:prod_xyz#price_xyz',
applicationUsername: 'user123', // Your user identifier
successUrl: 'https://example.com/success',
cancelUrl: 'https://example.com/cancel'
});
The applicationUsername
will be stored in the subscription's metadata.
Update Existing Subscription
You can change the user association of an existing subscription:
// Using Stripe Dashboard
// Edit subscription metadata:
{
"application_username": "newuser123"
}
// Or using Stripe API
await stripe.subscriptions.update('sub_xyz', {
metadata: {
application_username: 'newuser123'
}
});
Choose Entitlement Strategy
Configure how subscription ownership works in your application settings:
ALL_CLAIMERS (Default)
// All users with valid credentials get access
const { purchases } = await iaptic.getPurchases();
if (purchases.length > 0) {
// User has access
enableFeatures(purchases[0]);
}
LAST_CLAIMER
// Only the most recent user gets access
const { purchases } = await iaptic.getPurchases();
if (purchases.length > 0 && purchases[0].applicationUsername === currentUser) {
// Current user has access
enableFeatures(purchases[0]);
}
Handle Subscription Transfers
- Simple Transfer
// Update subscription owner
await stripe.subscriptions.update('sub_xyz', {
metadata: {
application_username: 'newuser123'
}
});
- Transfer with Verification
async function transferSubscription(subscriptionId, newUsername) {
// Verify current access
const { purchases } = await iaptic.getPurchases(subscriptionId);
if (!purchases.length) {
throw new Error('Subscription not found');
}
// Update ownership
await stripe.subscriptions.update(subscriptionId, {
metadata: {
application_username: newUsername,
previous_username: purchases[0].applicationUsername,
transferred_at: new Date().toISOString()
}
});
// Notify users
notifyTransfer(purchases[0].applicationUsername, newUsername);
}
Track Ownership Changes
Monitor subscription transfers through webhooks:
// In your webhook handler
if (event.type === 'customer.subscription.updated') {
const subscription = event.data.object;
const previousAttributes = event.data.previous_attributes;
if (previousAttributes.metadata?.application_username) {
const oldUsername = previousAttributes.metadata.application_username;
const newUsername = subscription.metadata.application_username;
// Handle ownership change
onOwnershipChanged(subscription.id, oldUsername, newUsername);
}
}
Best Practices
-
User Identifiers
- Use consistent username format
- Consider using email addresses
- Store user ID mapping if needed
-
Access Control
- Validate ownership changes
- Keep transfer history
- Handle edge cases (deleted users)
-
UI/UX
- Show current owner
- Confirm transfers
- Notify affected users
-
Security
- Verify transfer authority
- Log ownership changes
- Handle disputes
Common Issues
Access Lost After Transfer
- Check entitlement strategy
- Verify metadata update
- Clear local storage
- Refresh access tokens
Multiple Users Issue
- Verify entitlement strategy
- Check webhook processing
- Clear browser cache
- Update client storage
Transfer Failed
- Check API permissions
- Verify subscription status
- Validate metadata format
- Check webhook delivery
Example Implementation
Complete transfer flow with UI:
class SubscriptionManager {
async transferOwnership(subscriptionId, newUsername) {
try {
// 1. Verify current access
const { purchases } = await iaptic.getPurchases(subscriptionId);
if (!purchases.length) {
throw new Error('Subscription not found');
}
// 2. Update ownership
await stripe.subscriptions.update(subscriptionId, {
metadata: {
application_username: newUsername,
previous_username: purchases[0].applicationUsername,
transferred_at: new Date().toISOString()
}
});
// 3. Update local storage
localStorage.removeItem('stripe_access_key');
// 4. Notify users
await this.notifyUsers(purchases[0], newUsername);
return true;
} catch (error) {
console.error('Transfer failed:', error);
throw error;
}
}
async notifyUsers(purchase, newUsername) {
// Implement your notification logic
}
}