checkout-intents 0.1.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

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.
@@ -2,16 +2,19 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, Iterable, cast
5
+ import logging
6
+ from typing import Any, List, Union, TypeVar, Callable, Iterable, cast
7
+ from typing_extensions import Literal, TypeGuard
6
8
 
7
9
  import httpx
8
10
 
9
11
  from ..types import (
12
+ checkout_intent_list_params,
10
13
  checkout_intent_create_params,
11
14
  checkout_intent_confirm_params,
12
15
  checkout_intent_add_payment_params,
13
16
  )
14
- from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
17
+ from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
15
18
  from .._utils import maybe_transform, async_maybe_transform
16
19
  from .._compat import cached_property
17
20
  from .._resource import SyncAPIResource, AsyncAPIResource
@@ -21,14 +24,25 @@ from .._response import (
21
24
  async_to_raw_response_wrapper,
22
25
  async_to_streamed_response_wrapper,
23
26
  )
24
- from .._base_client import make_request_options
27
+ from ..pagination import SyncCursorPagination, AsyncCursorPagination
28
+ from .._exceptions import PollTimeoutError
29
+ from .._base_client import AsyncPaginator, make_request_options
25
30
  from ..types.buyer_param import BuyerParam
26
- from ..types.checkout_intent import CheckoutIntent
31
+ from ..types.checkout_intent import (
32
+ CheckoutIntent,
33
+ FailedCheckoutIntent,
34
+ CompletedCheckoutIntent,
35
+ AwaitingConfirmationCheckoutIntent,
36
+ )
27
37
  from ..types.payment_method_param import PaymentMethodParam
28
38
  from ..types.variant_selection_param import VariantSelectionParam
29
39
 
30
40
  __all__ = ["CheckoutIntentsResource", "AsyncCheckoutIntentsResource"]
31
41
 
42
+ T = TypeVar("T", bound=CheckoutIntent)
43
+
44
+ logger: logging.Logger = logging.getLogger(__name__)
45
+
32
46
 
33
47
  class CheckoutIntentsResource(SyncAPIResource):
34
48
  @cached_property
@@ -134,6 +148,59 @@ class CheckoutIntentsResource(SyncAPIResource):
134
148
  ),
135
149
  )
136
150
 
151
+ def list(
152
+ self,
153
+ *,
154
+ id: SequenceNotStr[str] | Omit = omit,
155
+ after: str | Omit = omit,
156
+ before: str | Omit = omit,
157
+ limit: float | Omit = omit,
158
+ state: List[Literal["retrieving_offer", "awaiting_confirmation", "placing_order", "completed", "failed"]]
159
+ | Omit = omit,
160
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
161
+ # The extra values given here take precedence over values defined on the client or passed to this method.
162
+ extra_headers: Headers | None = None,
163
+ extra_query: Query | None = None,
164
+ extra_body: Body | None = None,
165
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
166
+ ) -> SyncCursorPagination[CheckoutIntent]:
167
+ """
168
+ Retrieve a paginated list of checkout intents
169
+
170
+ Enables developers to query checkout intents associated with their account, with
171
+ filters and cursor-based pagination.
172
+
173
+ Args:
174
+ extra_headers: Send extra headers
175
+
176
+ extra_query: Add additional query parameters to the request
177
+
178
+ extra_body: Add additional JSON properties to the request
179
+
180
+ timeout: Override the client-level default timeout for this request, in seconds
181
+ """
182
+ return self._get_api_list(
183
+ "/api/v1/checkout-intents",
184
+ page=SyncCursorPagination[CheckoutIntent],
185
+ options=make_request_options(
186
+ extra_headers=extra_headers,
187
+ extra_query=extra_query,
188
+ extra_body=extra_body,
189
+ timeout=timeout,
190
+ query=maybe_transform(
191
+ {
192
+ "id": id,
193
+ "after": after,
194
+ "before": before,
195
+ "limit": limit,
196
+ "state": state,
197
+ },
198
+ checkout_intent_list_params.CheckoutIntentListParams,
199
+ ),
200
+ ),
201
+ model=cast(Any, CheckoutIntent), # Union types cannot be passed in as arguments in the type system
202
+ )
203
+
137
204
  def add_payment(
138
205
  self,
139
206
  id: str,
@@ -218,6 +285,365 @@ class CheckoutIntentsResource(SyncAPIResource):
218
285
  ),
219
286
  )
220
287
 
