paddle 2.7.1 → 2.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d34df63b33ad8a971eabe70779c7ff47f025a8ab2ef5d96dcea24838c6835419
4
- data.tar.gz: fc46cb72067fc2c22a9c8c011d3dc341329e36edaf089b80fce2e048ccba47d6
3
+ metadata.gz: 688edb526349f04a5e5b255f6ca8620388e18f431d152501689b73eee572efaf
4
+ data.tar.gz: 2ce860d28169ed75275c97043c1cc5511460da8377b4e14283be97895f03f71a
5
5
  SHA512:
6
- metadata.gz: c02dfdef5f72c98767c66bbf841981a31edbc762febc19aa691230a19961d80565dfd40a61ef6b7e26c8d124f1a38c33bc48f94de789ae00b188eff10ea301fa
7
- data.tar.gz: a045b9fb22b89645c8b3d3fb6ed4eb7bf3e33d6547b719d521ee977aef9de12bce773ac679c683f6b20a8f0320fb0e71c87f049992210774fca3b59aa85e0d04
6
+ metadata.gz: b3a2fe51d7a3d636f8f1f6cb5427863760da0c7149cc45dcc0c1901a236df86ab97f9ae233f29ddca16ef0c4dd6f08ede0bc727b93d8187f243d2d41c73125eb
7
+ data.tar.gz: 3444042854883edd1ec749d501498fdb242f25f643acb0d8b3d49ef31d1168e4257d8e8c1f07c4cbfcc753a4603c783adf4d6ce0b5cb0c38f3e934848a4548bf
data/Gemfile.lock CHANGED
@@ -1,89 +1,97 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- paddle (2.7.1)
4
+ paddle (2.8)
5
+ cgi
5
6
  faraday (~> 2.11)
6
7
  ostruct (~> 0.6.0)
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
11
- activesupport (7.2.1)
12
+ activesupport (8.1.1)
12
13
  base64
13
14
  bigdecimal
14
15
  concurrent-ruby (~> 1.0, >= 1.3.1)
15
16
  connection_pool (>= 2.2.5)
16
17
  drb
17
18
  i18n (>= 1.6, < 2)
19
+ json
18
20
  logger (>= 1.4.2)
19
21
  minitest (>= 5.1)
20
22
  securerandom (>= 0.3)
21
23
  tzinfo (~> 2.0, >= 2.0.5)
22
- ast (2.4.2)
23
- base64 (0.2.0)
24
- bigdecimal (3.1.8)
25
- concurrent-ruby (1.3.4)
26
- connection_pool (2.4.1)
27
- dotenv (3.1.2)
28
- drb (2.2.1)
29
- faraday (2.12.2)
24
+ uri (>= 0.13.1)
25
+ ast (2.4.3)
26
+ base64 (0.3.0)
27
+ bigdecimal (3.3.1)
28
+ cgi (0.5.1)
29
+ concurrent-ruby (1.3.5)
30
+ connection_pool (3.0.2)
31
+ dotenv (3.2.0)
32
+ drb (2.2.3)
33
+ faraday (2.14.0)
30
34
  faraday-net_http (>= 2.0, < 3.5)
31
35
  json
32
36
  logger
33
- faraday-net_http (3.4.0)
34
- net-http (>= 0.5.0)
35
- i18n (1.14.5)
37
+ faraday-net_http (3.4.2)
38
+ net-http (~> 0.5)
39
+ i18n (1.14.7)
36
40
  concurrent-ruby (~> 1.0)
37
- json (2.7.2)
38
- language_server-protocol (3.17.0.3)
39
- logger (1.6.4)
40
- minitest (5.25.1)
41
- net-http (0.6.0)
42
- uri
43
- ostruct (0.6.0)
44
- parallel (1.26.3)
45
- parser (3.3.5.0)
41
+ json (2.18.0)
42
+ language_server-protocol (3.17.0.5)
43
+ lint_roller (1.1.0)
44
+ logger (1.7.0)
45
+ minitest (5.27.0)
46
+ net-http (0.8.0)
47
+ uri (>= 0.11.1)
48
+ ostruct (0.6.3)
49
+ parallel (1.27.0)
50
+ parser (3.3.10.0)
46
51
  ast (~> 2.4.1)
47
52
  racc
53
+ prism (1.6.0)
48
54
  racc (1.8.1)
49
- rack (3.1.7)
55
+ rack (3.2.4)
50
56
  rainbow (3.1.1)
