Files
english/.opencode/skills/payment-integration/references/polar/benefits.md
2026-04-12 01:06:31 +07:00

397 lines
8.2 KiB
Markdown

# 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