288
+ def _poll_until(
289
+ self,
290
+ id: str,
291
+ condition: Callable[[CheckoutIntent], TypeGuard[T]],
292
+ *,
293
+ poll_interval: float = 5.0,
294
+ max_attempts: int = 120,
295
+ extra_headers: Headers | None = None,
296
+ extra_query: Query | None = None,
297
+ extra_body: Body | None = None,
298
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
299
+ ) -> T:
300
+ """
301
+ A helper to poll a checkout intent until a specific condition is met.
302
+
303
+ Args:
304
+ id: The checkout intent ID to poll
305
+ condition: A callable that returns True when the desired state is reached
306
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
307
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
308
+ extra_headers: Send extra headers
309
+ extra_query: Add additional query parameters to the request
310
+ extra_body: Add additional JSON properties to the request
311
+ timeout: Override the client-level default timeout for this request, in seconds
312
+
313
+ Returns:
314
+ The checkout intent once the condition is met
315
+
316
+ Raises:
317
+ CheckoutIntentsError: If the maximum number of attempts is reached without the condition being met
318
+ """
319
+ if max_attempts < 1:
320
+ logger.warning(
321
+ "[Checkout Intents SDK] Invalid max_attempts value: %s. max_attempts must be >= 1. "
322
+ "Defaulting to 1 to ensure at least one polling attempt.",
323
+ max_attempts,
324
+ )
325
+ max_attempts = 1
326
+
327
+ attempts = 0
328
+
329
+ # Build headers for polling
330
+ poll_headers: dict[str, str] = {
331
+ "X-Stainless-Poll-Helper": "true",
332
+ "X-Stainless-Custom-Poll-Interval": str(int(poll_interval * 1000)),
333
+ }
334
+ if extra_headers:
335
+ for k, v in extra_headers.items():
336
+ if not isinstance(v, Omit):
337
+ poll_headers[k] = v # type: ignore[assignment]
338
+
339
+ while attempts < max_attempts:
340
+ # Use with_raw_response to access response headers
341
+ response = self.with_raw_response.retrieve(
342
+ id,
343
+ extra_headers=poll_headers,
344
+ extra_query=extra_query,
345
+ extra_body=extra_body,
346
+ timeout=timeout,
347
+ )
348
+
349
+ intent = response.parse()
350
+
351
+ # Check if condition is met
352
+ if condition(intent):
353
+ return intent
354
+
355
+ attempts += 1
356
+
357
+ # If we've reached max attempts, throw an error
358
+ if attempts >= max_attempts:
359
+ raise PollTimeoutError(
360
+ intent_id=id,
361
+ attempts=attempts,
362
+ poll_interval=poll_interval,
363
+ max_attempts=max_attempts,
364
+ )
365
+
366
+ # Check if server suggests a polling interval
367
+ sleep_interval = poll_interval
368
+ header_interval = response.headers.get("retry-after-ms")
369
+ if header_interval:
370
+ try:
371
+ header_interval_ms = int(header_interval)
372
+ sleep_interval = header_interval_ms / 1000.0
373
+ except ValueError:
374
+ pass # Ignore invalid header values
375
+
376
+ # Sleep before next poll
377
+ self._sleep(sleep_interval)
378
+
379
+ # This should never be reached due to the throw above, but TypeScript needs it
380
+ raise PollTimeoutError(
381
+ intent_id=id,
382
+ attempts=attempts,
383
+ poll_interval=poll_interval,
384
+ max_attempts=max_attempts,
385
+ )
386
+
387
+ def poll_until_completed(
388
+ self,
389
+ id: str,
390
+ *,
391
+ poll_interval: float = 5.0,
392
+ max_attempts: int = 120,
393
+ extra_headers: Headers | None = None,
394
+ extra_query: Query | None = None,
395
+ extra_body: Body | None = None,
396
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
397
+ ) -> Union[CompletedCheckoutIntent, FailedCheckoutIntent]:
398
+ """
399
+ A helper to poll a checkout intent until it reaches a completed state
400
+ (completed or failed).
401
+
402
+ Args:
403
+ id: The checkout intent ID to poll
404
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
405
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
406
+ extra_headers: Send extra headers
407
+ extra_query: Add additional query parameters to the request
408
+ extra_body: Add additional JSON properties to the request
409
+ timeout: Override the client-level default timeout for this request, in seconds
410
+
411
+ Returns:
412
+ The checkout intent once it reaches completed or failed state
413
+
414
+ Example:
415
+ ```python
416
+ checkout_intent = client.checkout_intents.poll_until_completed("id")
417
+ if checkout_intent.state == "completed":
418
+ print("Order placed successfully!")
419
+ elif checkout_intent.state == "failed":
420
+ print("Order failed:", checkout_intent.failure_reason)
421
+ ```
422
+ """
423
+
424
+ def is_completed(
425
+ intent: CheckoutIntent,
426
+ ) -> TypeGuard[Union[CompletedCheckoutIntent, FailedCheckoutIntent]]:
427
+ return intent.state in ("completed", "failed")
428
+
429
+ return self._poll_until(
430
+ id,
431
+ is_completed,
432
+ poll_interval=poll_interval,
433
+ max_attempts=max_attempts,
434
+ extra_headers=extra_headers,
435
+ extra_query=extra_query,
436
+ extra_body=extra_body,
437
+ timeout=timeout,
438
+ )
439
+
440
+ def poll_until_awaiting_confirmation(
441
+ self,
442
+ id: str,
443
+ *,
444
+ poll_interval: float = 5.0,
445
+ max_attempts: int = 120,
446
+ extra_headers: Headers | None = None,
447
+ extra_query: Query | None = None,
448
+ extra_body: Body | None = None,
449
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
450
+ ) -> Union[AwaitingConfirmationCheckoutIntent, FailedCheckoutIntent]:
451
+ """
452
+ A helper to poll a checkout intent until it's ready for confirmation
453
+ (awaiting_confirmation state) or has failed. This is typically used after
454
+ creating a checkout intent to wait for the offer to be retrieved from the merchant.
455
+
456
+ The intent can reach awaiting_confirmation (success - ready to confirm) or failed
457
+ (offer retrieval failed). Always check the state after polling.
458
+
459
+ Args:
460
+ id: The checkout intent ID to poll
461
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
462
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
463
+ extra_headers: Send extra headers
464
+ extra_query: Add additional query parameters to the request
465
+ extra_body: Add additional JSON properties to the request
466
+ timeout: Override the client-level default timeout for this request, in seconds
467
+
468
+ Returns:
469
+ The checkout intent once it reaches awaiting_confirmation or failed state
470
+
471
+ Example:
472
+ ```python
473
+ intent = client.checkout_intents.poll_until_awaiting_confirmation("id")
474
+
475
+ if intent.state == "awaiting_confirmation":
476
+ # Review the offer before confirming
477
+ print("Total:", intent.offer.cost.total)
478
+ elif intent.state == "failed":
479
+ # Handle failure (e.g., offer retrieval failed, product out of stock)
480
+ print("Failed:", intent.failure_reason)
481
+ ```
482
+ """
483
+
484
+ def is_awaiting_confirmation(
485
+ intent: CheckoutIntent,
486
+ ) -> TypeGuard[Union[AwaitingConfirmationCheckoutIntent, FailedCheckoutIntent]]:
487
+ return intent.state in ("awaiting_confirmation", "failed")
488
+
489
+ return self._poll_until(
490
+ id,
491
+ is_awaiting_confirmation,
492
+ poll_interval=poll_interval,
493
+ max_attempts=max_attempts,
494
+ extra_headers=extra_headers,
495
+ extra_query=extra_query,
496
+ extra_body=extra_body,
497
+ timeout=timeout,
498
+ )
499
+
500
+ def create_and_poll(
501
+ self,
502
+ *,
503
+ buyer: BuyerParam,
504
+ product_url: str,
505
+ quantity: float,
506
+ variant_selections: Iterable[VariantSelectionParam] | Omit = omit,
507
+ poll_interval: float = 5.0,
508
+ max_attempts: int = 120,
509
+ extra_headers: Headers | None = None,
510
+ extra_query: Query | None = None,
511
+ extra_body: Body | None = None,
512
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
513
+ ) -> Union[AwaitingConfirmationCheckoutIntent, FailedCheckoutIntent]:
514
+ """
515
+ A helper to create a checkout intent and poll until it's ready for confirmation.
516
+ This follows the Rye documented flow: create → poll until awaiting_confirmation.
517
+
518
+ After this method completes, you should review the offer (pricing, shipping, taxes)
519
+ with the user before calling confirm().
520
+
521
+ Args:
522
+ buyer: Buyer information
523
+ product_url: URL of the product to purchase
524
+ quantity: Quantity of the product
525
+ variant_selections: Product variant selections (optional)
526
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
527
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
528
+ extra_headers: Send extra headers
529
+ extra_query: Add additional query parameters to the request
530
+ extra_body: Add additional JSON properties to the request
531
+ timeout: Override the client-level default timeout for this request, in seconds
532
+
533
+ Returns:
534
+ The checkout intent once it reaches awaiting_confirmation or failed state
535
+
536
+ Example:
537
+ ```python
538
+ # Phase 1: Create and wait for offer
539
+ intent = client.checkout_intents.create_and_poll(
540
+ buyer={
541
+ "address1": "123 Main St",
542
+ "city": "New York",
543
+ "country": "US",
544
+ "email": "john.doe@example.com",
545
+ "first_name": "John",
546
+ "last_name": "Doe",
547
+ "phone": "1234567890",
548
+ "postal_code": "10001",
549
+ "province": "NY",
550
+ },
551
+ product_url="https://example.com/product",
552
+ quantity=1,
553
+ )
554
+
555
+ # Review the offer with the user
556
+ print("Total:", intent.offer.cost.total)
557
+
558
+ # Phase 2: Confirm with payment
559
+ completed = client.checkout_intents.confirm_and_poll(
560
+ intent.id, payment_method={"type": "stripe_token", "stripe_token": "tok_visa"}
561
+ )
562
+ ```
563
+ """
564
+ intent = self.create(
565
+ buyer=buyer,
566
+ product_url=product_url,
567
+ quantity=quantity,
568
+ variant_selections=variant_selections,
569
+ extra_headers=extra_headers,
570
+ extra_query=extra_query,
571
+ extra_body=extra_body,
572
+ timeout=timeout,
573
+ )
574
+ return self.poll_until_awaiting_confirmation(
575
+ intent.id,
576
+ poll_interval=poll_interval,
577
+ max_attempts=max_attempts,
578
+ extra_headers=extra_headers,
579
+ extra_query=extra_query,
580
+ extra_body=extra_body,
581
+ timeout=timeout,
582
+ )
583
+
584
+ def confirm_and_poll(
585
+ self,
586
+ id: str,
587
+ *,
588
+ payment_method: PaymentMethodParam,
589
+ poll_interval: float = 5.0,
590
+ max_attempts: int = 120,
591
+ extra_headers: Headers | None = None,
592
+ extra_query: Query | None = None,
593
+ extra_body: Body | None = None,
594
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
595
+ ) -> Union[CompletedCheckoutIntent, FailedCheckoutIntent]:
596
+ """
597
+ A helper to confirm a checkout intent and poll until it reaches a completed state
598
+ (completed or failed).
599
+
600
+ Args:
601
+ id: The checkout intent ID to confirm
602
+ payment_method: Payment method information
603
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
604
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
605
+ extra_headers: Send extra headers
606
+ extra_query: Add additional query parameters to the request
607
+ extra_body: Add additional JSON properties to the request
608
+ timeout: Override the client-level default timeout for this request, in seconds
609
+
610
+ Returns:
611
+ The checkout intent once it reaches completed or failed state
612
+
613
+ Example:
614
+ ```python
615
+ checkout_intent = client.checkout_intents.confirm_and_poll(
616
+ "id",
617
+ payment_method={
618
+ "stripe_token": "tok_1RkrWWHGDlstla3f1Fc7ZrhH",
619
+ "type": "stripe_token",
620
+ },
621
+ )
622
+
623
+ if checkout_intent.state == "completed":
624
+ print("Order placed successfully!")
625
+ elif checkout_intent.state == "failed":
626
+ print("Order failed:", checkout_intent.failure_reason)
627
+ ```
628
+ """
629
+ intent = self.confirm(
630
+ id,
631
+ payment_method=payment_method,
632
+ extra_headers=extra_headers,
633
+ extra_query=extra_query,
634
+ extra_body=extra_body,
635
+ timeout=timeout,
636
+ )
637
+ return self.poll_until_completed(
638
+ intent.id,
639
+ poll_interval=poll_interval,
640
+ max_attempts=max_attempts,
641
+ extra_headers=extra_headers,
642
+ extra_query=extra_query,
643
+ extra_body=extra_body,
644
+ timeout=timeout,
645
+ )
646
+
221
647
 