51
- rake (13.2.1)
52
- regexp_parser (2.9.2)
53
- rubocop (1.66.1)
57
+ rake (13.3.1)
58
+ regexp_parser (2.11.3)
59
+ rubocop (1.81.7)
54
60
  json (~> 2.3)
55
- language_server-protocol (>= 3.17.0)
61
+ language_server-protocol (~> 3.17.0.2)
62
+ lint_roller (~> 1.1.0)
56
63
  parallel (~> 1.10)
57
64
  parser (>= 3.3.0.2)
58
65
  rainbow (>= 2.2.2, < 4.0)
59
- regexp_parser (>= 2.4, < 3.0)
60
- rubocop-ast (>= 1.32.2, < 2.0)
66
+ regexp_parser (>= 2.9.3, < 3.0)
67
+ rubocop-ast (>= 1.47.1, < 2.0)
61
68
  ruby-progressbar (~> 1.7)
62
- unicode-display_width (>= 2.4.0, < 3.0)
63
- rubocop-ast (1.32.3)
64
- parser (>= 3.3.1.0)
65
- rubocop-minitest (0.36.0)
66
- rubocop (>= 1.61, < 2.0)
67
- rubocop-ast (>= 1.31.1, < 2.0)
68
- rubocop-performance (1.21.1)
69
- rubocop (>= 1.48.1, < 2.0)
70
- rubocop-ast (>= 1.31.1, < 2.0)
71
- rubocop-rails (2.26.0)
69
+ unicode-display_width (>= 2.4.0, < 4.0)
70
+ rubocop-ast (1.48.0)
71
+ parser (>= 3.3.7.2)
72
+ prism (~> 1.4)
73
+ rubocop-performance (1.26.1)
74
+ lint_roller (~> 1.1)
75
+ rubocop (>= 1.75.0, < 2.0)
76
+ rubocop-ast (>= 1.47.1, < 2.0)
77
+ rubocop-rails (2.34.2)
72
78
  activesupport (>= 4.2.0)
79
+ lint_roller (~> 1.1)
73
80
  rack (>= 1.1)
74
- rubocop (>= 1.52.0, < 2.0)
75
- rubocop-ast (>= 1.31.1, < 2.0)
76
- rubocop-rails-omakase (1.0.0)
77
- rubocop
78
- rubocop-minitest
79
- rubocop-performance
80
- rubocop-rails
81
+ rubocop (>= 1.75.0, < 2.0)
82
+ rubocop-ast (>= 1.44.0, < 2.0)
83
+ rubocop-rails-omakase (1.1.0)
84
+ rubocop (>= 1.72)
85
+ rubocop-performance (>= 1.24)
86
+ rubocop-rails (>= 2.30)
81
87
  ruby-progressbar (1.13.0)
82
- securerandom (0.3.1)
88
+ securerandom (0.4.1)
83
89
  tzinfo (2.0.6)
84
90
  concurrent-ruby (~> 1.0)
85
- unicode-display_width (2.5.0)
86
- uri (1.0.2)
91
+ unicode-display_width (3.2.0)
92
+ unicode-emoji (~> 4.1)
93
+ unicode-emoji (4.1.0)
94
+ uri (1.1.1)
87
95
  vcr (6.3.1)
88
96
  base64
89
97
 
data/README.md CHANGED
@@ -77,6 +77,57 @@ Paddle::Product.list(per_page: 10, after: "abc123")
77
77
  >
78
78
  > The Paddle API doesn't take `nil` values for optional parameters. If you want to remove a value, you'll need to pass `"null"` instead.
79
79
 
