polar-ruby 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +50 -0
- data/DEVELOPMENT.md +329 -0
- data/EXAMPLES.md +385 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +115 -0
- data/LICENSE +23 -0
- data/PROJECT_SUMMARY.md +256 -0
- data/README.md +635 -0
- data/Rakefile +24 -0
- data/examples/demo.rb +106 -0
- data/lib/polar/authentication.rb +83 -0
- data/lib/polar/client.rb +144 -0
- data/lib/polar/configuration.rb +46 -0
- data/lib/polar/customer_portal/benefit_grants.rb +41 -0
- data/lib/polar/customer_portal/customers.rb +69 -0
- data/lib/polar/customer_portal/license_keys.rb +70 -0
- data/lib/polar/customer_portal/orders.rb +82 -0
- data/lib/polar/customer_portal/subscriptions.rb +51 -0
- data/lib/polar/errors.rb +96 -0
- data/lib/polar/http_client.rb +150 -0
- data/lib/polar/pagination.rb +133 -0
- data/lib/polar/resources/base.rb +47 -0
- data/lib/polar/resources/benefits.rb +64 -0
- data/lib/polar/resources/checkouts.rb +75 -0
- data/lib/polar/resources/customers.rb +120 -0
- data/lib/polar/resources/events.rb +45 -0
- data/lib/polar/resources/files.rb +57 -0
- data/lib/polar/resources/license_keys.rb +81 -0
- data/lib/polar/resources/metrics.rb +30 -0
- data/lib/polar/resources/oauth2.rb +61 -0
- data/lib/polar/resources/orders.rb +54 -0
- data/lib/polar/resources/organizations.rb +41 -0
- data/lib/polar/resources/payments.rb +29 -0
- data/lib/polar/resources/products.rb +58 -0
- data/lib/polar/resources/subscriptions.rb +55 -0
- data/lib/polar/resources/webhooks.rb +81 -0
- data/lib/polar/version.rb +5 -0
- data/lib/polar/webhooks.rb +174 -0
- data/lib/polar.rb +65 -0
- metadata +239 -0
data/README.md
ADDED
@@ -0,0 +1,635 @@
|
|
1
|
+
# Polar Ruby SDK
|
2
|
+
|
3
|
+
> **Note:** This SDK was generated with the help of AI and is **not an official SDK from Polar.sh**. It is a community project and not affiliated with or endorsed by Polar.sh. Contributions, suggestions, and improvements are very welcome!
|
4
|
+
|
5
|
+
A comprehensive Ruby SDK for [Polar.sh](https://polar.sh), providing easy integration with their payment infrastructure, subscription management, and merchant services.
|
6
|
+
|
7
|
+
[](https://badge.fury.io/rb/polar-ruby)
|
8
|
+
[](https://www.ruby-lang.org/)
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
10
|
+
|
11
|
+
## Features
|
12
|
+
|
13
|
+
- **Complete API Coverage**: Access all Polar.sh API endpoints
|
14
|
+
- **Type Safety**: Well-structured response objects and error handling
|
15
|
+
- **Authentication**: Support for Organization Access Tokens and Customer Sessions
|
16
|
+
- **Pagination**: Built-in pagination support for list endpoints
|
17
|
+
- **Retry Logic**: Automatic retries with exponential backoff
|
18
|
+
- **Webhook Verification**: Secure webhook signature validation
|
19
|
+
- **Environment Support**: Production and sandbox environments
|
20
|
+
- **Customer Portal**: Dedicated customer-facing API endpoints
|
21
|
+
- **Ruby Compatibility**: Supports Ruby 2.7+
|
22
|
+
|
23
|
+
## Table of Contents
|
24
|
+
|
25
|
+
- [Installation](#installation)
|
26
|
+
- [Quick Start](#quick-start)
|
27
|
+
- [Authentication](#authentication)
|
28
|
+
- [Configuration](#configuration)
|
29
|
+
- [Core API Resources](#core-api-resources)
|
30
|
+
- [Customer Portal API](#customer-portal-api)
|
31
|
+
- [Pagination](#pagination)
|
32
|
+
- [Error Handling](#error-handling)
|
33
|
+
- [Webhook Verification](#webhook-verification)
|
34
|
+
- [Environment Support](#environment-support)
|
35
|
+
- [Examples](#examples)
|
36
|
+
- [Development](#development)
|
37
|
+
- [Contributing](#contributing)
|
38
|
+
|
39
|
+
## Installation
|
40
|
+
|
41
|
+
Add this line to your application's Gemfile:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
gem 'polar-ruby'
|
45
|
+
```
|
46
|
+
|
47
|
+
And then execute:
|
48
|
+
|
49
|
+
```bash
|
50
|
+
bundle install
|
51
|
+
```
|
52
|
+
|
53
|
+
Or install it yourself as:
|
54
|
+
|
55
|
+
```bash
|
56
|
+
gem install polar-ruby
|
57
|
+
```
|
58
|
+
|
59
|
+
## Quick Start
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
require 'polar'
|
63
|
+
|
64
|
+
# Initialize client with Organization Access Token
|
65
|
+
client = Polar.new(access_token: 'polar_oat_your_token_here')
|
66
|
+
|
67
|
+
# List organizations
|
68
|
+
organizations = client.organizations.list.auto_paginate
|
69
|
+
puts organizations.first
|
70
|
+
|
71
|
+
# Create a product
|
72
|
+
product = client.products.create({
|
73
|
+
name: "Premium Plan",
|
74
|
+
description: "Access to premium features",
|
75
|
+
organization_id: "org_123"
|
76
|
+
})
|
77
|
+
|
78
|
+
# List customers with pagination
|
79
|
+
client.customers.list.each do |customer|
|
80
|
+
puts "Customer: #{customer['name']} (#{customer['email']})"
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
## Authentication
|
85
|
+
|
86
|
+
### Organization Access Tokens (OAT)
|
87
|
+
|
88
|
+
Use an OAT to act on behalf of your organization. Create tokens in your organization settings.
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
# Via initialization
|
92
|
+
client = Polar.new(access_token: 'polar_oat_your_token_here')
|
93
|
+
|
94
|
+
# Via environment variable
|
95
|
+
ENV['POLAR_ACCESS_TOKEN'] = 'polar_oat_your_token_here'
|
96
|
+
client = Polar.new
|
97
|
+
|
98
|
+
# Via global configuration
|
99
|
+
Polar.configure do |config|
|
100
|
+
config.access_token = 'polar_oat_your_token_here'
|
101
|
+
end
|
102
|
+
client = Polar.new
|
103
|
+
```
|
104
|
+
|
105
|
+
### Customer Sessions
|
106
|
+
|
107
|
+
For customer-facing operations, use customer session tokens:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
# Customer portal operations require customer session
|
111
|
+
customer_client = Polar.new(customer_session: 'customer_session_token')
|
112
|
+
|
113
|
+
# Or pass session token to individual calls
|
114
|
+
orders = client.customer_portal.orders.list(customer_session: 'customer_session_token')
|
115
|
+
```
|
116
|
+
|
117
|
+
## Configuration
|
118
|
+
|
119
|
+
### Global Configuration
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
Polar.configure do |config|
|
123
|
+
config.access_token = 'polar_oat_your_token_here'
|
124
|
+
config.server = :sandbox # :production (default) or :sandbox
|
125
|
+
config.timeout = 30 # Request timeout in seconds
|
126
|
+
config.retries = 3 # Number of retry attempts
|
127
|
+
config.logger = Logger.new(STDOUT)
|
128
|
+
config.debug = true # Enable debug logging
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
### Per-Client Configuration
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
client = Polar.new(
|
136
|
+
access_token: 'polar_oat_your_token_here',
|
137
|
+
server: :sandbox,
|
138
|
+
timeout: 60,
|
139
|
+
retries: 5,
|
140
|
+
debug: true
|
141
|
+
)
|
142
|
+
```
|
143
|
+
|
144
|
+
### Environment Variables
|
145
|
+
|
146
|
+
The SDK respects the following environment variables:
|
147
|
+
|
148
|
+
- `POLAR_ACCESS_TOKEN`: Default access token
|
149
|
+
- `POLAR_DEBUG`: Enable debug logging (set to 'true')
|
150
|
+
|
151
|
+
## Core API Resources
|
152
|
+
|
153
|
+
### Organizations
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
# List organizations
|
157
|
+
organizations = client.organizations.list.auto_paginate
|
158
|
+
|
159
|
+
# Get organization
|
160
|
+
org = client.organizations.get('org_123')
|
161
|
+
|
162
|
+
# Create organization
|
163
|
+
new_org = client.organizations.create({
|
164
|
+
name: "My Company",
|
165
|
+
slug: "my-company"
|
166
|
+
})
|
167
|
+
|
168
|
+
# Update organization
|
169
|
+
updated_org = client.organizations.update('org_123', { name: "Updated Name" })
|
170
|
+
```
|
171
|
+
|
172
|
+
### Products
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
# List products
|
176
|
+
products = client.products.list(organization_id: 'org_123').auto_paginate
|
177
|
+
|
178
|
+
# Create product
|
179
|
+
product = client.products.create({
|
180
|
+
name: "Premium Plan",
|
181
|
+
description: "Access to premium features",
|
182
|
+
organization_id: "org_123",
|
183
|
+
prices: [
|
184
|
+
{
|
185
|
+
type: "recurring",
|
186
|
+
amount: 2000, # $20.00 in cents
|
187
|
+
currency: "USD",
|
188
|
+
recurring: { interval: "month" }
|
189
|
+
}
|
190
|
+
]
|
191
|
+
})
|
192
|
+
|
193
|
+
# Get product
|
194
|
+
product = client.products.get('prod_123')
|
195
|
+
|
196
|
+
# Update product
|
197
|
+
updated_product = client.products.update('prod_123', { name: "New Name" })
|
198
|
+
```
|
199
|
+
|
200
|
+
### Customers
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
# List customers
|
204
|
+
customers = client.customers.list(organization_id: 'org_123')
|
205
|
+
|
206
|
+
# Create customer
|
207
|
+
customer = client.customers.create({
|
208
|
+
email: "customer@example.com",
|
209
|
+
name: "John Doe",
|
210
|
+
organization_id: "org_123"
|
211
|
+
})
|
212
|
+
|
213
|
+
# Get customer
|
214
|
+
customer = client.customers.get('cust_123')
|
215
|
+
|
216
|
+
# Update customer
|
217
|
+
updated_customer = client.customers.update('cust_123', { name: "Jane Doe" })
|
218
|
+
|
219
|
+
# Get customer by external ID
|
220
|
+
customer = client.customers.get_external('external_123', organization_id: 'org_123')
|
221
|
+
```
|
222
|
+
|
223
|
+
### Orders
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
# List orders
|
227
|
+
orders = client.orders.list(organization_id: 'org_123')
|
228
|
+
|
229
|
+
# Get order
|
230
|
+
order = client.orders.get('order_123')
|
231
|
+
|
232
|
+
# Update order
|
233
|
+
updated_order = client.orders.update('order_123', { metadata: { key: "value" } })
|
234
|
+
|
235
|
+
# Generate invoice
|
236
|
+
invoice = client.orders.generate_invoice('order_123')
|
237
|
+
```
|
238
|
+
|
239
|
+
### Payments
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
# List payments
|
243
|
+
payments = client.payments.list(organization_id: 'org_123')
|
244
|
+
|
245
|
+
# Get payment
|
246
|
+
payment = client.payments.get('pay_123')
|
247
|
+
```
|
248
|
+
|
249
|
+
### Subscriptions
|
250
|
+
|
251
|
+
```ruby
|
252
|
+
# List subscriptions
|
253
|
+
subscriptions = client.subscriptions.list(organization_id: 'org_123')
|
254
|
+
|
255
|
+
# Get subscription
|
256
|
+
subscription = client.subscriptions.get('sub_123')
|
257
|
+
|
258
|
+
# Update subscription
|
259
|
+
updated_sub = client.subscriptions.update('sub_123', { metadata: { key: "value" } })
|
260
|
+
|
261
|
+
# Cancel subscription
|
262
|
+
cancelled_sub = client.subscriptions.revoke('sub_123')
|
263
|
+
```
|
264
|
+
|
265
|
+
### Checkouts
|
266
|
+
|
267
|
+
```ruby
|
268
|
+
# Create checkout session
|
269
|
+
checkout = client.checkouts.create({
|
270
|
+
product_price_id: "price_123",
|
271
|
+
success_url: "https://yoursite.com/success",
|
272
|
+
cancel_url: "https://yoursite.com/cancel",
|
273
|
+
customer_data: {
|
274
|
+
email: "customer@example.com"
|
275
|
+
}
|
276
|
+
})
|
277
|
+
|
278
|
+
# Get checkout session
|
279
|
+
checkout = client.checkouts.get('checkout_123')
|
280
|
+
|
281
|
+
# Client-side operations (no auth required)
|
282
|
+
checkout = client.checkouts.client_get('checkout_123')
|
283
|
+
updated_checkout = client.checkouts.client_update('checkout_123', { customer_data: { name: "John" } })
|
284
|
+
confirmed_checkout = client.checkouts.client_confirm('checkout_123')
|
285
|
+
```
|
286
|
+
|
287
|
+
## Customer Portal API
|
288
|
+
|
289
|
+
The Customer Portal API provides customer-facing endpoints with proper scoping:
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
# Initialize with customer session
|
293
|
+
customer_client = Polar.new(customer_session: 'customer_session_token')
|
294
|
+
|
295
|
+
# Or pass session to individual calls
|
296
|
+
session_token = 'customer_session_token'
|
297
|
+
|
298
|
+
# Get customer information
|
299
|
+
customer = client.customer_portal.customers.get(customer_session: session_token)
|
300
|
+
|
301
|
+
# List customer orders
|
302
|
+
orders = client.customer_portal.orders.list(customer_session: session_token)
|
303
|
+
|
304
|
+
# Get specific order
|
305
|
+
order = client.customer_portal.orders.get('order_123', customer_session: session_token)
|
306
|
+
|
307
|
+
# List customer subscriptions
|
308
|
+
subscriptions = client.customer_portal.subscriptions.list(customer_session: session_token)
|
309
|
+
|
310
|
+
# Cancel subscription
|
311
|
+
client.customer_portal.subscriptions.cancel('sub_123', customer_session: session_token)
|
312
|
+
|
313
|
+
# List license keys
|
314
|
+
license_keys = client.customer_portal.license_keys.list(customer_session: session_token)
|
315
|
+
|
316
|
+
# Validate license key (no auth required)
|
317
|
+
validation = client.customer_portal.license_keys.validate('license_key_123')
|
318
|
+
|
319
|
+
# Activate license key
|
320
|
+
activation = client.customer_portal.license_keys.activate('license_key_123', {
|
321
|
+
label: "Development Machine"
|
322
|
+
})
|
323
|
+
```
|
324
|
+
|
325
|
+
## Pagination
|
326
|
+
|
327
|
+
The SDK provides automatic pagination support:
|
328
|
+
|
329
|
+
```ruby
|
330
|
+
# Auto-paginate (loads all pages into memory)
|
331
|
+
all_customers = client.customers.list.auto_paginate
|
332
|
+
|
333
|
+
# Manual pagination
|
334
|
+
customers_paginated = client.customers.list(organization_id: 'org_123')
|
335
|
+
|
336
|
+
# Iterate through all pages
|
337
|
+
customers_paginated.each do |customer|
|
338
|
+
puts "Customer: #{customer['name']}"
|
339
|
+
end
|
340
|
+
|
341
|
+
# Get specific page
|
342
|
+
page_2 = customers_paginated.page(2)
|
343
|
+
|
344
|
+
# Check pagination info
|
345
|
+
puts "Total: #{customers_paginated.count}"
|
346
|
+
puts "Pages: #{customers_paginated.total_pages}"
|
347
|
+
```
|
348
|
+
|
349
|
+
## Error Handling
|
350
|
+
|
351
|
+
The SDK provides comprehensive error handling:
|
352
|
+
|
353
|
+
```ruby
|
354
|
+
begin
|
355
|
+
customer = client.customers.get('invalid_id')
|
356
|
+
rescue Polar::NotFoundError => e
|
357
|
+
puts "Customer not found: #{e.message}"
|
358
|
+
rescue Polar::UnauthorizedError => e
|
359
|
+
puts "Authentication failed: #{e.message}"
|
360
|
+
rescue Polar::ValidationError => e
|
361
|
+
puts "Validation error: #{e.message}"
|
362
|
+
puts "Status: #{e.status_code}"
|
363
|
+
puts "Body: #{e.body}"
|
364
|
+
rescue Polar::HTTPError => e
|
365
|
+
puts "HTTP error: #{e.status_code} - #{e.message}"
|
366
|
+
rescue Polar::ConnectionError => e
|
367
|
+
puts "Connection error: #{e.message}"
|
368
|
+
rescue Polar::TimeoutError => e
|
369
|
+
puts "Request timed out: #{e.message}"
|
370
|
+
rescue Polar::Error => e
|
371
|
+
puts "Polar SDK error: #{e.message}"
|
372
|
+
end
|
373
|
+
```
|
374
|
+
|
375
|
+
### Error Types
|
376
|
+
|
377
|
+
- `Polar::HTTPError` - Base HTTP error class
|
378
|
+
- `Polar::BadRequestError` - 400 Bad Request
|
379
|
+
- `Polar::UnauthorizedError` - 401 Unauthorized
|
380
|
+
- `Polar::ForbiddenError` - 403 Forbidden
|
381
|
+
- `Polar::NotFoundError` - 404 Not Found
|
382
|
+
- `Polar::UnprocessableEntityError` - 422 Validation Error
|
383
|
+
- `Polar::TooManyRequestsError` - 429 Rate Limited
|
384
|
+
- `Polar::InternalServerError` - 500 Server Error
|
385
|
+
- `Polar::ConnectionError` - Network connection failed
|
386
|
+
- `Polar::TimeoutError` - Request timeout
|
387
|
+
- `Polar::WebhookVerificationError` - Webhook signature verification failed
|
388
|
+
|
389
|
+
## Webhook Verification
|
390
|
+
|
391
|
+
Verify webhook signatures to ensure requests are from Polar:
|
392
|
+
|
393
|
+
```ruby
|
394
|
+
# In your webhook endpoint (Rails example)
|
395
|
+
class WebhooksController < ApplicationController
|
396
|
+
skip_before_action :verify_authenticity_token
|
397
|
+
|
398
|
+
def polar_webhook
|
399
|
+
payload = request.body.read
|
400
|
+
headers = request.headers
|
401
|
+
secret = ENV['POLAR_WEBHOOK_SECRET']
|
402
|
+
|
403
|
+
begin
|
404
|
+
event = Polar::Webhooks.validate_event(payload, headers, secret)
|
405
|
+
|
406
|
+
# Process the event
|
407
|
+
case event['type']
|
408
|
+
when 'order.created'
|
409
|
+
handle_order_created(event['data'])
|
410
|
+
when 'subscription.cancelled'
|
411
|
+
handle_subscription_cancelled(event['data'])
|
412
|
+
end
|
413
|
+
|
414
|
+
render json: { status: 'ok' }
|
415
|
+
rescue Polar::WebhookVerificationError => e
|
416
|
+
render json: { error: 'Invalid signature' }, status: 403
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
private
|
421
|
+
|
422
|
+
def handle_order_created(order_data)
|
423
|
+
# Process order creation
|
424
|
+
puts "New order: #{order_data['id']}"
|
425
|
+
end
|
426
|
+
|
427
|
+
def handle_subscription_cancelled(subscription_data)
|
428
|
+
# Process subscription cancellation
|
429
|
+
puts "Cancelled subscription: #{subscription_data['id']}"
|
430
|
+
end
|
431
|
+
end
|
432
|
+
```
|
433
|
+
|
434
|
+
### Manual Webhook Verification
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
# Verify signature manually
|
438
|
+
valid = Polar::Webhooks.verify_signature(
|
439
|
+
payload,
|
440
|
+
timestamp,
|
441
|
+
signature,
|
442
|
+
secret
|
443
|
+
)
|
444
|
+
|
445
|
+
# Parse event type
|
446
|
+
event_type = Polar::Webhooks.parse_event_type(payload)
|
447
|
+
|
448
|
+
# Check specific event type
|
449
|
+
is_order_event = Polar::Webhooks.event_type?(payload, 'order.created')
|
450
|
+
|
451
|
+
# Create event wrapper
|
452
|
+
event = Polar::Webhooks::Event.new(payload)
|
453
|
+
puts "Event ID: #{event.id}"
|
454
|
+
puts "Event Type: #{event.type}"
|
455
|
+
puts "Is subscription event: #{event.subscription_event?}"
|
456
|
+
```
|
457
|
+
|
458
|
+
## Environment Support
|
459
|
+
|
460
|
+
### Production Environment
|
461
|
+
|
462
|
+
```ruby
|
463
|
+
# Default environment
|
464
|
+
client = Polar.new(access_token: 'polar_oat_prod_token')
|
465
|
+
|
466
|
+
# Explicit production
|
467
|
+
client = Polar.new(
|
468
|
+
access_token: 'polar_oat_prod_token',
|
469
|
+
server: :production
|
470
|
+
)
|
471
|
+
```
|
472
|
+
|
473
|
+
### Sandbox Environment
|
474
|
+
|
475
|
+
```ruby
|
476
|
+
# Sandbox environment for testing
|
477
|
+
client = Polar.new(
|
478
|
+
access_token: 'polar_oat_sandbox_token',
|
479
|
+
server: :sandbox
|
480
|
+
)
|
481
|
+
|
482
|
+
# Custom base URL
|
483
|
+
client = Polar.new(
|
484
|
+
access_token: 'polar_oat_token',
|
485
|
+
base_url: 'https://custom-api.polar.sh/v1'
|
486
|
+
)
|
487
|
+
```
|
488
|
+
|
489
|
+
## Examples
|
490
|
+
|
491
|
+
### E-commerce Integration
|
492
|
+
|
493
|
+
```ruby
|
494
|
+
class PolarService
|
495
|
+
def initialize
|
496
|
+
@client = Polar.new(access_token: ENV['POLAR_ACCESS_TOKEN'])
|
497
|
+
end
|
498
|
+
|
499
|
+
def create_checkout_for_product(product_id, customer_email, success_url, cancel_url)
|
500
|
+
@client.checkouts.create({
|
501
|
+
product_price_id: product_id,
|
502
|
+
success_url: success_url,
|
503
|
+
cancel_url: cancel_url,
|
504
|
+
customer_data: {
|
505
|
+
email: customer_email
|
506
|
+
}
|
507
|
+
})
|
508
|
+
end
|
509
|
+
|
510
|
+
def get_customer_orders(customer_id)
|
511
|
+
@client.orders.list(customer_id: customer_id).auto_paginate
|
512
|
+
end
|
513
|
+
|
514
|
+
def create_subscription_checkout(price_id, customer_data)
|
515
|
+
@client.checkouts.create({
|
516
|
+
product_price_id: price_id,
|
517
|
+
success_url: "#{ENV['APP_URL']}/subscription/success",
|
518
|
+
cancel_url: "#{ENV['APP_URL']}/subscription/cancel",
|
519
|
+
customer_data: customer_data
|
520
|
+
})
|
521
|
+
end
|
522
|
+
end
|
523
|
+
```
|
524
|
+
|
525
|
+
### License Key Management
|
526
|
+
|
527
|
+
```ruby
|
528
|
+
class LicenseManager
|
529
|
+
def initialize
|
530
|
+
@client = Polar.new(access_token: ENV['POLAR_ACCESS_TOKEN'])
|
531
|
+
end
|
532
|
+
|
533
|
+
def validate_license(license_key)
|
534
|
+
result = @client.customer_portal.license_keys.validate(license_key)
|
535
|
+
{
|
536
|
+
valid: result['valid'],
|
537
|
+
customer: result['customer'],
|
538
|
+
product: result['product']
|
539
|
+
}
|
540
|
+
rescue Polar::Error => e
|
541
|
+
{ valid: false, error: e.message }
|
542
|
+
end
|
543
|
+
|
544
|
+
def activate_license(license_key, machine_info)
|
545
|
+
@client.customer_portal.license_keys.activate(license_key, {
|
546
|
+
label: machine_info[:name],
|
547
|
+
metadata: {
|
548
|
+
os: machine_info[:os],
|
549
|
+
version: machine_info[:version]
|
550
|
+
}
|
551
|
+
})
|
552
|
+
rescue Polar::Error => e
|
553
|
+
{ error: e.message }
|
554
|
+
end
|
555
|
+
end
|
556
|
+
```
|
557
|
+
|
558
|
+
### Subscription Management
|
559
|
+
|
560
|
+
```ruby
|
561
|
+
class SubscriptionManager
|
562
|
+
def initialize
|
563
|
+
@client = Polar.new(access_token: ENV['POLAR_ACCESS_TOKEN'])
|
564
|
+
end
|
565
|
+
|
566
|
+
def get_customer_subscriptions(customer_session)
|
567
|
+
@client.customer_portal.subscriptions.list(
|
568
|
+
customer_session: customer_session
|
569
|
+
).auto_paginate
|
570
|
+
end
|
571
|
+
|
572
|
+
def cancel_subscription(subscription_id, customer_session)
|
573
|
+
@client.customer_portal.subscriptions.cancel(
|
574
|
+
subscription_id,
|
575
|
+
customer_session: customer_session
|
576
|
+
)
|
577
|
+
end
|
578
|
+
|
579
|
+
def update_subscription(subscription_id, updates, customer_session)
|
580
|
+
@client.customer_portal.subscriptions.update(
|
581
|
+
subscription_id,
|
582
|
+
updates,
|
583
|
+
customer_session: customer_session
|
584
|
+
)
|
585
|
+
end
|
586
|
+
end
|
587
|
+
```
|
588
|
+
|
589
|
+
## Development
|
590
|
+
|
591
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
592
|
+
|
593
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
594
|
+
|
595
|
+
### Running Tests
|
596
|
+
|
597
|
+
```bash
|
598
|
+
# Run all tests
|
599
|
+
bundle exec rspec
|
600
|
+
|
601
|
+
# Run with coverage
|
602
|
+
bundle exec rspec --format documentation
|
603
|
+
|
604
|
+
# Run specific test file
|
605
|
+
bundle exec rspec spec/polar/client_spec.rb
|
606
|
+
```
|
607
|
+
|
608
|
+
### Documentation
|
609
|
+
|
610
|
+
Generate documentation:
|
611
|
+
|
612
|
+
```bash
|
613
|
+
bundle exec yard doc
|
614
|
+
```
|
615
|
+
|
616
|
+
## Contributing
|
617
|
+
|
618
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/polarsource/polar-ruby. This project is intended to be a safe, welcoming space for collaboration.
|
619
|
+
|
620
|
+
1. Fork it
|
621
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
622
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
623
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
624
|
+
5. Create new Pull Request
|
625
|
+
|
626
|
+
## License
|
627
|
+
|
628
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
629
|
+
|
630
|
+
## Support
|
631
|
+
|
632
|
+
- [Polar.sh Documentation](https://polar.sh/docs)
|
633
|
+
- [API Reference](https://polar.sh/docs/api-reference)
|
634
|
+
- [GitHub Issues](https://github.com/polarsource/polar-ruby/issues)
|
635
|
+
- [Polar Discord Community](https://discord.gg/polar)
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
RuboCop::RakeTask.new
|
9
|
+
|
10
|
+
desc 'Run tests with coverage'
|
11
|
+
task :test_with_coverage do
|
12
|
+
ENV['COVERAGE'] = 'true'
|
13
|
+
Rake::Task[:spec].invoke
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation'
|
17
|
+
task :doc do
|
18
|
+
system('yard doc')
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Run all quality checks'
|
22
|
+
task quality: %i[rubocop spec]
|
23
|
+
|
24
|
+
task default: :quality
|