222
648
  class AsyncCheckoutIntentsResource(AsyncAPIResource):
223
649
  @cached_property
@@ -323,6 +749,59 @@ class AsyncCheckoutIntentsResource(AsyncAPIResource):
323
749
  ),
324
750
  )
325
751
 
752
+ def list(
753
+ self,
754
+ *,
755
+ id: SequenceNotStr[str] | Omit = omit,
756
+ after: str | Omit = omit,
757
+ before: str | Omit = omit,
758
+ limit: float | Omit = omit,
759
+ state: List[Literal["retrieving_offer", "awaiting_confirmation", "placing_order", "completed", "failed"]]
760
+ | Omit = omit,
761
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
762
+ # The extra values given here take precedence over values defined on the client or passed to this method.
763
+ extra_headers: Headers | None = None,
764
+ extra_query: Query | None = None,
765
+ extra_body: Body | None = None,
766
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
767
+ ) -> AsyncPaginator[CheckoutIntent, AsyncCursorPagination[CheckoutIntent]]:
768
+ """
769
+ Retrieve a paginated list of checkout intents
770
+
771
+ Enables developers to query checkout intents associated with their account, with
772
+ filters and cursor-based pagination.
773
+
774
+ Args:
775
+ extra_headers: Send extra headers
776
+
777
+ extra_query: Add additional query parameters to the request
778
+
779
+ extra_body: Add additional JSON properties to the request
780
+
781
+ timeout: Override the client-level default timeout for this request, in seconds
782
+ """
783
+ return self._get_api_list(
784
+ "/api/v1/checkout-intents",
785
+ page=AsyncCursorPagination[CheckoutIntent],
786
+ options=make_request_options(
787
+ extra_headers=extra_headers,
788
+ extra_query=extra_query,
789
+ extra_body=extra_body,
790
+ timeout=timeout,
791
+ query=maybe_transform(
792
+ {
793
+ "id": id,
794
+ "after": after,
795
+ "before": before,
796
+ "limit": limit,
797
+ "state": state,
798
+ },
799
+ checkout_intent_list_params.CheckoutIntentListParams,
800
+ ),
801
+ ),
802
+ model=cast(Any, CheckoutIntent), # Union types cannot be passed in as arguments in the type system
803
+ )
804
+
326
805
  async def add_payment(
327
806
  self,
328
807
  id: str,
@@ -407,6 +886,365 @@ class AsyncCheckoutIntentsResource(AsyncAPIResource):
407
886
  ),