80
+ ### Error Handling
81
+
82
+ When API requests fail, the gem provides detailed error information to help you debug issues. Errors are raised as exceptions with comprehensive details including field-level validation errors.
83
+
84
+ #### Error Structure
85
+
86
+ All errors inherit from `Paddle::ErrorGenerator` and include:
87
+ - HTTP status code
88
+ - Error code from Paddle
89
+ - Detailed error message
90
+ - Field-specific validation errors (when applicable)
91
+ - Documentation URL for more information
92
+ - Request ID for support
93
+
94
+ #### Available Error Classes
95
+
96
+ - `Paddle::Errors::BadRequestError` (400) - Invalid request parameters
97
+ - `Paddle::Errors::AuthenticationMissingError` (401) - Missing or invalid API credentials
98
+ - `Paddle::Errors::ForbiddenError` (403) - Insufficient permissions
99
+ - `Paddle::Errors::EntityNotFoundError` (404) - Resource not found
100
+ - `Paddle::Errors::ConflictError` (409) - Request conflicts with existing data
101
+ - `Paddle::Errors::TooManyRequestsError` (429) - Rate limit exceeded
102
+ - `Paddle::Errors::InternalError` (500) - Server error
103
+ - `Paddle::Errors::ServiceUnavailableError` (503) - Service unavailable
104
+
105
+ #### Error Example
106
+
107
+ When creating a Price with invalid parameters, you'll receive a detailed error:
108
+
109
+ ```ruby
110
+ begin
111
+ Paddle::Price.create(product_id: "pro_123", trial_period: { frequency: "monthly" })
112
+ rescue Paddle::Errors::BadRequestError => e
113
+ puts e.message
114
+ # => Error 400: Invalid request. 'bad_request'
115
+ # Field errors:
116
+ # - trial_period.frequency: Invalid type. Expected: integer, given: string
117
+ # - trial_period: Must validate one and only one schema (oneOf)
118
+ # Documentation: https://developer.paddle.com/v1/errors/shared/bad_request
119
+ # Request ID: e385967f-4298-4240-a971-f988209b32ca
120
+
121
+ # Access error details programmatically
122
+ e.http_status_code #=> 400
123
+ e.paddle_error_code #=> "bad_request"
124
+ e.paddle_error_message #=> "Invalid request."
125
+ e.paddle_errors #=> [{"field"=>"trial_period.frequency", "message"=>"Invalid type. Expected: integer, given: string"}, ...]
126
+ e.documentation_url #=> "https://developer.paddle.com/v1/errors/shared/bad_request"
127
+ e.request_id #=> "e385967f-4298-4240-a971-f988209b32ca"
128
+ end
129
+ ```
130
+
80
131
  ### Updating records
81
132
 
82
133
  For API endpoints that support it, you can use the `update` method to update a record, like so:
@@ -196,6 +247,11 @@ Paddle::Customer.update(id: "ctm_abc123", status: "archived")
196
247
  # Retrieve credit balance for a customer
197
248
  # https://developer.paddle.com/api-reference/customers/list-credit-balances
198
249
  Paddle::Customer.credit(id: "ctm_abc123")
250
+
251
+ # Generate an authentication token for a customer
252
+ # https://developer.paddle.com/api-reference/customers/generate-customer-authentication-token
253
+ Paddle::Customer.auth_token id: "ctm_abc123"
254
+ #=> #<Paddle::CustomerAuthToken customer_auth_token="pca_abc123", expires_at="2025-12-10T16:21:21.554Z">
199
255
  ```
200
256
 
201
257
  ### Addresses
@@ -376,6 +432,22 @@ Paddle::Adjustment.create(
376
432
  Paddle::Adjustment.credit_note(id: "adj_abc123", disposition: "inline")
377
433
  ```
378
434
 
435
+ ### Payment Methods
436
+
437
+ ```ruby
438
+ # List all payment methods for a customer
439
+ # https://developer.paddle.com/api-reference/payment-methods/list-payment-methods
440
+ Paddle::PaymentMethod.list customer: "ctm_abc123"
441
+
442
+ # Retrieve a single payment method for a customer
443
+ # https://developer.paddle.com/api-reference/payment-methods/get-payment-method
444
+ Paddle::PaymentMethod.retrieve customer: "ctm_abc123", id: "paymtd_abc123"
445
+
446
+ # Delete a payment method for a customer
447
+ # https://developer.paddle.com/api-reference/payment-methods/delete-payment-method
448
+ Paddle::PaymentMethod.delete customer: "ctm_abc123", id: "paymtd_abc123"
449
+ ```
450
+
379
451
  ### Event Types
380
452
 
381
453
  ```ruby
@@ -524,6 +596,27 @@ Paddle::SimulationRun.events(simulation_id: "ntfsim_abc123", run_id: "ntfsimrun_
524
596
  Paddle::SimulationRunEvent.replay(simulation_id: "ntfsim_abc123", run_id: "ntfsimrun_abc123", id: "ntfsimevt_abc123")
525
597
  ```
526
598
 
