init
This commit is contained in:
@@ -0,0 +1,396 @@
|
||||
# Polar Benefits
|
||||
|
||||
Automated benefit delivery system for digital products.
|
||||
|
||||
## Philosophy
|
||||
|
||||
Configure once, automatic delivery. Polar handles granting and revoking based on subscription state.
|
||||
|
||||
## Benefit Types
|
||||
|
||||
### 1. License Keys
|
||||
|
||||
**Auto-generate unique keys with customizable branding.**
|
||||
|
||||
**Create:**
|
||||
```typescript
|
||||
const benefit = await polar.benefits.create({
|
||||
type: "license_keys",
|
||||
organization_id: "org_xxx",
|
||||
description: "Software License",
|
||||
properties: {
|
||||
prefix: "MYAPP",
|
||||
expires: false,
|
||||
activations: 1,
|
||||
limit_usage: false
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Validation API (unauthenticated):**
|
||||
```typescript
|
||||
const validation = await polar.licenses.validate({
|
||||
key: "MYAPP-XXXX-XXXX-XXXX",
|
||||
organization_id: "org_xxx"
|
||||
});
|
||||
|
||||
if (validation.valid) {
|
||||
// Grant access
|
||||
}
|
||||
```
|
||||
|
||||
**Activation/Deactivation:**
|
||||
```typescript
|
||||
await polar.licenses.activate(licenseKey, {
|
||||
label: "User's MacBook Pro"
|
||||
});
|
||||
|
||||
await polar.licenses.deactivate(activationId);
|
||||
```
|
||||
|
||||
**Auto-revoke:** On subscription cancellation or refund
|
||||
|
||||
### 2. GitHub Repository Access
|
||||
|
||||
**Auto-invite to private repos with permission management.**
|
||||
|
||||
**Create:**
|
||||
```typescript
|
||||
const benefit = await polar.benefits.create({
|
||||
type: "github_repository",
|
||||
organization_id: "org_xxx",
|
||||
description: "Access to private repo",
|
||||
properties: {
|
||||
repository_owner: "myorg",
|
||||
repository_name: "private-repo",
|
||||
permission: "pull" // or "push", "admin"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Multiple Repos:**
|
||||
```typescript
|
||||
{
|
||||
properties: {
|
||||
repositories: [
|
||||
{ owner: "myorg", name: "repo1", permission: "pull" },
|
||||
{ owner: "myorg", name: "repo2", permission: "push" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Behavior:**
|
||||
- Auto-invite on subscription activation
|
||||
- Permission managed by Polar
|
||||
- Auto-revoke on cancellation
|
||||
|
||||
### 3. Discord Access
|
||||
|
||||
**Server invites and role assignment.**
|
||||
|
||||
**Create:**
|
||||
```typescript
|
||||
const benefit = await polar.benefits.create({
|
||||
type: "discord",
|
||||
organization_id: "org_xxx",
|
||||
description: "Premium Discord role",
|
||||
properties: {
|
||||
guild_id: "123456789",
|
||||
role_id: "987654321"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Multiple Roles:**
|
||||
```typescript
|
||||
{
|
||||
properties: {
|
||||
guild_id: "123456789",
|
||||
roles: [
|
||||
{ role_id: "role1", name: "Premium" },
|
||||
{ role_id: "role2", name: "Supporter" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Requirements:**
|
||||
- Polar Discord app must be added to server
|
||||
- Configure in Polar dashboard
|
||||
|
||||
**Behavior:**
|
||||
- Auto-invite to server
|
||||
- Assign roles automatically
|
||||
- Remove roles on cancellation
|
||||
|
||||
### 4. Downloadable Files
|
||||
|
||||
**Secure file delivery up to 10GB each.**
|
||||
|
||||
**Create:**
|
||||
```typescript
|
||||
const benefit = await polar.benefits.create({
|
||||
type: "downloadable",
|
||||
organization_id: "org_xxx",
|
||||
description: "Premium templates",
|
||||
properties: {
|
||||
files: [
|
||||
{ name: "template1.zip", size: 5000000 },
|
||||
{ name: "template2.psd", size: 10000000 }
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Upload Files:**
|
||||
- Via Polar dashboard
|
||||
- Secure storage
|
||||
- Access control
|
||||
|
||||
**Customer Access:**
|
||||
- Download links in customer portal
|
||||
- Secure, time-limited URLs
|
||||
- Multiple files supported
|
||||
|
||||
### 5. Meter Credits
|
||||
|
||||
**Pre-purchased usage for usage-based billing.**
|
||||
|
||||
**Create:**
|
||||
```typescript
|
||||
const benefit = await polar.benefits.create({
|
||||
type: "custom",
|
||||
organization_id: "org_xxx",
|
||||
description: "10,000 API credits",
|
||||
properties: {
|
||||
meter_id: "meter_xxx",
|
||||
credits: 10000
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Automatic Application:**
|
||||
- Credits added on subscription start
|
||||
- Balance tracked via API
|
||||
- Depletes with usage
|
||||
|
||||
**Balance Check:**
|
||||
```typescript
|
||||
const balance = await polar.meters.getBalance({
|
||||
customer_id: "cust_xxx",
|
||||
meter_id: "meter_xxx"
|
||||
});
|
||||
```
|
||||
|
||||
### 6. Custom Benefits
|
||||
|
||||
**Flexible placeholder for manual fulfillment.**
|
||||
|
||||
**Create:**
|
||||
```typescript
|
||||
const benefit = await polar.benefits.create({
|
||||
type: "custom",
|
||||
organization_id: "org_xxx",
|
||||
description: "Priority support via email",
|
||||
properties: {
|
||||
note: "Email support@example.com with your order ID for priority support"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Use Cases:**
|
||||
- Cal.com booking links
|
||||
- Email support access
|
||||
- Community forum access
|
||||
- Manual onboarding
|
||||
|
||||
## Benefit Grants
|
||||
|
||||
**Link between customer and benefit.**
|
||||
|
||||
### States
|
||||
- `created` - Grant created
|
||||
- `active` - Benefit delivered
|
||||
- `revoked` - Access removed
|
||||
|
||||
### Webhooks
|
||||
- `benefit_grant.created` - Grant created
|
||||
- `benefit_grant.updated` - Status changed
|
||||
- `benefit_grant.revoked` - Access revoked
|
||||
|
||||
### Auto-revoke Triggers
|
||||
- Subscription canceled
|
||||
- Subscription revoked
|
||||
- Refund processed
|
||||
- Product changed (if benefit not on new product)
|
||||
|
||||
### Querying Grants
|
||||
```typescript
|
||||
const grants = await polar.benefitGrants.list({
|
||||
customer_id: "cust_xxx",
|
||||
benefit_id: "benefit_xxx",
|
||||
is_granted: true
|
||||
});
|
||||
```
|
||||
|
||||
## Attaching Benefits to Products
|
||||
|
||||
### Via API
|
||||
```typescript
|
||||
await polar.products.updateBenefits(productId, {
|
||||
benefits: [benefitId1, benefitId2, benefitId3]
|
||||
});
|
||||
```
|
||||
|
||||
### Via Dashboard
|
||||
1. Navigate to product
|
||||
2. Benefits tab
|
||||
3. Select benefits to attach
|
||||
4. Save
|
||||
|
||||
### Order
|
||||
- Benefits granted in order attached
|
||||
- Customers see in that order
|
||||
- Reorder via dashboard or API
|
||||
|
||||
## Customer Experience
|
||||
|
||||
### Viewing Benefits
|
||||
- Customer portal shows all active benefits
|
||||
- Clear instructions for each type
|
||||
- Download links for files
|
||||
- License keys displayed
|
||||
|
||||
### Accessing Benefits
|
||||
```typescript
|
||||
// Generate customer portal link
|
||||
const session = await polar.customerSessions.create({
|
||||
external_customer_id: userId
|
||||
});
|
||||
|
||||
// Customer sees:
|
||||
// - Active subscriptions
|
||||
// - Granted benefits
|
||||
// - Download links
|
||||
// - License keys
|
||||
// - Instructions
|
||||
```
|
||||
|
||||
## Implementation Patterns
|
||||
|
||||
### License Key Validation
|
||||
```typescript
|
||||
// In your application
|
||||
async function validateLicense(key) {
|
||||
try {
|
||||
const result = await polar.licenses.validate({
|
||||
key: key,
|
||||
organization_id: process.env.POLAR_ORG_ID
|
||||
});
|
||||
|
||||
if (!result.valid) {
|
||||
return { valid: false, reason: 'Invalid license' };
|
||||
}
|
||||
|
||||
if (result.limit_usage && result.usage >= result.limit_usage) {
|
||||
return { valid: false, reason: 'Usage limit exceeded' };
|
||||
}
|
||||
|
||||
return { valid: true, customer: result.customer };
|
||||
} catch (error) {
|
||||
console.error('License validation failed:', error);
|
||||
return { valid: false, reason: 'Validation error' };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GitHub Access Check
|
||||
```typescript
|
||||
// Listen to benefit grant webhook
|
||||
app.post('/webhook/polar', async (req, res) => {
|
||||
const event = validateEvent(req.body, req.headers, secret);
|
||||
|
||||
if (event.type === 'benefit_grant.created') {
|
||||
const grant = event.data;
|
||||
|
||||
if (grant.benefit.type === 'github_repository') {
|
||||
// Update user's GitHub access in your system
|
||||
await updateGitHubAccess(grant.customer.external_id, true);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({ received: true });
|
||||
});
|
||||
```
|
||||
|
||||
### Discord Role Sync
|
||||
```typescript
|
||||
// Monitor benefit grants
|
||||
if (event.type === 'benefit_grant.created') {
|
||||
const grant = event.data;
|
||||
|
||||
if (grant.benefit.type === 'discord') {
|
||||
// Notify user to connect Discord
|
||||
await sendDiscordInvite(grant.customer.email);
|
||||
}
|
||||
}
|
||||
|
||||
if (event.type === 'benefit_grant.revoked') {
|
||||
const grant = event.data;
|
||||
|
||||
if (grant.benefit.type === 'discord') {
|
||||
// Roles removed automatically by Polar
|
||||
await notifyRoleRemoval(grant.customer.external_id);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Benefit Selection:**
|
||||
- Choose appropriate benefit types
|
||||
- Consider automation capabilities
|
||||
- Plan for revocation scenarios
|
||||
|
||||
2. **License Keys:**
|
||||
- Set appropriate activation limits
|
||||
- Monitor usage patterns
|
||||
- Provide clear validation errors
|
||||
- Allow customers to manage activations
|
||||
|
||||
3. **GitHub Access:**
|
||||
- Set minimum required permissions
|
||||
- Use separate repos for different tiers
|
||||
- Monitor repository access
|
||||
- Communicate access removal
|
||||
|
||||
4. **Discord Roles:**
|
||||
- Clear role hierarchy
|
||||
- Meaningful role names
|
||||
- Separate roles per product tier
|
||||
- Welcome messages for new members
|
||||
|
||||
5. **Files:**
|
||||
- Organize files clearly
|
||||
- Provide README/instructions
|
||||
- Keep files updated
|
||||
- Version control important files
|
||||
|
||||
6. **Credits:**
|
||||
- Clear credit value communication
|
||||
- Usage tracking and display
|
||||
- Alerts near depletion
|
||||
- Easy credit top-up
|
||||
|
||||
7. **Custom Benefits:**
|
||||
- Clear, actionable instructions
|
||||
- Provide contact information
|
||||
- Set expectations for timing
|
||||
- Track manual fulfillment
|
||||
|
||||
8. **Customer Communication:**
|
||||
- Welcome email with benefit access info
|
||||
- Instructions for each benefit type
|
||||
- Support contact for issues
|
||||
- Revocation warnings before cancellation
|
||||
Reference in New Issue
Block a user