408
887
  )
409
888
 
889
+ async def _poll_until(
890
+ self,
891
+ id: str,
892
+ condition: Callable[[CheckoutIntent], TypeGuard[T]],
893
+ *,
894
+ poll_interval: float = 5.0,
895
+ max_attempts: int = 120,
896
+ extra_headers: Headers | None = None,
897
+ extra_query: Query | None = None,
898
+ extra_body: Body | None = None,
899
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
900
+ ) -> T:
901
+ """
902
+ A helper to poll a checkout intent until a specific condition is met.
903
+
904
+ Args:
905
+ id: The checkout intent ID to poll
906
+ condition: A callable that returns True when the desired state is reached
907
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
908
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
909
+ extra_headers: Send extra headers
910
+ extra_query: Add additional query parameters to the request
911
+ extra_body: Add additional JSON properties to the request
912
+ timeout: Override the client-level default timeout for this request, in seconds
913
+
914
+ Returns:
915
+ The checkout intent once the condition is met
916
+
917
+ Raises:
918
+ CheckoutIntentsError: If the maximum number of attempts is reached without the condition being met
919
+ """
920
+ if max_attempts < 1:
921
+ logger.warning(
922
+ "[Checkout Intents SDK] Invalid max_attempts value: %s. max_attempts must be >= 1. "
923
+ "Defaulting to 1 to ensure at least one polling attempt.",
924
+ max_attempts,
925
+ )
926
+ max_attempts = 1
927
+
928
+ attempts = 0
929
+
930
+ # Build headers for polling
931
+ poll_headers: dict[str, str] = {
932
+ "X-Stainless-Poll-Helper": "true",
933
+ "X-Stainless-Custom-Poll-Interval": str(int(poll_interval * 1000)),
934
+ }
935
+ if extra_headers:
936
+ for k, v in extra_headers.items():
937
+ if not isinstance(v, Omit):
938
+ poll_headers[k] = v # type: ignore[assignment]
939
+
940
+ while attempts < max_attempts:
941
+ # Use with_raw_response to access response headers
942
+ response = await self.with_raw_response.retrieve(
943
+ id,
944
+ extra_headers=poll_headers,
945
+ extra_query=extra_query,
946
+ extra_body=extra_body,
947
+ timeout=timeout,
948
+ )
949
+
950
+ intent = await response.parse()
951
+
952
+ # Check if condition is met
953
+ if condition(intent):
954
+ return intent
955
+
956
+ attempts += 1
957
+
958
+ # If we've reached max attempts, throw an error
959
+ if attempts >= max_attempts:
960
+ raise PollTimeoutError(
961
+ intent_id=id,
962
+ attempts=attempts,
963
+ poll_interval=poll_interval,
964
+ max_attempts=max_attempts,
965
+ )
966
+
967
+ # Check if server suggests a polling interval
968
+ sleep_interval = poll_interval
969
+ header_interval = response.headers.get("retry-after-ms")
970
+ if header_interval:
971
+ try:
972
+ header_interval_ms = int(header_interval)
973
+ sleep_interval = header_interval_ms / 1000.0
974
+ except ValueError:
975
+ pass # Ignore invalid header values
976
+
977
+ # Sleep before next poll
978
+ await self._sleep(sleep_interval)
979
+
980
+ # This should never be reached due to the throw above, but TypeScript needs it
981
+ raise PollTimeoutError(
982
+ intent_id=id,
983
+ attempts=attempts,
984
+ poll_interval=poll_interval,
985
+ max_attempts=max_attempts,
986
+ )
987
+
988
+ async def poll_until_completed(
989
+ self,
990
+ id: str,
991
+ *,
992
+ poll_interval: float = 5.0,
993
+ max_attempts: int = 120,
994
+ extra_headers: Headers | None = None,
995
+ extra_query: Query | None = None,
996
+ extra_body: Body | None = None,
997
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
998
+ ) -> Union[CompletedCheckoutIntent, FailedCheckoutIntent]:
999
+ """
1000
+ A helper to poll a checkout intent until it reaches a completed state
1001
+ (completed or failed).
1002
+
1003
+ Args:
1004
+ id: The checkout intent ID to poll
1005
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
1006
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
1007
+ extra_headers: Send extra headers
1008
+ extra_query: Add additional query parameters to the request
1009
+ extra_body: Add additional JSON properties to the request
1010
+ timeout: Override the client-level default timeout for this request, in seconds
1011
+
1012
+ Returns:
1013
+ The checkout intent once it reaches completed or failed state
1014
+
1015
+ Example:
1016
+ ```python
1017
+ checkout_intent = await client.checkout_intents.poll_until_completed("id")
1018
+ if checkout_intent.state == "completed":
1019
+ print("Order placed successfully!")
1020
+ elif checkout_intent.state == "failed":
1021
+ print("Order failed:", checkout_intent.failure_reason)
1022
+ ```
1023
+ """
1024
+
1025
+ def is_completed(
1026
+ intent: CheckoutIntent,
1027
+ ) -> TypeGuard[Union[CompletedCheckoutIntent, FailedCheckoutIntent]]:
1028
+ return intent.state in ("completed", "failed")
1029
+
1030
+ return await self._poll_until(
1031
+ id,
1032
+ is_completed,
1033
+ poll_interval=poll_interval,
1034
+ max_attempts=max_attempts,
1035
+ extra_headers=extra_headers,
1036
+ extra_query=extra_query,
1037
+ extra_body=extra_body,
1038
+ timeout=timeout,
1039
+ )
1040
+
1041
+ async def poll_until_awaiting_confirmation(
1042
+ self,
1043
+ id: str,
1044
+ *,
1045
+ poll_interval: float = 5.0,
1046
+ max_attempts: int = 120,
1047
+ extra_headers: Headers | None = None,
1048
+ extra_query: Query | None = None,
1049
+ extra_body: Body | None = None,
1050
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
1051
+ ) -> Union[AwaitingConfirmationCheckoutIntent, FailedCheckoutIntent]:
1052
+ """
1053
+ A helper to poll a checkout intent until it's ready for confirmation
1054
+ (awaiting_confirmation state) or has failed. This is typically used after
1055
+ creating a checkout intent to wait for the offer to be retrieved from the merchant.
1056
+
1057
+ The intent can reach awaiting_confirmation (success - ready to confirm) or failed
1058
+ (offer retrieval failed). Always check the state after polling.
1059
+
1060
+ Args:
1061
+ id: The checkout intent ID to poll
1062
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
1063
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
1064
+ extra_headers: Send extra headers
1065
+ extra_query: Add additional query parameters to the request
1066
+ extra_body: Add additional JSON properties to the request
1067
+ timeout: Override the client-level default timeout for this request, in seconds
1068
+
1069
+ Returns:
1070
+ The checkout intent once it reaches awaiting_confirmation or failed state
1071
+
1072
+ Example:
1073
+ ```python
1074
+ intent = await client.checkout_intents.poll_until_awaiting_confirmation("id")
1075
+
1076
+ if intent.state == "awaiting_confirmation":
1077
+ # Review the offer before confirming
1078
+ print("Total:", intent.offer.cost.total)
1079
+ elif intent.state == "failed":
1080
+ # Handle failure (e.g., offer retrieval failed, product out of stock)
1081
+ print("Failed:", intent.failure_reason)
1082
+ ```
1083
+ """
1084
+
1085
+ def is_awaiting_confirmation(
1086
+ intent: CheckoutIntent,
1087
+ ) -> TypeGuard[Union[AwaitingConfirmationCheckoutIntent, FailedCheckoutIntent]]:
1088
+ return intent.state in ("awaiting_confirmation", "failed")
1089
+
1090
+ return await self._poll_until(
1091
+ id,
1092
+ is_awaiting_confirmation,
1093
+ poll_interval=poll_interval,
1094
+ max_attempts=max_attempts,
1095
+ extra_headers=extra_headers,
1096
+ extra_query=extra_query,
1097
+ extra_body=extra_body,
1098
+ timeout=timeout,
1099
+ )
1100
+
1101
+ async def create_and_poll(
1102
+ self,
1103
+ *,
1104
+ buyer: BuyerParam,
1105
+ product_url: str,
1106
+ quantity: float,
1107
+ variant_selections: Iterable[VariantSelectionParam] | Omit = omit,
1108
+ poll_interval: float = 5.0,
1109
+ max_attempts: int = 120,
1110
+ extra_headers: Headers | None = None,
1111
+ extra_query: Query | None = None,
1112
+ extra_body: Body | None = None,
1113
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
1114
+ ) -> Union[AwaitingConfirmationCheckoutIntent, FailedCheckoutIntent]:
1115
+ """
1116
+ A helper to create a checkout intent and poll until it's ready for confirmation.
1117
+ This follows the Rye documented flow: create → poll until awaiting_confirmation.
1118
+
1119
+ After this method completes, you should review the offer (pricing, shipping, taxes)
1120
+ with the user before calling confirm().
1121
+
1122
+ Args:
1123
+ buyer: Buyer information
1124
+ product_url: URL of the product to purchase
1125
+ quantity: Quantity of the product
1126
+ variant_selections: Product variant selections (optional)
1127
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
1128
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
1129
+ extra_headers: Send extra headers
1130
+ extra_query: Add additional query parameters to the request
1131
+ extra_body: Add additional JSON properties to the request
1132
+ timeout: Override the client-level default timeout for this request, in seconds
1133
+
1134
+ Returns:
1135
+ The checkout intent once it reaches awaiting_confirmation or failed state
1136
+
1137
+ Example:
1138
+ ```python
1139
+ # Phase 1: Create and wait for offer
1140
+ intent = await client.checkout_intents.create_and_poll(
1141
+ buyer={
1142
+ "address1": "123 Main St",
1143
+ "city": "New York",
1144
+ "country": "US",
1145
+ "email": "john.doe@example.com",
1146
+ "first_name": "John",
1147
+ "last_name": "Doe",
1148
+ "phone": "1234567890",
1149
+ "postal_code": "10001",
1150
+ "province": "NY",
1151
+ },
1152
+ product_url="https://example.com/product",
1153
+ quantity=1,
1154
+ )
1155
+
1156
+ # Review the offer with the user
1157
+ print("Total:", intent.offer.cost.total)
1158
+
1159
+ # Phase 2: Confirm with payment
1160
+ completed = await client.checkout_intents.confirm_and_poll(
1161
+ intent.id, payment_method={"type": "stripe_token", "stripe_token": "tok_visa"}
1162
+ )
1163
+ ```
1164
+ """
1165
+ intent = await self.create(
1166
+ buyer=buyer,
1167
+ product_url=product_url,
1168
+ quantity=quantity,
1169
+ variant_selections=variant_selections,
1170
+ extra_headers=extra_headers,
1171
+ extra_query=extra_query,
1172
+ extra_body=extra_body,
1173
+ timeout=timeout,
1174
+ )
1175
+ return await self.poll_until_awaiting_confirmation(
1176
+ intent.id,
1177
+ poll_interval=poll_interval,
1178
+ max_attempts=max_attempts,
1179
+ extra_headers=extra_headers,
1180
+ extra_query=extra_query,
1181
+ extra_body=extra_body,
1182
+ timeout=timeout,
1183
+ )
1184
+
1185
+ async def confirm_and_poll(
1186
+ self,
1187
+ id: str,
1188
+ *,
1189
+ payment_method: PaymentMethodParam,
1190
+ poll_interval: float = 5.0,
1191
+ max_attempts: int = 120,
1192
+ extra_headers: Headers | None = None,
1193
+ extra_query: Query | None = None,
1194
+ extra_body: Body | None = None,
1195
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
1196
+ ) -> Union[CompletedCheckoutIntent, FailedCheckoutIntent]:
1197
+ """
1198
+ A helper to confirm a checkout intent and poll until it reaches a completed state
1199
+ (completed or failed).
1200
+
1201
+ Args:
1202
+ id: The checkout intent ID to confirm
1203
+ payment_method: Payment method information
1204
+ poll_interval: The interval in seconds between polling attempts (default: 5.0)
1205
+ max_attempts: The maximum number of polling attempts before timing out (default: 120)
1206
+ extra_headers: Send extra headers
1207
+ extra_query: Add additional query parameters to the request
1208
+ extra_body: Add additional JSON properties to the request
1209
+ timeout: Override the client-level default timeout for this request, in seconds
1210
+
1211
+ Returns:
1212
+ The checkout intent once it reaches completed or failed state
1213
+
1214
+ Example:
1215
+ ```python
1216
+ checkout_intent = await client.checkout_intents.confirm_and_poll(
1217
+ "id",
1218
+ payment_method={
1219
+ "stripe_token": "tok_1RkrWWHGDlstla3f1Fc7ZrhH",
1220
+ "type": "stripe_token",
1221
+ },
1222
+ )
1223
+
1224
+ if checkout_intent.state == "completed":
1225
+ print("Order placed successfully!")
1226
+ elif checkout_intent.state == "failed":
1227
+ print("Order failed:", checkout_intent.failure_reason)
1228
+ ```
1229
+ """
1230
+ intent = await self.confirm(
1231
+ id,
1232
+ payment_method=payment_method,
1233
+ extra_headers=extra_headers,
1234
+ extra_query=extra_query,
1235
+ extra_body=extra_body,
1236
+ timeout=timeout,
1237
+ )
1238
+ return await self.poll_until_completed(
1239
+ intent.id,
1240
+ poll_interval=poll_interval,
1241
+ max_attempts=max_attempts,
1242
+ extra_headers=extra_headers,
1243
+ extra_query=extra_query,
1244
+ extra_body=extra_body,
1245
+ timeout=timeout,
1246
+ )
1247
+
410
1248
 