599
+ ### Client Tokens
600
+
601
+ ```ruby
602
+ # List all Client Tokens
603
+ # https://developer.paddle.com/api-reference/client-tokens/list-client-tokens
604
+ Paddle::ClientToken.list
605
+
606
+ # Create a Client Token
607
+ # https://developer.paddle.com/api-reference/client-tokens/create-client-token
608
+ Paddle::ClientToken.create name: "My Token"
609
+
610
+ # Get a Client Token
611
+ # https://developer.paddle.com/api-reference/client-tokens/get-client-token
612
+ Paddle::ClientToken.retrieve id: "ctkn_abc123"
613
+
614
+ # Update a Client Token
615
+ # https://developer.paddle.com/api-reference/client-tokens/update-client-token
616
+ Paddle::ClientToken.update id: "ctkn_abc123", status: "revoked"
617
+ ```
618
+
619
+
527
620
  ## Classic API
528
621
 
529
622
  For accessing the Paddle Classic API
@@ -1,5 +1,7 @@
1
1
  module Paddle
2
2
  class Collection
3
+ include Enumerable
4
+
3
5
  attr_reader :data, :total
4
6
 
5
7
  def self.from_response(response, type:)
@@ -3,6 +3,9 @@ module Paddle
3
3
  attr_reader :http_status_code
4
4
  attr_reader :paddle_error_code
5
5
  attr_reader :paddle_error_message
6
+ attr_reader :paddle_errors
7
+ attr_reader :documentation_url
8
+ attr_reader :request_id
6
9
 
7
10
  def initialize(response_body, http_status_code)
8
11
  @response_body = response_body
@@ -16,6 +19,9 @@ module Paddle
16
19
  def set_paddle_error_values
17
20
  @paddle_error_code = @response_body.dig("error", "code")
18
21
  @paddle_error_message = @response_body.dig("error", "detail")
22
+ @paddle_errors = @response_body.dig("error", "errors") || []
23
+ @documentation_url = @response_body.dig("error", "documentation_url")
24
+ @request_id = @response_body.dig("meta", "request_id")
19
25
  end
20
26
 
21
27
  def error_message
@@ -25,10 +31,31 @@ module Paddle
25
31
  end
26
32
 
27
33
  def build_message
28
- if paddle_error_code.nil?
29
- return "Error #{@http_status_code}: #{error_message}"
34
+ base_message = if paddle_error_code.nil?
35
+ "Error #{@http_status_code}: #{error_message}"
36
+ else
37
+ "Error #{@http_status_code}: #{error_message} '#{paddle_error_code}'"
30
38
  end
31
- "Error #{@http_status_code}: #{error_message} '#{paddle_error_code}'"
39
+
40
+ # Add detailed field errors if present
41
+ if @paddle_errors && !@paddle_errors.empty?
42
+ field_errors = @paddle_errors.map do |err|
43
+ " - #{err['field']}: #{err['message']}"
44
+ end.join("\n")
45
+ base_message += "\nField errors:\n#{field_errors}"
46
+ end
47
+
48
+ # Add documentation URL if present
49
+ if @documentation_url
50
+ base_message += "\nDocumentation: #{@documentation_url}"
51
+ end
52
+
53
+ # Add request ID if present (useful for support)
54
+ if @request_id
55
+ base_message += "\nRequest ID: #{@request_id}"
56
+ end
57
+
58
+ base_message
32
59
  end
33
60
  end
34
61
 
@@ -37,7 +64,8 @@ module Paddle
37
64
  private
38
65
 
39
66
  def error_message
40
- "Your request was malformed."
67
+ # Use the detailed Paddle error message if available, otherwise fall back to generic message
68
+ @paddle_error_message || "Your request was malformed."
41
69
  end
42
70
  end
43
71
 
@@ -0,0 +1,26 @@
1
+ module Paddle
2
+ class ClientToken < Object
3
+ class << self
4
+ def list(**params)
5
+ response = Client.get_request("client-tokens", params: params)
6
+ Collection.from_response(response, type: ClientToken)
7
+ end
8
+
9
+ def create(name:, **params)
10
+ attrs = { name: name }
11
+ response = Client.post_request("client-tokens", body: attrs.merge(params))
12
+ ClientToken.new(response.body["data"])
13
+ end
14
+
15
+ def retrieve(id:)
16
+ response = Client.get_request("client-tokens/#{id}")
17
+ ClientToken.new(response.body["data"])
18
+ end
19
+
20
+ def update(id:, **params)
21
+ response = Client.patch_request("client-tokens/#{id}", body: params)
22
+ ClientToken.new(response.body["data"])
23
+ end
24
+ end
25
+ end
26
+ end
@@ -26,6 +26,11 @@ module Paddle
26
26
  response = Client.get_request("customers/#{id}/credit-balances")
