checkout-intents 0.0.2 → 0.2.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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +80 -1
  4. data/lib/checkout_intents/client.rb +34 -5
  5. data/lib/checkout_intents/errors.rb +33 -0
  6. data/lib/checkout_intents/internal/transport/base_client.rb +33 -0
  7. data/lib/checkout_intents/models/base_checkout_intent.rb +3 -3
  8. data/lib/checkout_intents/models/betas/checkout_session_create_params.rb +3 -3
  9. data/lib/checkout_intents/models/checkout_intent_create_params.rb +3 -3
  10. data/lib/checkout_intents/models/checkout_intent_purchase_params.rb +3 -3
  11. data/lib/checkout_intents/resources/betas/checkout_sessions.rb +1 -1
  12. data/lib/checkout_intents/resources/checkout_intents.rb +239 -2
  13. data/lib/checkout_intents/version.rb +1 -1
  14. data/rbi/checkout_intents/errors.rbi +33 -0
  15. data/rbi/checkout_intents/internal/transport/base_client.rbi +12 -0
  16. data/rbi/checkout_intents/models/base_checkout_intent.rbi +2 -2
  17. data/rbi/checkout_intents/models/betas/checkout_session_create_params.rbi +2 -2
  18. data/rbi/checkout_intents/models/checkout_intent_create_params.rbi +2 -2
  19. data/rbi/checkout_intents/models/checkout_intent_purchase_params.rbi +2 -2
  20. data/rbi/checkout_intents/resources/betas/checkout_sessions.rbi +1 -1
  21. data/rbi/checkout_intents/resources/checkout_intents.rbi +115 -2
  22. data/sig/checkout_intents/models/base_checkout_intent.rbs +4 -4
  23. data/sig/checkout_intents/models/betas/checkout_session_create_params.rbs +4 -4
  24. data/sig/checkout_intents/models/checkout_intent_create_params.rbs +4 -4
  25. data/sig/checkout_intents/models/checkout_intent_purchase_params.rbs +4 -4
  26. data/sig/checkout_intents/resources/betas/checkout_sessions.rbs +1 -1
  27. data/sig/checkout_intents/resources/checkout_intents.rbs +36 -2
  28. metadata +16 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc70fb7635edef3da40cc306e01a4e0754caee4ae66652784a95b1da116c073c
4
- data.tar.gz: 560d24479d9c9d730a35f55ec5224f595983884a3d5accf419975a753d522dd8
3
+ metadata.gz: 6ccc0d2eeeb7a1702d337ab33d2fbb8dea3223c39aefc94a9a5460930f808293
4
+ data.tar.gz: 7f41dc18f595b8bfa410eda98c4f55ca377db74b28a7336469ca4660513d907c
5
5
  SHA512:
6
- metadata.gz: 1c5fcfbf0a8d880d86396ef3f6c1e2040eb039b15e89be624cbd253203c87b0eb4c599e421cf2bf6b98bbae53f4ab92aa29a016327994b4dac2acaac9c6cdc02
7
- data.tar.gz: b5a0f0238c5306f03bda47b7ecfad94e2137c69f53a4109c16f1615498ecab63c5a82a7118f562cceeb13429aade81855a6948b531664127b2c832db9254c296
6
+ metadata.gz: e2311ef4c1c2be6041830d7512449d65b8d37804ff6d6b160f53c5b82afc66eba8cce0b188cd383e6416dae43b4458785ed725c746686405e21a2f2cba2f4b77
7
+ data.tar.gz: 8ef1985d27314dad4a6e30c26e6b3e5e379aed5318114ebe20e2e883661c2ef5d555374853b3346aba8139904da5d6129a9db5f30220fcc0b9aba9aeeea021e0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0 (2026-01-12)
4
+
5
+ Full Changelog: [v0.1.0...v0.2.0](https://github.com/rye-com/checkout-intents-ruby/compare/v0.1.0...v0.2.0)
6
+
7
+ ### Features
8
+
9
+ * **api:** convert polling helpers to flat keyword args ([0b0893e](https://github.com/rye-com/checkout-intents-ruby/commit/0b0893e255447c6ef35a81196c7481242f7eab8b))
10
+
11
+
12
+ ### Chores
13
+
14
+ * **api:** coerce `quantity` to an `Integer` ([e32b3fc](https://github.com/rye-com/checkout-intents-ruby/commit/e32b3fc5848bfd455cba755cceddfd94f5d40da0))
15
+
16
+ ## 0.1.0 (2026-01-12)
17
+
18
+ Full Changelog: [v0.0.2...v0.1.0](https://github.com/rye-com/checkout-intents-ruby/compare/v0.0.2...v0.1.0)
19
+
20
+ ### Features
21
+
22
+ * **api:** add polling helpers ([5209a5f](https://github.com/rye-com/checkout-intents-ruby/commit/5209a5fcb449acf6e4ab52e1711b5c95a5acfa63))
23
+ * **api:** auto infer environment value ([d666fbb](https://github.com/rye-com/checkout-intents-ruby/commit/d666fbb211955c2c02c9fb5c88de0dea6240adf1))
24
+
25
+
26
+ ### Chores
27
+
28
+ * **internal:** add request_with_headers method ([89dc817](https://github.com/rye-com/checkout-intents-ruby/commit/89dc817a36404e5231e65ab7f05ebe1e5766c61f))
29
+ * move `cgi` into dependencies for ruby 4 ([7674f56](https://github.com/rye-com/checkout-intents-ruby/commit/7674f56727d3e5d940c110eb173d91148224c21b))
30
+
31
+
32
+ ### Documentation
33
+
34
+ * **api:** polling helpers ([465f0a0](https://github.com/rye-com/checkout-intents-ruby/commit/465f0a06848b014fd4e3526ff5c2a01b68f3b7ec))
35
+
3
36
  ## 0.0.2 (2026-01-07)
4
37
 
5
38
  Full Changelog: [v0.0.1...v0.0.2](https://github.com/rye-com/checkout-intents-ruby/compare/v0.0.1...v0.0.2)
@@ -13,4 +46,5 @@ Full Changelog: [v0.0.1...v0.0.2](https://github.com/rye-com/checkout-intents-ru
13
46
  ### Chores
14
47
 
15
48
  * configure new SDK language ([ee73dec](https://github.com/rye-com/checkout-intents-ruby/commit/ee73dec601f3c6286045a97a8c900ade97e9099f))
49
+ * sync repo ([c2a3795](https://github.com/rye-com/checkout-intents-ruby/commit/c2a379536364e5dbdfc5aabfaf20383817a1e2b1))
16
50
  * update SDK settings ([a11c510](https://github.com/rye-com/checkout-intents-ruby/commit/a11c51015c6bcdbbc51353813a10b4421f9ebf44))
data/README.md CHANGED
@@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application
17
17
  <!-- x-release-please-start-version -->
18
18
 
19
19
  ```ruby
20
- gem "checkout-intents", "~> 0.0.2"
20
+ gem "checkout-intents", "~> 0.2.0"
21
21
  ```
22
22
 
23
23
  <!-- x-release-please-end -->
@@ -81,6 +81,63 @@ if page.next_page?
81
81
  end
82
82
  ```
83
83
 
84
+ ### Polling Helpers
85
+
86
+ This SDK includes helper methods for the asynchronous checkout flow. The recommended pattern follows Rye's two-phase checkout:
87
+
88
+ ```ruby
89
+ # Phase 1: Create and wait for offer
90
+ intent = checkout_intents.checkout_intents.create_and_poll(
91
+ buyer: {
92
+ address1: "123 Main St",
93
+ city: "New York",
94
+ country: "US",
95
+ email: "john.doe@example.com",
96
+ firstName: "John",
97
+ lastName: "Doe",
98
+ phone: "5555555555",
99
+ postalCode: "10001",
100
+ province: "NY"
101
+ },
102
+ product_url: "https://example.com/product",
103
+ quantity: 1
104
+ )
105
+
106
+ # Handle failure during offer retrieval
107
+ if intent.state == CheckoutIntents::CheckoutIntent::FailedCheckoutIntent::State::FAILED
108
+ puts "Failed: #{intent.failure_reason.message}"
109
+ else
110
+ # Review pricing with user
111
+ puts "Total: #{intent.offer.cost.total}"
112
+
113
+ # Phase 2: Confirm and wait for completion
114
+ completed = checkout_intents.checkout_intents.confirm_and_poll(
115
+ intent.id,
116
+ payment_method: { type: :stripe_token, stripeToken: "tok_visa" }
117
+ )
118
+
119
+ puts "Status: #{completed.state}"
120
+ end
121
+ ```
122
+
123
+ Available polling methods:
124
+
125
+ - `create_and_poll` - Create and poll until offer is ready (awaiting_confirmation or failed)
126
+ - `confirm_and_poll` - Confirm and poll until completion (completed or failed)
127
+ - `poll_until_completed` - Poll until completed or failed
128
+ - `poll_until_awaiting_confirmation` - Poll until offer is ready or failed
129
+
130
+ All polling methods support customizable timeouts:
131
+
132
+ ```ruby
133
+ # Configure polling behavior
134
+ intent = checkout_intents.checkout_intents.poll_until_completed(
135
+ intent_id,
136
+ poll_interval: 5.0, # Poll every 5 seconds (default)
137
+ max_attempts: 120 # Try up to 120 times, ~10 minutes (default)
138
+ )
139
+ ```
140
+
84
141
  ### Handling errors
85
142
 
86
143
  When the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `CheckoutIntents::Errors::APIError` will be thrown:
@@ -128,6 +185,28 @@ Error codes are as follows:
128
185
  | Other HTTP error | `APIStatusError` |
129
186
  | Timeout | `APITimeoutError` |
130
187
  | Network error | `APIConnectionError` |
188
+ | Polling timeout | `PollTimeoutError` |
189
+
190
+ ### Polling Timeout Errors
191
+
192
+ When using polling helper methods, if the operation exceeds the configured `max_attempts`, a `PollTimeoutError` is raised with helpful context:
193
+
194
+ ```ruby
195
+ begin
196
+ intent = checkout_intents.checkout_intents.poll_until_completed(
197
+ "intent_id",
198
+ poll_interval: 5.0,
199
+ max_attempts: 60
200
+ )
201
+ rescue CheckoutIntents::Errors::PollTimeoutError => e
202
+ puts "Polling timed out for intent: #{e.intent_id}"
203
+ puts "Attempted #{e.attempts} times over #{e.attempts * e.poll_interval}s"
204
+
205
+ # You can retrieve the current state manually
206
+ current_intent = checkout_intents.checkout_intents.retrieve(e.intent_id)
207
+ puts "Current state: #{current_intent.state}"
208
+ end
209
+ ```
131
210
 
132
211
  ### Retries
133
212
 
@@ -42,6 +42,19 @@ module CheckoutIntents
42
42
  {"authorization" => "Bearer #{@api_key}"}
43
43
  end
44
44
 
45
+ # Extracts the environment from a Rye API key.
46
+ # API keys follow the format: RYE/{environment}-{key}
47
+ #
48
+ # @api private
49
+ #
50
+ # @param api_key [String] The API key to parse
51
+ #
52
+ # @return [Symbol, nil] The extracted environment (:staging or :production), or nil if format doesn't match
53
+ private_class_method def self.extract_environment_from_api_key(api_key)
54
+ match = api_key.match(%r{\ARYE/(staging|production)-})
55
+ match ? match[1].to_sym : nil
56
+ end
57
+
45
58
  # Creates and returns a new client for interacting with the API.
46
59
  #
47
60
  # @param api_key [String, nil] Rye API key. Format: `RYE/{environment}-abcdef` Defaults to
@@ -73,17 +86,33 @@ module CheckoutIntents
73
86
  initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY,
74
87
  max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY
75
88
  )
76
- base_url ||= CheckoutIntents::Client::ENVIRONMENTS.fetch(environment&.to_sym || :production) do
77
- message = "environment must be one of #{CheckoutIntents::Client::ENVIRONMENTS.keys}, got #{environment}"
78
- raise ArgumentError.new(message)
79
- end
80
-
81
89
  if api_key.nil?
82
90
  raise ArgumentError.new("api_key is required, and can be set via environ: \"CHECKOUT_INTENTS_API_KEY\"")
83
91
  end
84
92
 
85
93
  @api_key = api_key.to_s
86
94
 
95
+ # Auto-infer environment from API key
96
+ inferred_environment = self.class.send(:extract_environment_from_api_key, @api_key)
97
+
98
+ # Validate environment option matches API key (if both provided)
99
+ if environment && inferred_environment && environment.to_sym != inferred_environment
100
+ raise ArgumentError.new(
101
+ "Environment mismatch: API key is for '#{inferred_environment}' environment " \
102
+ "but 'environment' option is set to '#{environment}'. Please use an API key that " \
103
+ "matches your desired environment or omit the 'environment' option to auto-detect " \
104
+ "from the API key (only auto-detectable with the RYE/{environment}-abcdef api key format)."
105
+ )
106
+ end
107
+
108
+ # Resolve environment: explicit > inferred > default (staging)
109
+ resolved_environment = environment&.to_sym || inferred_environment || :staging
110
+
111
+ base_url ||= CheckoutIntents::Client::ENVIRONMENTS.fetch(resolved_environment) do
112
+ message = "environment must be one of #{CheckoutIntents::Client::ENVIRONMENTS.keys}, got #{resolved_environment}"
113
+ raise ArgumentError.new(message)
114
+ end
115
+
87
116
  super(
88
117
  base_url: base_url,
89
118
  timeout: timeout,
@@ -224,5 +224,38 @@ module CheckoutIntents
224
224
  class InternalServerError < CheckoutIntents::Errors::APIStatusError
225
225
  HTTP_STATUS = (500..)
226
226
  end
227
+
228
+ class PollTimeoutError < CheckoutIntents::Errors::Error
229
+ # @return [String]
230
+ attr_reader :intent_id
231
+
232
+ # @return [Integer]
233
+ attr_reader :attempts
234
+
235
+ # @return [Float]
236
+ attr_reader :poll_interval
237
+
238
+ # @return [Integer]
239
+ attr_reader :max_attempts
240
+
241
+ # @api private
242
+ #
243
+ # @param intent_id [String]
244
+ # @param attempts [Integer]
245
+ # @param poll_interval [Float]
246
+ # @param max_attempts [Integer]
247
+ # @param message [String, nil]
248
+ def initialize(intent_id:, attempts:, poll_interval:, max_attempts:, message: nil)
249
+ @intent_id = intent_id
250
+ @attempts = attempts
251
+ @poll_interval = poll_interval
252
+ @max_attempts = max_attempts
253
+
254
+ message ||= "Polling timeout for checkout intent '#{intent_id}': " \
255
+ "condition not met after #{attempts} attempts (#{(max_attempts * poll_interval).round(1)}s). " \
256
+ "Consider increasing max_attempts or poll_interval."
257
+ super(message)
258
+ end
259
+ end
227
260
  end
228
261
  end
@@ -518,6 +518,39 @@ module CheckoutIntents
518
518
  end
519
519
  end
520
520
 
521
+ # @api private
522
+ #
523
+ # Like `request`, but returns both the parsed model and response headers.
524
+ # Used internally for polling helpers that need to inspect headers.
525
+ #
526
+ # @param req [Hash{Symbol=>Object}]
527
+ #
528
+ # @raise [CheckoutIntents::Errors::APIError]
529
+ # @return [Hash{Symbol=>Object}] Hash with :data and :headers keys
530
+ def request_with_headers(req)
531
+ self.class.validate!(req)
532
+ model = req.fetch(:model) { CheckoutIntents::Internal::Type::Unknown }
533
+ opts = req[:options].to_h
534
+ unwrap = req[:unwrap]
535
+ CheckoutIntents::RequestOptions.validate!(opts)
536
+ request = build_request(req.except(:options), opts)
537
+
538
+ send_retry_header = request.fetch(:headers)["x-stainless-retry-count"] == "0"
539
+ _status, response, stream = send_request(
540
+ request,
541
+ redirect_count: 0,
542
+ retry_count: 0,
543
+ send_retry_header: send_retry_header
544
+ )
545
+
546
+ headers = CheckoutIntents::Internal::Util.normalized_headers(response.each_header.to_h)
547
+ decoded = CheckoutIntents::Internal::Util.decode_content(headers, stream: stream)
548
+ unwrapped = CheckoutIntents::Internal::Util.dig(decoded, unwrap)
549
+ data = CheckoutIntents::Internal::Type::Converter.coerce(model, unwrapped)
550
+
551
+ {data: data, headers: headers}
552
+ end
553
+
521
554
  # @api private
522
555
  #
523
556
  # @return [String]
@@ -25,8 +25,8 @@ module CheckoutIntents
25
25
 
26
26
  # @!attribute quantity
27
27
  #
28
- # @return [Float]
29
- required :quantity, Float
28
+ # @return [Integer]
29
+ required :quantity, Integer
30
30
 
31
31
  # @!attribute constraints
32
32
  #
@@ -50,7 +50,7 @@ module CheckoutIntents
50
50
  # @param buyer [CheckoutIntents::Models::Buyer]
51
51
  # @param created_at [Time]
52
52
  # @param product_url [String]
53
- # @param quantity [Float]
53
+ # @param quantity [Integer]
54
54
  # @param constraints [CheckoutIntents::Models::BaseCheckoutIntent::Constraints]
55
55
  # @param promo_codes [Array<String>]
56
56
  # @param variant_selections [Array<CheckoutIntents::Models::VariantSelection>]
@@ -15,8 +15,8 @@ module CheckoutIntents
15
15
 
16
16
  # @!attribute quantity
17
17
  #
18
- # @return [Float]
19
- required :quantity, Float
18
+ # @return [Integer]
19
+ required :quantity, Integer
20
20
 
21
21
  # @!attribute buyer
22
22
  # Optional buyer information, used to pre-fill the checkout form with the buyer's
@@ -48,7 +48,7 @@ module CheckoutIntents
48
48
  #
49
49
  # @param product_url [String]
50
50
  #
51
- # @param quantity [Float]
51
+ # @param quantity [Integer]
52
52
  #
53
53
  # @param buyer [CheckoutIntents::Models::Betas::CheckoutSessionCreateParams::Buyer] Optional buyer information, used to pre-fill the checkout form with the buyer's
54
54
  #
@@ -19,8 +19,8 @@ module CheckoutIntents
19
19
 
20
20
  # @!attribute quantity
21
21
  #
22
- # @return [Float]
23
- required :quantity, Float
22
+ # @return [Integer]
23
+ required :quantity, Integer
24
24
 
25
25
  # @!attribute constraints
26
26
  #
@@ -42,7 +42,7 @@ module CheckoutIntents
42
42
  # @!method initialize(buyer:, product_url:, quantity:, constraints: nil, promo_codes: nil, variant_selections: nil, request_options: {})
43
43
  # @param buyer [CheckoutIntents::Models::Buyer]
44
44
  # @param product_url [String]
45
- # @param quantity [Float]
45
+ # @param quantity [Integer]
46
46
  # @param constraints [CheckoutIntents::Models::CheckoutIntentCreateParams::Constraints]
47
47
  # @param promo_codes [Array<String>]
48
48
  # @param variant_selections [Array<CheckoutIntents::Models::VariantSelection>]
@@ -24,8 +24,8 @@ module CheckoutIntents
24
24
 
25
25
  # @!attribute quantity
26
26
  #
27
- # @return [Float]
28
- required :quantity, Float
27
+ # @return [Integer]
28
+ required :quantity, Integer
29
29
 
30
30
  # @!attribute constraints
31
31
  #
@@ -48,7 +48,7 @@ module CheckoutIntents
48
48
  # @param buyer [CheckoutIntents::Models::Buyer]
49
49
  # @param payment_method [CheckoutIntents::Models::PaymentMethod::StripeTokenPaymentMethod, CheckoutIntents::Models::PaymentMethod::BasisTheoryPaymentMethod, CheckoutIntents::Models::PaymentMethod::NekudaPaymentMethod]
50
50
  # @param product_url [String]
51
- # @param quantity [Float]
51
+ # @param quantity [Integer]
52
52
  # @param constraints [CheckoutIntents::Models::CheckoutIntentPurchaseParams::Constraints]
53
53
  # @param promo_codes [Array<String>]
54
54
  # @param variant_selections [Array<CheckoutIntents::Models::VariantSelection>]
@@ -16,7 +16,7 @@ module CheckoutIntents
16
16
  #
17
17
  # @param product_url [String]
18
18
  #
19
- # @param quantity [Float]
19
+ # @param quantity [Integer]
20
20
  #
21
21
  # @param buyer [::CheckoutIntents::Models::Betas::CheckoutSessionCreateParams::Buyer] Optional buyer information, used to pre-fill the checkout form with the buyer's
22
22
  #
@@ -3,13 +3,18 @@
3
3
  module CheckoutIntents
4
4
  module Resources
5
5
  class CheckoutIntents
6
+ # Default polling interval in seconds
7
+ DEFAULT_POLL_INTERVAL = 5.0
8
+
9
+ # Default maximum polling attempts
10
+ DEFAULT_MAX_ATTEMPTS = 120
6
11
  # Create a checkout intent with the given request body.
7
12
  #
8
13
  # @overload create(buyer:, product_url:, quantity:, constraints: nil, promo_codes: nil, variant_selections: nil, request_options: {})
9
14
  #
10
15
  # @param buyer [::CheckoutIntents::Models::Buyer]
11
16
  # @param product_url [String]
12
- # @param quantity [Float]
17
+ # @param quantity [Integer]
13
18
  # @param constraints [::CheckoutIntents::Models::CheckoutIntentCreateParams::Constraints]
14
19
  # @param promo_codes [Array<String>]
15
20
  # @param variant_selections [Array<::CheckoutIntents::Models::VariantSelection>]
@@ -142,7 +147,7 @@ module CheckoutIntents
142
147
  # @param buyer [::CheckoutIntents::Models::Buyer]
143
148
  # @param payment_method [::CheckoutIntents::Models::PaymentMethod::StripeTokenPaymentMethod, ::CheckoutIntents::Models::PaymentMethod::BasisTheoryPaymentMethod, ::CheckoutIntents::Models::PaymentMethod::NekudaPaymentMethod]
144
149
  # @param product_url [String]
145
- # @param quantity [Float]
150
+ # @param quantity [Integer]
146
151
  # @param constraints [::CheckoutIntents::Models::CheckoutIntentPurchaseParams::Constraints]
147
152
  # @param promo_codes [Array<String>]
148
153
  # @param variant_selections [Array<::CheckoutIntents::Models::VariantSelection>]
@@ -162,12 +167,244 @@ module CheckoutIntents
162
167
  )
163
168
  end
164
169
 
170
+ # Poll a checkout intent until it reaches a completed state (completed or failed).
171
+ #
172
+ # @param id [String] The checkout intent ID to poll
173
+ # @param poll_interval [Float] Seconds between polling attempts (default: 5.0)
174
+ # @param max_attempts [Integer] Maximum polling attempts before timeout (default: 120)
175
+ # @param request_options [::CheckoutIntents::RequestOptions, Hash{Symbol=>Object}, nil]
176
+ #
177
+ # @return [::CheckoutIntents::Models::CheckoutIntent::CompletedCheckoutIntent, ::CheckoutIntents::Models::CheckoutIntent::FailedCheckoutIntent]
178
+ #
179
+ # @raise [::CheckoutIntents::Errors::PollTimeoutError] If max attempts reached without reaching terminal state
180
+ #
181
+ # @example
182
+ # intent = client.checkout_intents.poll_until_completed("ci_123")
183
+ # if intent.state == :completed
184
+ # puts "Order placed successfully!"
185
+ # else
186
+ # puts "Order failed: #{intent.failure_reason.message}"
187
+ # end
188
+ def poll_until_completed(
189
+ id,
190
+ poll_interval: DEFAULT_POLL_INTERVAL,
191
+ max_attempts: DEFAULT_MAX_ATTEMPTS,
192
+ request_options: {}
193
+ )
194
+ poll_until(
195
+ id,
196
+ ->(intent) { [:completed, :failed].include?(intent.state) },
197
+ poll_interval: poll_interval,
198
+ max_attempts: max_attempts,
199
+ request_options: request_options
200
+ )
201
+ end
202
+
203
+ # Poll a checkout intent until it's ready for confirmation (awaiting_confirmation or failed).
204
+ #
205
+ # This is typically used after creating a checkout intent to wait for the offer
206
+ # to be retrieved from the merchant. The intent can reach awaiting_confirmation
207
+ # (success - ready to confirm) or failed (offer retrieval failed).
208
+ #
209
+ # @param id [String] The checkout intent ID to poll
210
+ # @param poll_interval [Float] Seconds between polling attempts (default: 5.0)
211
+ # @param max_attempts [Integer] Maximum polling attempts before timeout (default: 120)
212
+ # @param request_options [::CheckoutIntents::RequestOptions, Hash{Symbol=>Object}, nil]
213
+ #
214
+ # @return [::CheckoutIntents::Models::CheckoutIntent::AwaitingConfirmationCheckoutIntent, ::CheckoutIntents::Models::CheckoutIntent::FailedCheckoutIntent]
215
+ #
216
+ # @raise [::CheckoutIntents::Errors::PollTimeoutError] If max attempts reached without reaching target state
217
+ #
218
+ # @example
219
+ # intent = client.checkout_intents.poll_until_awaiting_confirmation("ci_123")
220
+ # if intent.state == :awaiting_confirmation
221
+ # puts "Total: #{intent.offer.cost.total}"
222
+ # else
223
+ # puts "Failed: #{intent.failure_reason.message}"
224
+ # end
225
+ def poll_until_awaiting_confirmation(
226
+ id,
227
+ poll_interval: DEFAULT_POLL_INTERVAL,
228
+ max_attempts: DEFAULT_MAX_ATTEMPTS,
229
+ request_options: {}
230
+ )
231
+ poll_until(
232
+ id,
233
+ ->(intent) { [:awaiting_confirmation, :failed].include?(intent.state) },
234
+ poll_interval: poll_interval,
235
+ max_attempts: max_attempts,
236
+ request_options: request_options
237
+ )
238
+ end
239
+
240
+ # Create a checkout intent and poll until it's ready for confirmation.
241
+ #
242
+ # This follows the Rye documented flow: create -> poll until awaiting_confirmation.
243
+ # After this method completes, you should review the offer (pricing, shipping, taxes)
244
+ # with the user before calling confirm().
245
+ #
246
+ # @overload create_and_poll(buyer:, product_url:, quantity:, constraints: nil, promo_codes: nil, variant_selections: nil, poll_interval: 5.0, max_attempts: 120, request_options: {})
247
+ #
248
+ # @param buyer [::CheckoutIntents::Models::Buyer]
249
+ # @param product_url [String]
250
+ # @param quantity [Integer]
251
+ # @param constraints [::CheckoutIntents::Models::CheckoutIntentCreateParams::Constraints]
252
+ # @param promo_codes [Array<String>]
253
+ # @param variant_selections [Array<::CheckoutIntents::Models::VariantSelection>]
254
+ # @param poll_interval [Float] Seconds between polling attempts (default: 5.0)
255
+ # @param max_attempts [Integer] Maximum polling attempts before timeout (default: 120)
256
+ # @param request_options [::CheckoutIntents::RequestOptions, Hash{Symbol=>Object}, nil]
257
+ #
258
+ # @return [::CheckoutIntents::Models::CheckoutIntent::AwaitingConfirmationCheckoutIntent, ::CheckoutIntents::Models::CheckoutIntent::FailedCheckoutIntent]
259
+ #
260
+ # @raise [::CheckoutIntents::Errors::PollTimeoutError] If max attempts reached without reaching target state
261
+ #
262
+ # @example
263
+ # intent = client.checkout_intents.create_and_poll(
264
+ # buyer: { address1: "123 Main St", city: "New York", ... },
265
+ # product_url: "https://example.com/product",
266
+ # quantity: 1
267
+ # )
268
+ # puts "Total: #{intent.offer.cost.total}"
269
+ def create_and_poll(
270
+ buyer:,
271
+ product_url:,
272
+ quantity:,
273
+ constraints: nil,
274
+ promo_codes: nil,
275
+ variant_selections: nil,
276
+ poll_interval: DEFAULT_POLL_INTERVAL,
277
+ max_attempts: DEFAULT_MAX_ATTEMPTS,
278
+ request_options: {}
279
+ )
280
+ intent = create(
281
+ buyer: buyer,
282
+ product_url: product_url,
283
+ quantity: quantity,
284
+ constraints: constraints,
285
+ promo_codes: promo_codes,
286
+ variant_selections: variant_selections,
287
+ request_options: request_options
288
+ )
289
+ poll_until_awaiting_confirmation(
290
+ intent.id,
291
+ poll_interval: poll_interval,
292
+ max_attempts: max_attempts,
293
+ request_options: request_options
294
+ )
295
+ end
296
+
297
+ # Confirm a checkout intent and poll until it reaches a completed state (completed or failed).
298
+ #
299
+ # @overload confirm_and_poll(id, payment_method:, poll_interval: 5.0, max_attempts: 120, request_options: {})
300
+ #
301
+ # @param id [String] The id of the checkout intent to confirm
302
+ # @param payment_method [::CheckoutIntents::Models::PaymentMethod::StripeTokenPaymentMethod, ::CheckoutIntents::Models::PaymentMethod::BasisTheoryPaymentMethod, ::CheckoutIntents::Models::PaymentMethod::NekudaPaymentMethod]
303
+ # @param poll_interval [Float] Seconds between polling attempts (default: 5.0)
304
+ # @param max_attempts [Integer] Maximum polling attempts before timeout (default: 120)
305
+ # @param request_options [::CheckoutIntents::RequestOptions, Hash{Symbol=>Object}, nil]
306
+ #
307
+ # @return [::CheckoutIntents::Models::CheckoutIntent::CompletedCheckoutIntent, ::CheckoutIntents::Models::CheckoutIntent::FailedCheckoutIntent]
308
+ #
309
+ # @raise [::CheckoutIntents::Errors::PollTimeoutError] If max attempts reached without reaching terminal state
310
+ #
311
+ # @example
312
+ # intent = client.checkout_intents.confirm_and_poll(
313
+ # "ci_123",
314
+ # payment_method: { type: "stripe_token", stripe_token: "tok_visa" }
315
+ # )
316
+ # if intent.state == :completed
317
+ # puts "Order placed successfully!"
318
+ # else
319
+ # puts "Order failed: #{intent.failure_reason.message}"
320
+ # end
321
+ def confirm_and_poll(
322
+ id,
323
+ payment_method:,
324
+ poll_interval: DEFAULT_POLL_INTERVAL,
325
+ max_attempts: DEFAULT_MAX_ATTEMPTS,
326
+ request_options: {}
327
+ )
328
+ intent = confirm(id, payment_method: payment_method, request_options: request_options)
329
+ poll_until_completed(
330
+ intent.id,
331
+ poll_interval: poll_interval,
332
+ max_attempts: max_attempts,
333
+ request_options: request_options
334
+ )
335
+ end
336
+
165
337
  # @api private
166
338
  #
167
339
  # @param client [::CheckoutIntents::Client]
168
340
  def initialize(client:)
169
341
  @client = client
170
342
  end
343
+
344
+ private
345
+
346
+ # Core polling implementation.
347
+ #
348
+ # @param id [String] The checkout intent ID
349
+ # @param condition [Proc] Returns true when polling should stop
350
+ # @param poll_interval [Float] Seconds between polls
351
+ # @param max_attempts [Integer] Maximum attempts
352
+ # @param request_options [Hash] Additional request options
353
+ #
354
+ # @return [::CheckoutIntents::Models::CheckoutIntent]
355
+ def poll_until(id, condition, poll_interval:, max_attempts:, request_options:)
356
+ if max_attempts < 1
357
+ warn(
358
+ "[Checkout Intents SDK] Invalid max_attempts value: #{max_attempts}. " \
359
+ "max_attempts must be >= 1. Defaulting to 1."
360
+ )
361
+ max_attempts = 1
362
+ end
363
+
364
+ attempts = 0
365
+ poll_headers = {
366
+ "x-stainless-poll-helper" => "true",
367
+ "x-stainless-custom-poll-interval" => (poll_interval * 1000).to_i.to_s
368
+ }
369
+
370
+ merged_options = (request_options || {}).merge(
371
+ extra_headers: ((request_options || {})[:extra_headers] || {}).merge(poll_headers)
372
+ )
373
+
374
+ while attempts < max_attempts
375
+ result = @client.request_with_headers(
376
+ method: :get,
377
+ path: ["api/v1/checkout-intents/%1$s", id],
378
+ model: ::CheckoutIntents::CheckoutIntent,
379
+ options: merged_options
380
+ )
381
+
382
+ intent = result[:data]
383
+ headers = result[:headers]
384
+
385
+ return intent if condition.call(intent)
386
+
387
+ attempts += 1
388
+
389
+ if attempts >= max_attempts
390
+ raise ::CheckoutIntents::Errors::PollTimeoutError.new(
391
+ intent_id: id,
392
+ attempts: attempts,
393
+ poll_interval: poll_interval,
394
+ max_attempts: max_attempts
395
+ )
396
+ end
397
+
398
+ # Check for server-suggested polling interval
399
+ sleep_interval = poll_interval
400
+ if (header_interval = headers["retry-after-ms"])
401
+ header_interval_ms = Integer(header_interval, exception: false)
402
+ sleep_interval = header_interval_ms / 1000.0 if header_interval_ms
403
+ end
404
+
405
+ sleep(sleep_interval)
406
+ end
407
+ end
171
408
  end
172
409
  end
173
410
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CheckoutIntents
4
- VERSION = "0.0.2"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -201,5 +201,38 @@ module CheckoutIntents
201
201
  class InternalServerError < CheckoutIntents::Errors::APIStatusError
202
202
  HTTP_STATUS = T.let((500..), T::Range[Integer])
203
203
  end
204
+
205
+ class PollTimeoutError < CheckoutIntents::Errors::Error
206
+ sig { returns(String) }
207
+ attr_reader :intent_id
208
+
209
+ sig { returns(Integer) }
210
+ attr_reader :attempts
211
+
212
+ sig { returns(Float) }
213
+ attr_reader :poll_interval
214
+
215
+ sig { returns(Integer) }
216
+ attr_reader :max_attempts
217
+
218
+ # @api private
219
+ sig do
220
+ params(
221
+ intent_id: String,
222
+ attempts: Integer,
223
+ poll_interval: Float,
224
+ max_attempts: Integer,
225
+ message: T.nilable(String)
226
+ ).returns(T.attached_class)
227
+ end
228
+ def self.new(
229
+ intent_id:,
230
+ attempts:,
231
+ poll_interval:,
232
+ max_attempts:,
233
+ message: nil
234
+ )
235
+ end
236
+ end
204
237
  end
205
238
  end
@@ -299,6 +299,18 @@ module CheckoutIntents
299
299
  )
300
300
  end
301
301
 
302
+ # @api private
303
+ #
304
+ # Like `request`, but returns both the parsed model and response headers.
305
+ # Used internally for polling helpers that need to inspect headers.
306
+ sig do
307
+ params(
308
+ req: CheckoutIntents::Internal::Transport::BaseClient::RequestComponents
309
+ ).returns({ data: T.anything, headers: T::Hash[String, String] })
310
+ end
311
+ def request_with_headers(req)
312
+ end
313
+
302
314
  # @api private
303
315
  sig { returns(String) }
304
316
  def inspect
@@ -64,7 +64,7 @@ module CheckoutIntents
64
64
  buyer: CheckoutIntents::Buyer::OrHash,
65
65
  created_at: Time,
66
66
  product_url: String,
67
- quantity: Float,
67
+ quantity: Integer,
68
68
  constraints: CheckoutIntents::BaseCheckoutIntent::Constraints::OrHash,
69
69
  promo_codes: T::Array[String],
70
70
  variant_selections:
@@ -90,7 +90,7 @@ module CheckoutIntents
90
90
  buyer: CheckoutIntents::Buyer,
91
91
  created_at: Time,
92
92
  product_url: String,
93
- quantity: Float,
93
+ quantity: Integer,
94
94
  constraints: CheckoutIntents::BaseCheckoutIntent::Constraints,
95
95
  promo_codes: T::Array[String],
96
96
  variant_selections: T::Array[CheckoutIntents::VariantSelection]
@@ -77,7 +77,7 @@ module CheckoutIntents
77
77
  sig do
78
78
  params(
79
79
  product_url: String,
80
- quantity: Float,
80
+ quantity: Integer,
81
81
  buyer:
82
82
  CheckoutIntents::Betas::CheckoutSessionCreateParams::Buyer::OrHash,
83
83
  constraints:
@@ -105,7 +105,7 @@ module CheckoutIntents
105
105
  override.returns(
106
106
  {
107
107
  product_url: String,
108
- quantity: Float,
108
+ quantity: Integer,
109
109
  buyer: CheckoutIntents::Betas::CheckoutSessionCreateParams::Buyer,
110
110
  constraints:
111
111
  CheckoutIntents::Betas::CheckoutSessionCreateParams::Constraints,
@@ -62,7 +62,7 @@ module CheckoutIntents
62
62
  params(
63
63
  buyer: CheckoutIntents::Buyer::OrHash,
64
64
  product_url: String,
65
- quantity: Float,
65
+ quantity: Integer,
66
66
  constraints:
67
67
  CheckoutIntents::CheckoutIntentCreateParams::Constraints::OrHash,
68
68
  promo_codes: T::Array[String],
@@ -87,7 +87,7 @@ module CheckoutIntents
87
87
  {
88
88
  buyer: CheckoutIntents::Buyer,
89
89
  product_url: String,
90
- quantity: Float,
90
+ quantity: Integer,
91
91
  constraints:
92
92
  CheckoutIntents::CheckoutIntentCreateParams::Constraints,
93
93
  promo_codes: T::Array[String],
@@ -79,7 +79,7 @@ module CheckoutIntents
79
79
  CheckoutIntents::PaymentMethod::NekudaPaymentMethod::OrHash
80
80
  ),
81
81
  product_url: String,
82
- quantity: Float,
82
+ quantity: Integer,
83
83
  constraints:
84
84
  CheckoutIntents::CheckoutIntentPurchaseParams::Constraints::OrHash,
85
85
  promo_codes: T::Array[String],
@@ -111,7 +111,7 @@ module CheckoutIntents
111
111
  CheckoutIntents::PaymentMethod::NekudaPaymentMethod
112
112
  ),
113
113
  product_url: String,
114
- quantity: Float,
114
+ quantity: Integer,
115
115
  constraints:
116
116
  CheckoutIntents::CheckoutIntentPurchaseParams::Constraints,
117
117
  promo_codes: T::Array[String],
@@ -11,7 +11,7 @@ module CheckoutIntents
11
11
  sig do
12
12
  params(
13
13
  product_url: String,
14
- quantity: Float,
14
+ quantity: Integer,
15
15
  buyer:
16
16
  ::CheckoutIntents::Betas::CheckoutSessionCreateParams::Buyer::OrHash,
17
17
  constraints:
@@ -8,7 +8,7 @@ module CheckoutIntents
8
8
  params(
9
9
  buyer: ::CheckoutIntents::Buyer::OrHash,
10
10
  product_url: String,
11
- quantity: Float,
11
+ quantity: Integer,
12
12
  constraints:
13
13
  ::CheckoutIntents::CheckoutIntentCreateParams::Constraints::OrHash,
14
14
  promo_codes: T::Array[String],
@@ -135,7 +135,7 @@ module CheckoutIntents
135
135
  ::CheckoutIntents::PaymentMethod::NekudaPaymentMethod::OrHash
136
136
  ),
137
137
  product_url: String,
138
- quantity: Float,
138
+ quantity: Integer,
139
139
  constraints:
140
140
  ::CheckoutIntents::CheckoutIntentPurchaseParams::Constraints::OrHash,
141
141
  promo_codes: T::Array[String],
@@ -156,6 +156,119 @@ module CheckoutIntents
156
156
  )
157
157
  end
158
158
 
159
+ # Default polling interval in seconds
160
+ DEFAULT_POLL_INTERVAL = T.let(5.0, Float)
161
+
162
+ # Default maximum polling attempts
163
+ DEFAULT_MAX_ATTEMPTS = T.let(120, Integer)
164
+
165
+ # Poll a checkout intent until it reaches a completed state (completed or failed).
166
+ sig do
167
+ params(
168
+ id: String,
169
+ poll_interval: Float,
170
+ max_attempts: Integer,
171
+ request_options: ::CheckoutIntents::RequestOptions::OrHash
172
+ ).returns(
173
+ T.any(
174
+ ::CheckoutIntents::CheckoutIntent::CompletedCheckoutIntent,
175
+ ::CheckoutIntents::CheckoutIntent::FailedCheckoutIntent
176
+ )
177
+ )
178
+ end
179
+ def poll_until_completed(
180
+ id,
181
+ poll_interval: DEFAULT_POLL_INTERVAL,
182
+ max_attempts: DEFAULT_MAX_ATTEMPTS,
183
+ request_options: {}
184
+ )
185
+ end
186
+
187
+ # Poll a checkout intent until it's ready for confirmation (awaiting_confirmation or failed).
188
+ sig do
189
+ params(
190
+ id: String,
191
+ poll_interval: Float,
192
+ max_attempts: Integer,
193
+ request_options: ::CheckoutIntents::RequestOptions::OrHash
194
+ ).returns(
195
+ T.any(
196
+ ::CheckoutIntents::CheckoutIntent::AwaitingConfirmationCheckoutIntent,
197
+ ::CheckoutIntents::CheckoutIntent::FailedCheckoutIntent
198
+ )
199
+ )
200
+ end
201
+ def poll_until_awaiting_confirmation(
202
+ id,
203
+ poll_interval: DEFAULT_POLL_INTERVAL,
204
+ max_attempts: DEFAULT_MAX_ATTEMPTS,
205
+ request_options: {}
206
+ )
207
+ end
208
+
209
+ # Create a checkout intent and poll until it's ready for confirmation.
210
+ sig do
211
+ params(
212
+ buyer: ::CheckoutIntents::Buyer::OrHash,
213
+ product_url: String,
214
+ quantity: Integer,
215
+ constraints:
216
+ ::CheckoutIntents::CheckoutIntentCreateParams::Constraints::OrHash,
217
+ promo_codes: T::Array[String],
218
+ variant_selections:
219
+ T::Array[::CheckoutIntents::VariantSelection::OrHash],
220
+ poll_interval: Float,
221
+ max_attempts: Integer,
222
+ request_options: ::CheckoutIntents::RequestOptions::OrHash
223
+ ).returns(
224
+ T.any(
225
+ ::CheckoutIntents::CheckoutIntent::AwaitingConfirmationCheckoutIntent,
226
+ ::CheckoutIntents::CheckoutIntent::FailedCheckoutIntent
227
+ )
228
+ )
229
+ end
230
+ def create_and_poll(
231
+ buyer:,
232
+ product_url:,
233
+ quantity:,
234
+ constraints: nil,
235
+ promo_codes: nil,
236
+ variant_selections: nil,
237
+ poll_interval: DEFAULT_POLL_INTERVAL,
238
+ max_attempts: DEFAULT_MAX_ATTEMPTS,
239
+ request_options: {}
240
+ )
241
+ end
242
+
243
+ # Confirm a checkout intent and poll until it reaches a completed state.
244
+ sig do
245
+ params(
246
+ id: String,
247
+ payment_method:
248
+ T.any(
249
+ ::CheckoutIntents::PaymentMethod::StripeTokenPaymentMethod::OrHash,
250
+ ::CheckoutIntents::PaymentMethod::BasisTheoryPaymentMethod::OrHash,
251
+ ::CheckoutIntents::PaymentMethod::NekudaPaymentMethod::OrHash
252
+ ),
253
+ poll_interval: Float,
254
+ max_attempts: Integer,
255
+ request_options: ::CheckoutIntents::RequestOptions::OrHash
256
+ ).returns(
257
+ T.any(
258
+ ::CheckoutIntents::CheckoutIntent::CompletedCheckoutIntent,
259
+ ::CheckoutIntents::CheckoutIntent::FailedCheckoutIntent
260
+ )
261
+ )
262
+ end
263
+ def confirm_and_poll(
264
+ id,
265
+ payment_method:,
266
+ poll_interval: DEFAULT_POLL_INTERVAL,
267
+ max_attempts: DEFAULT_MAX_ATTEMPTS,
268
+ request_options: {}
269
+ )
270
+ end
271
+
159
272
  # @api private
160
273
  sig { params(client: ::CheckoutIntents::Client).returns(T.attached_class) }
161
274
  def self.new(client:)
@@ -6,7 +6,7 @@ module CheckoutIntents
6
6
  buyer: CheckoutIntents::Buyer,
7
7
  created_at: Time,
8
8
  product_url: String,
9
- quantity: Float,
9
+ quantity: Integer,
10
10
  constraints: CheckoutIntents::BaseCheckoutIntent::Constraints,
11
11
  promo_codes: ::Array[String],
12
12
  variant_selections: ::Array[CheckoutIntents::VariantSelection]
@@ -21,7 +21,7 @@ module CheckoutIntents
21
21
 
22
22
  attr_accessor product_url: String
23
23
 
24
- attr_accessor quantity: Float
24
+ attr_accessor quantity: Integer
25
25
 
26
26
  attr_reader constraints: CheckoutIntents::BaseCheckoutIntent::Constraints?
27
27
 
@@ -44,7 +44,7 @@ module CheckoutIntents
44
44
  buyer: CheckoutIntents::Buyer,
45
45
  created_at: Time,
46
46
  product_url: String,
47
- quantity: Float,
47
+ quantity: Integer,
48
48
  ?constraints: CheckoutIntents::BaseCheckoutIntent::Constraints,
49
49
  ?promo_codes: ::Array[String],
50
50
  ?variant_selections: ::Array[CheckoutIntents::VariantSelection]
@@ -55,7 +55,7 @@ module CheckoutIntents
55
55
  buyer: CheckoutIntents::Buyer,
56
56
  created_at: Time,
57
57
  product_url: String,
58
- quantity: Float,
58
+ quantity: Integer,
59
59
  constraints: CheckoutIntents::BaseCheckoutIntent::Constraints,
60
60
  promo_codes: ::Array[String],
61
61
  variant_selections: ::Array[CheckoutIntents::VariantSelection]
@@ -4,7 +4,7 @@ module CheckoutIntents
4
4
  type checkout_session_create_params =
5
5
  {
6
6
  product_url: String,
7
- quantity: Float,
7
+ quantity: Integer,
8
8
  buyer: CheckoutIntents::Betas::CheckoutSessionCreateParams::Buyer,
9
9
  constraints: CheckoutIntents::Betas::CheckoutSessionCreateParams::Constraints,
10
10
  promo_codes: ::Array[String],
@@ -18,7 +18,7 @@ module CheckoutIntents
18
18
 
19
19
  attr_accessor product_url: String
20
20
 
21
- attr_accessor quantity: Float
21
+ attr_accessor quantity: Integer
22
22
 
23
23
  attr_reader buyer: CheckoutIntents::Betas::CheckoutSessionCreateParams::Buyer?
24
24
 
@@ -44,7 +44,7 @@ module CheckoutIntents
44
44
 
45
45
  def initialize: (
46
46
  product_url: String,
47
- quantity: Float,
47
+ quantity: Integer,
48
48
  ?buyer: CheckoutIntents::Betas::CheckoutSessionCreateParams::Buyer,
49
49
  ?constraints: CheckoutIntents::Betas::CheckoutSessionCreateParams::Constraints,
50
50
  ?promo_codes: ::Array[String],
@@ -54,7 +54,7 @@ module CheckoutIntents
54
54
 
55
55
  def to_hash: -> {
56
56
  product_url: String,
57
- quantity: Float,
57
+ quantity: Integer,
58
58
  buyer: CheckoutIntents::Betas::CheckoutSessionCreateParams::Buyer,
59
59
  constraints: CheckoutIntents::Betas::CheckoutSessionCreateParams::Constraints,
60
60
  promo_codes: ::Array[String],
@@ -4,7 +4,7 @@ module CheckoutIntents
4
4
  {
5
5
  buyer: CheckoutIntents::Buyer,
6
6
  product_url: String,
7
- quantity: Float,
7
+ quantity: Integer,
8
8
  constraints: CheckoutIntents::CheckoutIntentCreateParams::Constraints,
9
9
  promo_codes: ::Array[String],
10
10
  variant_selections: ::Array[CheckoutIntents::VariantSelection]
@@ -19,7 +19,7 @@ module CheckoutIntents
19
19
 
20
20
  attr_accessor product_url: String
21
21
 
22
- attr_accessor quantity: Float
22
+ attr_accessor quantity: Integer
23
23
 
24
24
  attr_reader constraints: CheckoutIntents::CheckoutIntentCreateParams::Constraints?
25
25
 
@@ -40,7 +40,7 @@ module CheckoutIntents
40
40
  def initialize: (
41
41
  buyer: CheckoutIntents::Buyer,
42
42
  product_url: String,
43
- quantity: Float,
43
+ quantity: Integer,
44
44
  ?constraints: CheckoutIntents::CheckoutIntentCreateParams::Constraints,
45
45
  ?promo_codes: ::Array[String],
46
46
  ?variant_selections: ::Array[CheckoutIntents::VariantSelection],
@@ -50,7 +50,7 @@ module CheckoutIntents
50
50
  def to_hash: -> {
51
51
  buyer: CheckoutIntents::Buyer,
52
52
  product_url: String,
53
- quantity: Float,
53
+ quantity: Integer,
54
54
  constraints: CheckoutIntents::CheckoutIntentCreateParams::Constraints,
55
55
  promo_codes: ::Array[String],
56
56
  variant_selections: ::Array[CheckoutIntents::VariantSelection],
@@ -5,7 +5,7 @@ module CheckoutIntents
5
5
  buyer: CheckoutIntents::Buyer,
6
6
  payment_method: CheckoutIntents::Models::payment_method,
7
7
  product_url: String,
8
- quantity: Float,
8
+ quantity: Integer,
9
9
  constraints: CheckoutIntents::CheckoutIntentPurchaseParams::Constraints,
10
10
  promo_codes: ::Array[String],
11
11
  variant_selections: ::Array[CheckoutIntents::VariantSelection]
@@ -22,7 +22,7 @@ module CheckoutIntents
22
22
 
23
23
  attr_accessor product_url: String
24
24
 
25
- attr_accessor quantity: Float
25
+ attr_accessor quantity: Integer
26
26
 
27
27
  attr_reader constraints: CheckoutIntents::CheckoutIntentPurchaseParams::Constraints?
28
28
 
@@ -44,7 +44,7 @@ module CheckoutIntents
44
44
  buyer: CheckoutIntents::Buyer,
45
45
  payment_method: CheckoutIntents::Models::payment_method,
46
46
  product_url: String,
47
- quantity: Float,
47
+ quantity: Integer,
48
48
  ?constraints: CheckoutIntents::CheckoutIntentPurchaseParams::Constraints,
49
49
  ?promo_codes: ::Array[String],
50
50
  ?variant_selections: ::Array[CheckoutIntents::VariantSelection],
@@ -55,7 +55,7 @@ module CheckoutIntents
55
55
  buyer: CheckoutIntents::Buyer,
56
56
  payment_method: CheckoutIntents::Models::payment_method,
57
57
  product_url: String,
58
- quantity: Float,
58
+ quantity: Integer,
59
59
  constraints: CheckoutIntents::CheckoutIntentPurchaseParams::Constraints,
60
60
  promo_codes: ::Array[String],
61
61
  variant_selections: ::Array[CheckoutIntents::VariantSelection],
@@ -4,7 +4,7 @@ module CheckoutIntents
4
4
  class CheckoutSessions
5
5
  def create: (
6
6
  product_url: String,
7
- quantity: Float,
7
+ quantity: Integer,
8
8
  ?buyer: CheckoutIntents::Betas::CheckoutSessionCreateParams::Buyer,
9
9
  ?constraints: CheckoutIntents::Betas::CheckoutSessionCreateParams::Constraints,
10
10
  ?promo_codes: ::Array[String],
@@ -4,7 +4,7 @@ module CheckoutIntents
4
4
  def create: (
5
5
  buyer: CheckoutIntents::Buyer,
6
6
  product_url: String,
7
- quantity: Float,
7
+ quantity: Integer,
8
8
  ?constraints: CheckoutIntents::CheckoutIntentCreateParams::Constraints,
9
9
  ?promo_codes: ::Array[String],
10
10
  ?variant_selections: ::Array[CheckoutIntents::VariantSelection],
@@ -41,13 +41,47 @@ module CheckoutIntents
41
41
  buyer: CheckoutIntents::Buyer,
42
42
  payment_method: CheckoutIntents::Models::payment_method,
43
43
  product_url: String,
44
- quantity: Float,
44
+ quantity: Integer,
45
45
  ?constraints: CheckoutIntents::CheckoutIntentPurchaseParams::Constraints,
46
46
  ?promo_codes: ::Array[String],
47
47
  ?variant_selections: ::Array[CheckoutIntents::VariantSelection],
48
48
  ?request_options: CheckoutIntents::request_opts
49
49
  ) -> CheckoutIntents::Models::checkout_intent
50
50
 
51
+ def poll_until_completed: (
52
+ String id,
53
+ ?poll_interval: Float,
54
+ ?max_attempts: Integer,
55
+ ?request_options: CheckoutIntents::request_opts
56
+ ) -> (CheckoutIntents::CheckoutIntent::CompletedCheckoutIntent | CheckoutIntents::CheckoutIntent::FailedCheckoutIntent)
57
+
58
+ def poll_until_awaiting_confirmation: (
59
+ String id,
60
+ ?poll_interval: Float,
61
+ ?max_attempts: Integer,
62
+ ?request_options: CheckoutIntents::request_opts
63
+ ) -> (CheckoutIntents::CheckoutIntent::AwaitingConfirmationCheckoutIntent | CheckoutIntents::CheckoutIntent::FailedCheckoutIntent)
64
+
65
+ def create_and_poll: (
66
+ buyer: CheckoutIntents::Buyer,
67
+ product_url: String,
68
+ quantity: Integer,
69
+ ?constraints: CheckoutIntents::CheckoutIntentCreateParams::Constraints,
70
+ ?promo_codes: ::Array[String],
71
+ ?variant_selections: ::Array[CheckoutIntents::VariantSelection],
72
+ ?poll_interval: Float,
73
+ ?max_attempts: Integer,
74
+ ?request_options: CheckoutIntents::request_opts
75
+ ) -> (CheckoutIntents::CheckoutIntent::AwaitingConfirmationCheckoutIntent | CheckoutIntents::CheckoutIntent::FailedCheckoutIntent)
76
+
77
+ def confirm_and_poll: (
78
+ String id,
79
+ payment_method: CheckoutIntents::Models::payment_method,
80
+ ?poll_interval: Float,
81
+ ?max_attempts: Integer,
82
+ ?request_options: CheckoutIntents::request_opts
83
+ ) -> (CheckoutIntents::CheckoutIntent::CompletedCheckoutIntent | CheckoutIntents::CheckoutIntent::FailedCheckoutIntent)
84
+
51
85
  def initialize: (client: CheckoutIntents::Client) -> void
52
86
  end
53
87
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: checkout-intents
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Checkout Intents
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-01-07 00:00:00.000000000 Z
11
+ date: 2026-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cgi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: connection_pool
15
29
  requirement: !ruby/object:Gem::Requirement