411
1249
  class CheckoutIntentsResourceWithRawResponse:
412
1250
  def __init__(self, checkout_intents: CheckoutIntentsResource) -> None:
@@ -418,12 +1256,27 @@ class CheckoutIntentsResourceWithRawResponse:
418
1256
  self.retrieve = to_raw_response_wrapper(
419
1257
  checkout_intents.retrieve,
420
1258
  )
1259
+ self.list = to_raw_response_wrapper(
1260
+ checkout_intents.list,
1261
+ )
421
1262
  self.add_payment = to_raw_response_wrapper(
422
1263
  checkout_intents.add_payment,
423
1264
  )
424
1265
  self.confirm = to_raw_response_wrapper(
425
1266
  checkout_intents.confirm,
426
1267
  )
1268
+ self.poll_until_completed = to_raw_response_wrapper(
1269
+ checkout_intents.poll_until_completed,
1270
+ )
1271
+ self.poll_until_awaiting_confirmation = to_raw_response_wrapper(
1272
+ checkout_intents.poll_until_awaiting_confirmation,
1273
+ )
1274
+ self.create_and_poll = to_raw_response_wrapper(
1275
+ checkout_intents.create_and_poll,
1276
+ )
1277
+ self.confirm_and_poll = to_raw_response_wrapper(
1278
+ checkout_intents.confirm_and_poll,
1279
+ )
427
1280
 