27
27
  CreditBalance.new(response.body["data"][0])
28
28
  end
29
+
30
+ def auth_token(id:)
31
+ response = Client.post_request("customers/#{id}/auth-token", body: "")
32
+ CustomerAuthToken.new(response.body["data"])
33
+ end
29
34
  end
30
35
  end
31
36
  end
@@ -0,0 +1,4 @@
1
+ module Paddle
2
+ class CustomerAuthToken < Object
3
+ end
4
+ end
@@ -0,0 +1,19 @@
1
+ module Paddle
2
+ class PaymentMethod < Object
3
+ class << self
4
+ def list(customer:, **params)
5
+ response = Client.get_request("customers/#{customer}/payment-methods", params: params)
6
+ Collection.from_response(response, type: PaymentMethod)
7
+ end
8
+
9
+ def retrieve(customer:, id:)
10
+ response = Client.get_request("customers/#{customer}/payment-methods/#{id}")
11
+ PaymentMethod.new(response.body["data"])
12
+ end
13
+
14
+ def delete(customer:, id:)
15
+ Client.delete_request("customers/#{customer}/payment-methods/#{id}")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Paddle
4
- VERSION = "2.7.1"
4
+ VERSION = "2.8"
5
5
  end
data/lib/paddle.rb CHANGED
@@ -48,9 +48,12 @@ module Paddle
48
48
  autoload :SimulationRun, "paddle/models/simulation_run"
49
49
  autoload :SimulationRunEvent, "paddle/models/simulation_run_event"
50
50
  autoload :PortalSession, "paddle/models/portal_session"
51
+ autoload :PaymentMethod, "paddle/models/payment_method"
52
+ autoload :ClientToken, "paddle/models/client_token"
51
53
 
52
54
  autoload :NotificationLog, "paddle/models/notification_log"
53
55
  autoload :CreditBalance, "paddle/models/credit_balance"
56
+ autoload :CustomerAuthToken, "paddle/models/customer_auth_token"
54
57
 
55
58
  # Load Classic APIs
56
59
  module Classic
data/paddle.gemspec CHANGED
@@ -28,4 +28,5 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.add_dependency "faraday", "~> 2.11"
30
30
  spec.add_dependency "ostruct", "~> 0.6.0"
31
+ spec.add_dependency "cgi"
31
32
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paddle
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.1
4
+ version: '2.8'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dean Perry
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-12-20 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: faraday
@@ -38,7 +37,20 @@ dependencies:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
39
  version: 0.6.0
41
- description:
40
+ - !ruby/object:Gem::Dependency
41
+ name: cgi
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
42
54
  email:
43
55
  - dean@deanpcmad.com
44
56
  executables: []
@@ -89,14 +101,17 @@ files:
89
101
  - lib/paddle/models/address.rb
90
102
  - lib/paddle/models/adjustment.rb
91
103
  - lib/paddle/models/business.rb
104
+ - lib/paddle/models/client_token.rb
92
105
  - lib/paddle/models/credit_balance.rb
93
106
  - lib/paddle/models/customer.rb
107
+ - lib/paddle/models/customer_auth_token.rb
94
108
  - lib/paddle/models/discount.rb
95
109
  - lib/paddle/models/event.rb
96
110
  - lib/paddle/models/event_type.rb
97
111
  - lib/paddle/models/notification.rb
98
112
  - lib/paddle/models/notification_log.rb
99
113
  - lib/paddle/models/notification_setting.rb
114
+ - lib/paddle/models/payment_method.rb
100
115
  - lib/paddle/models/portal_session.rb
101
116
  - lib/paddle/models/price.rb
102
117
  - lib/paddle/models/pricing_preview.rb
@@ -116,7 +131,6 @@ licenses: []
116
131
  metadata:
117
132
  homepage_uri: https://github.com/deanpcmad/paddle
118
133
  source_code_uri: https://github.com/deanpcmad/paddle
119
- post_install_message:
120
134
  rdoc_options: []
121
135
  require_paths:
122
136
  - lib
@@ -131,8 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
145
  - !ruby/object:Gem::Version
132
146
  version: '0'
133
147
  requirements: []
134
- rubygems_version: 3.5.22
135
- signing_key:
148
+ rubygems_version: 4.0.1
136
149
  specification_version: 4
137
150
  summary: Ruby library for the Paddle Billing & Classic APIs
138
151
  test_files: []