428
1281
 
429
1282
  class AsyncCheckoutIntentsResourceWithRawResponse:
@@ -436,12 +1289,27 @@ class AsyncCheckoutIntentsResourceWithRawResponse:
436
1289
  self.retrieve = async_to_raw_response_wrapper(
437
1290
  checkout_intents.retrieve,
438
1291
  )
1292
+ self.list = async_to_raw_response_wrapper(
1293
+ checkout_intents.list,
1294
+ )
439
1295
  self.add_payment = async_to_raw_response_wrapper(
440
1296
  checkout_intents.add_payment,
441
1297
  )
442
1298
  self.confirm = async_to_raw_response_wrapper(
443
1299
  checkout_intents.confirm,
444
1300
  )
1301
+ self.poll_until_completed = async_to_raw_response_wrapper(
1302
+ checkout_intents.poll_until_completed,
1303
+ )
1304
+ self.poll_until_awaiting_confirmation = async_to_raw_response_wrapper(
1305
+ checkout_intents.poll_until_awaiting_confirmation,
1306
+ )
1307
+ self.create_and_poll = async_to_raw_response_wrapper(
1308
+ checkout_intents.create_and_poll,
1309
+ )
1310
+ self.confirm_and_poll = async_to_raw_response_wrapper(
1311
+ checkout_intents.confirm_and_poll,
1312
+ )
445
1313
 
446
1314
 
447
1315
  class CheckoutIntentsResourceWithStreamingResponse:
@@ -454,12 +1322,27 @@ class CheckoutIntentsResourceWithStreamingResponse:
454
1322
  self.retrieve = to_streamed_response_wrapper(
455
1323
  checkout_intents.retrieve,
456
1324
  )
1325
+ self.list = to_streamed_response_wrapper(
1326
+ checkout_intents.list,
1327
+ )
457
1328
  self.add_payment = to_streamed_response_wrapper(
458
1329
  checkout_intents.add_payment,
459
1330
  )
460
1331
  self.confirm = to_streamed_response_wrapper(
461
1332
  checkout_intents.confirm,
462
1333
  )
1334
+ self.poll_until_completed = to_streamed_response_wrapper(
1335
+ checkout_intents.poll_until_completed,
1336
+ )
1337
+ self.poll_until_awaiting_confirmation = to_streamed_response_wrapper(
1338
+ checkout_intents.poll_until_awaiting_confirmation,
1339
+ )
1340
+ self.create_and_poll = to_streamed_response_wrapper(
1341
+ checkout_intents.create_and_poll,
1342
+ )
1343
+ self.confirm_and_poll = to_streamed_response_wrapper(
1344
+ checkout_intents.confirm_and_poll,
1345
+ )
463
1346
 
464
1347
 
465
1348
  class AsyncCheckoutIntentsResourceWithStreamingResponse:
@@ -472,9 +1355,24 @@ class AsyncCheckoutIntentsResourceWithStreamingResponse:
472
1355
  self.retrieve = async_to_streamed_response_wrapper(
473
1356
  checkout_intents.retrieve,
474
1357
  )
1358
+ self.list = async_to_streamed_response_wrapper(
1359
+ checkout_intents.list,
1360
+ )
475
1361
  self.add_payment = async_to_streamed_response_wrapper(
476
1362
  checkout_intents.add_payment,
477
1363
  )
478
1364
  self.confirm = async_to_streamed_response_wrapper(
479
1365
  checkout_intents.confirm,
480
1366
  )
1367
+ self.poll_until_completed = async_to_streamed_response_wrapper(
1368
+ checkout_intents.poll_until_completed,
1369
+ )
1370
+ self.poll_until_awaiting_confirmation = async_to_streamed_response_wrapper(
1371
+ checkout_intents.poll_until_awaiting_confirmation,
1372
+ )
1373
+ self.create_and_poll = async_to_streamed_response_wrapper(
1374
+ checkout_intents.create_and_poll,
1375
+ )
1376
+ self.confirm_and_poll = async_to_streamed_response_wrapper(
1377
+ checkout_intents.confirm_and_poll,
1378
+ )