diff --git a/src/CheckoutSdk/AgenticCommerce/AgenticClient.cs b/src/CheckoutSdk/AgenticCommerce/AgenticClient.cs
new file mode 100644
index 00000000..56477868
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/AgenticClient.cs
@@ -0,0 +1,113 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Checkout.AgenticCommerce.Requests;
+using Checkout.AgenticCommerce.Responses;
+
+namespace Checkout.AgenticCommerce
+{
+ ///
+ /// Agentic Commerce API Client
+ ///
+ public class AgenticClient : AbstractClient, IAgenticClient
+ {
+ private const string AgenticPath = "agentic";
+ private const string EnrollPath = "enroll";
+ private const string PurchaseIntentPath = "purchase-intent";
+ private const string CredentialsPath = "credentials";
+
+ public AgenticClient(IApiClient apiClient, CheckoutConfiguration configuration) :
+ base(apiClient, configuration, SdkAuthorizationType.OAuth)
+ {
+ }
+
+ // Agentic Commerce enrollment
+ // ----------------------------------------------------------------
+
+ ///
+ /// Enroll a card for use with agentic commerce
+ /// [BETA]
+ ///
+ public Task EnrollACard(
+ EnrollACardRequest enrollACardRequest,
+ CancellationToken cancellationToken = default)
+ {
+ CheckoutUtils.ValidateParams("agenticEnrollRequest", enrollACardRequest);
+ return ApiClient.Post(
+ BuildPath(AgenticPath, EnrollPath),
+ SdkAuthorization(),
+ enrollACardRequest,
+ cancellationToken
+ );
+ }
+
+ // Purchase intents
+ // ----------------------------------------------------------------
+
+ ///
+ /// Create an agentic commerce purchase intent
+ /// [BETA]
+ ///
+ public Task CreatePurchaseIntent(
+ PurchaseIntentCreateRequest purchaseIntentCreateRequest,
+ CancellationToken cancellationToken = default)
+ {
+ CheckoutUtils.ValidateParams("agenticPurchaseIntentCreateRequest", purchaseIntentCreateRequest);
+ return ApiClient.Post(
+ BuildPath(AgenticPath, PurchaseIntentPath),
+ SdkAuthorization(),
+ purchaseIntentCreateRequest,
+ cancellationToken
+ );
+ }
+
+ ///
+ /// Create credentials for an agentic commerce purchase intent.
+ /// [BETA]
+ ///
+ public Task CreatePurchaseIntentCredentials(string id,
+ PurchaseIntentCredentialsCreateRequest purchaseIntentCredentialsCreateRequest,
+ CancellationToken cancellationToken = default)
+ {
+ CheckoutUtils.ValidateParams("id", id,"agenticPurchaseIntentCredentialsCreateRequest",
+ purchaseIntentCredentialsCreateRequest);
+ return ApiClient.Post(
+ BuildPath(AgenticPath, PurchaseIntentPath, id, CredentialsPath),
+ SdkAuthorization(),
+ purchaseIntentCredentialsCreateRequest,
+ cancellationToken
+ );
+ }
+
+ ///
+ /// Update an agentic commerce purchase intent
+ /// [BETA]
+ ///
+ public Task UpdatePurchaseIntent(string id,
+ PurchaseIntentUpdateRequest purchaseIntentUpdateRequest,
+ CancellationToken cancellationToken = default)
+ {
+ CheckoutUtils.ValidateParams("id", id, "agenticPurchaseIntentUpdateRequest", purchaseIntentUpdateRequest);
+ return ApiClient.Put(
+ BuildPath(AgenticPath, PurchaseIntentPath, id),
+ SdkAuthorization(),
+ purchaseIntentUpdateRequest,
+ cancellationToken
+ );
+ }
+
+ ///
+ /// Delete a purchase intent
+ /// Deletes a purchase intent for agentic commerce
+ ///
+ public Task DeletePurchaseIntent(string id,
+ CancellationToken cancellationToken = default)
+ {
+ CheckoutUtils.ValidateParams("id", id);
+ return ApiClient.Delete(
+ BuildPath(AgenticPath, PurchaseIntentPath, id),
+ SdkAuthorization(),
+ cancellationToken
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/Customer.cs b/src/CheckoutSdk/AgenticCommerce/Common/Customer.cs
new file mode 100644
index 00000000..be345e08
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/Customer.cs
@@ -0,0 +1,29 @@
+using Checkout.Common;
+
+namespace Checkout.AgenticCommerce.Common
+{
+ ///
+ /// The customer's details
+ ///
+ public class Customer
+ {
+ ///
+ /// The customer's email address
+ /// [Required]
+ ///
+ public string Email { get; set; }
+
+ ///
+ /// The customer's country, as a two-letter ISO 3166 country code
+ /// (https://www.checkout.com/docs/resources/codes/country-codes)
+ /// [Required]
+ ///
+ public CountryCode? CountryCode { get; set; }
+
+ ///
+ /// The customer's language, as a two-letter ISO 639 language code
+ /// [Required]
+ ///
+ public string LanguageCode { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/Device.cs b/src/CheckoutSdk/AgenticCommerce/Common/Device.cs
new file mode 100644
index 00000000..fb7c18e5
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/Device.cs
@@ -0,0 +1,32 @@
+namespace Checkout.AgenticCommerce.Common
+{
+ ///
+ /// The user's device
+ ///
+ public class Device
+ {
+ ///
+ /// The device's IP address
+ /// [Required]
+ ///
+ public string IpAddress { get; set; }
+
+ ///
+ /// The device's user agent
+ /// [Required]
+ ///
+ public string UserAgent { get; set; }
+
+ ///
+ /// The device brand
+ /// [Optional]
+ ///
+ public string DeviceBrand { get; set; }
+
+ ///
+ /// The device type
+ /// [Optional]
+ ///
+ public string DeviceType { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/Mandate.cs b/src/CheckoutSdk/AgenticCommerce/Common/Mandate.cs
new file mode 100644
index 00000000..4d98c511
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/Mandate.cs
@@ -0,0 +1,9 @@
+namespace Checkout.AgenticCommerce.Common
+{
+ ///
+ /// Mandate configuration for purchase intents
+ ///
+ public class Mandate : MandateBase
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/MandateBase.cs b/src/CheckoutSdk/AgenticCommerce/Common/MandateBase.cs
new file mode 100644
index 00000000..edb142e3
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/MandateBase.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Checkout.AgenticCommerce.Common
+{
+ ///
+ /// Mandate configuration for purchase intents
+ ///
+ public class MandateBase
+ {
+ ///
+ /// Purchase threshold configuration
+ ///
+ public PurchaseThreshold PurchaseThreshold { get; set; }
+
+ ///
+ /// A brief description of the purchase intent
+ /// <= 255 characters
+ /// [Required]
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// The date and time when the purchase intent expires, in ISO 8601 format.
+ /// This value must be set to a date and time in the future
+ /// [Required]
+ ///
+ public DateTime? ExpirationDate { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/MandateExtended.cs b/src/CheckoutSdk/AgenticCommerce/Common/MandateExtended.cs
new file mode 100644
index 00000000..ee35ba26
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/MandateExtended.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Checkout.AgenticCommerce.Common
+{
+ ///
+ /// Mandate configuration for purchase intents
+ ///
+ public class MandateExtended: MandateBase
+ {
+ ///
+ /// The unique identifier for the mandate
+ /// [Required]
+ ///
+ public string Id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/PurchaseIntentStatusType.cs b/src/CheckoutSdk/AgenticCommerce/Common/PurchaseIntentStatusType.cs
new file mode 100644
index 00000000..801d2080
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/PurchaseIntentStatusType.cs
@@ -0,0 +1,25 @@
+using System.Runtime.Serialization;
+
+namespace Checkout.AgenticCommerce.Common
+{
+ public enum PurchaseIntentStatusType
+ {
+ [EnumMember(Value = "active")]
+ Active,
+
+ [EnumMember(Value = "created")]
+ Created,
+
+ [EnumMember(Value = "cancelled")]
+ Cancelled,
+
+ [EnumMember(Value = "expired")]
+ Expired,
+
+ [EnumMember(Value = "declined")]
+ Declined,
+
+ [EnumMember(Value = "completed")]
+ Completed,
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/PurchaseThreshold.cs b/src/CheckoutSdk/AgenticCommerce/Common/PurchaseThreshold.cs
new file mode 100644
index 00000000..02666a7f
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/PurchaseThreshold.cs
@@ -0,0 +1,25 @@
+using Checkout.Common;
+
+namespace Checkout.AgenticCommerce.Common
+{
+ ///
+ /// Purchase threshold configuration
+ ///
+ public class PurchaseThreshold
+ {
+ ///
+ /// The maximum amount for the purchase
+ /// Format the amount (https://www.checkout.com/docs/payments/accept-payments/format-the-amount-value)
+ /// according to the currency_code
+ /// [Required]
+ ///
+ public int Amount { get; set; }
+
+ ///
+ /// The currency to use for the purchase, as an ISO 4217 currency code
+ /// (https://www.checkout.com/docs/resources/codes/currency-codes)
+ /// [Required]
+ ///
+ public Currency? CurrencyCode { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/Source.cs b/src/CheckoutSdk/AgenticCommerce/Common/Source.cs
new file mode 100644
index 00000000..714e1a35
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/Source.cs
@@ -0,0 +1,39 @@
+namespace Checkout.AgenticCommerce.Common
+{
+ ///
+ /// The payment source to enroll
+ ///
+ public class Source
+ {
+ ///
+ /// The full card number, without separators
+ /// [Required]
+ ///
+ public string Number { get; set; }
+
+ ///
+ /// Card expiry month
+ /// [ 13 .. 19 ] characters
+ /// [Required]
+ ///
+ public int ExpiryMonth { get; set; }
+
+ ///
+ /// Card expiry year
+ /// [Required]
+ ///
+ public int ExpiryYear { get; set; }
+
+ ///
+ /// Payment source type
+ /// [Required]
+ ///
+ public string Type { get; set; }
+
+ ///
+ /// The card's 3 or 4 digit card verification value (CVV) or security code
+ /// [Optional]
+ ///
+ public string Cvv { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/TransactionAmount.cs b/src/CheckoutSdk/AgenticCommerce/Common/TransactionAmount.cs
new file mode 100644
index 00000000..e875de9a
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/TransactionAmount.cs
@@ -0,0 +1,25 @@
+using Checkout.Common;
+
+namespace Checkout.AgenticCommerce.Common
+{
+ ///
+ /// Transaction amount information
+ ///
+ public class TransactionAmount
+ {
+ ///
+ /// The transaction amount
+ /// Format the amount (https://www.checkout.com/docs/payments/accept-payments/format-the-amount-value)
+ /// according to the currency_code
+ /// [Required]
+ ///
+ public int Amount { get; set; }
+
+ ///
+ /// The transaction currency, as an ISO 4217 currency code
+ /// (https://www.checkout.com/docs/resources/codes/currency-codes)
+ /// [Required]
+ ///
+ public Currency? CurrencyCode { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Common/TransactionData.cs b/src/CheckoutSdk/AgenticCommerce/Common/TransactionData.cs
new file mode 100644
index 00000000..fca8c8e4
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Common/TransactionData.cs
@@ -0,0 +1,42 @@
+using Checkout.Common;
+
+namespace Checkout.AgenticCommerce.Common
+{
+ ///
+ /// List of transaction data for the purchase
+ ///
+ public class TransactionData
+ {
+ ///
+ /// The merchant's country, as a two-letter ISO 3166 country code
+ /// (https://www.checkout.com/docs/resources/codes/country-codes)
+ /// [Required]
+ ///
+ public CountryCode? MerchantCountryCode { get; set; }
+
+ ///
+ /// The merchant's name
+ /// [Required]
+ ///
+ public string MerchantName { get; set; }
+
+ ///
+ /// The merchant's category code
+ /// (https://www.checkout.com/docs/developer-resources/codes/merchant-category-codes)
+ /// [Required]
+ ///
+ public string MerchantCategoryCode { get; set; }
+
+ ///
+ /// Transaction amount information
+ /// [Required]
+ ///
+ public TransactionAmount TransactionAmount { get; set; }
+
+ ///
+ /// The merchant's website URL
+ /// [Optional]
+ ///
+ public string MerchantUrl { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/IAgenticClient.cs b/src/CheckoutSdk/AgenticCommerce/IAgenticClient.cs
new file mode 100644
index 00000000..d716d4cf
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/IAgenticClient.cs
@@ -0,0 +1,58 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Checkout.AgenticCommerce.Requests;
+using Checkout.AgenticCommerce.Responses;
+
+namespace Checkout.AgenticCommerce
+{
+ ///
+ /// Agentic Commerce API Client
+ ///
+ public interface IAgenticClient
+ {
+ // Agentic Commerce enrollment
+ // ----------------------------------------------------------------
+
+ ///
+ /// Enroll a card for use with agentic commerce
+ /// [BETA]
+ ///
+ Task EnrollACard(
+ EnrollACardRequest enrollACardRequest,
+ CancellationToken cancellationToken = default);
+
+ // Purchase intents
+ // ----------------------------------------------------------------
+
+ ///
+ /// Create an agentic commerce purchase intent
+ /// [BETA]
+ ///
+ Task CreatePurchaseIntent(
+ PurchaseIntentCreateRequest purchaseIntentCreateRequest,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Create credentials for an agentic commerce purchase intent.
+ /// [BETA]
+ ///
+ Task CreatePurchaseIntentCredentials(string id,
+ PurchaseIntentCredentialsCreateRequest purchaseIntentCredentialsCreateRequest,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Update an agentic commerce purchase intent
+ /// [BETA]
+ ///
+ Task UpdatePurchaseIntent(string id,
+ PurchaseIntentUpdateRequest purchaseIntentUpdateRequest,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Cancel an agentic commerce purchase intent
+ /// [BETA]
+ ///
+ Task DeletePurchaseIntent(string id,
+ CancellationToken cancellationToken = default);
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Requests/EnrollACardRequest.cs b/src/CheckoutSdk/AgenticCommerce/Requests/EnrollACardRequest.cs
new file mode 100644
index 00000000..9ab748fa
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Requests/EnrollACardRequest.cs
@@ -0,0 +1,25 @@
+using Checkout.AgenticCommerce.Common;
+
+namespace Checkout.AgenticCommerce.Requests
+{
+ ///
+ /// Enroll a card for use with agentic commerce
+ ///
+ public class EnrollACardRequest
+ {
+ ///
+ /// The payment source to enroll
+ ///
+ public Source Source { get; set; }
+
+ ///
+ /// The user's device
+ ///
+ public Device Device { get; set; }
+
+ ///
+ /// The customer's details
+ ///
+ public Customer Customer { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Requests/PurchaseIntentCreateRequest.cs b/src/CheckoutSdk/AgenticCommerce/Requests/PurchaseIntentCreateRequest.cs
new file mode 100644
index 00000000..99409362
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Requests/PurchaseIntentCreateRequest.cs
@@ -0,0 +1,22 @@
+using Checkout.AgenticCommerce.Common;
+
+namespace Checkout.AgenticCommerce.Requests
+{
+ ///
+ /// Create an agentic commerce purchase intent
+ ///
+ public class PurchaseIntentCreateRequest : PurchaseIntentUpdateRequest
+ {
+ ///
+ /// The unique identifier for the network token
+ /// [Required]
+ ///
+ public string NetworkTokenId { get; set; }
+
+ ///
+ /// The user's device
+ /// [Required]
+ ///
+ public Device Device { get; set; }
+ }
+}
diff --git a/src/CheckoutSdk/AgenticCommerce/Requests/PurchaseIntentCredentialsCreateRequest.cs b/src/CheckoutSdk/AgenticCommerce/Requests/PurchaseIntentCredentialsCreateRequest.cs
new file mode 100644
index 00000000..c7065f9c
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Requests/PurchaseIntentCredentialsCreateRequest.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using Checkout.AgenticCommerce.Common;
+
+namespace Checkout.AgenticCommerce.Requests
+{
+ ///
+ /// Request to create a purchase intent credentials for agentic commerce
+ ///
+ public class PurchaseIntentCredentialsCreateRequest
+ {
+ ///
+ /// Array of transaction data for the purchase intent credentials
+ ///
+ public IList TransactionData { get; set; }
+ }
+}
diff --git a/src/CheckoutSdk/AgenticCommerce/Requests/PurchaseIntentUpdateRequest.cs b/src/CheckoutSdk/AgenticCommerce/Requests/PurchaseIntentUpdateRequest.cs
new file mode 100644
index 00000000..aa9af295
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Requests/PurchaseIntentUpdateRequest.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+using Checkout.AgenticCommerce.Common;
+
+namespace Checkout.AgenticCommerce.Requests
+{
+ ///
+ /// Create an agentic commerce purchase intent
+ ///
+ public class PurchaseIntentUpdateRequest
+ {
+ ///
+ /// A list of mandates associated with the purchase intent
+ ///
+ public IList Mandates { get; set; }
+
+ ///
+ /// A prompt or message for the customer. You can display this during the purchase process to provide additional
+ /// context or instructions
+ /// <= 4098 characters
+ ///
+ public string CustomerPrompt { get; set; }
+ }
+}
diff --git a/src/CheckoutSdk/AgenticCommerce/Responses/EnrollACardResponse.cs b/src/CheckoutSdk/AgenticCommerce/Responses/EnrollACardResponse.cs
new file mode 100644
index 00000000..65bb1373
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Responses/EnrollACardResponse.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Checkout.AgenticCommerce.Responses
+{
+ ///
+ /// Card enrolled successfully
+ ///
+ public class EnrollACardResponse : HttpMetadata
+ {
+ ///
+ /// The unique identifier for the provisioned token
+ /// [Required]
+ ///
+ public string TokenId { get; set; }
+
+ ///
+ /// The unique identifier for the provisioned token
+ /// [Required]
+ ///
+ public string NetworkTokenId { get; set; }
+
+ ///
+ /// The status of the enrollment
+ /// Value: "enrolled"
+ /// [Required]
+ ///
+ public string Status { get; set; }
+
+ ///
+ /// The date and time the enrollment was created, in ISO 8601 format
+ /// [Optional]
+ ///
+ public DateTime? CreatedAt { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/AgenticCommerce/Responses/PurchaseIntentResponse.cs b/src/CheckoutSdk/AgenticCommerce/Responses/PurchaseIntentResponse.cs
new file mode 100644
index 00000000..266fffcc
--- /dev/null
+++ b/src/CheckoutSdk/AgenticCommerce/Responses/PurchaseIntentResponse.cs
@@ -0,0 +1,47 @@
+using System.Collections.Generic;
+using Checkout.AgenticCommerce.Common;
+using Checkout.Common;
+
+namespace Checkout.AgenticCommerce.Responses
+{
+ ///
+ /// Response from purchase intent creation
+ ///
+ public class PurchaseIntentResponse : Resource
+ {
+ ///
+ /// The unique identifier for the purchase intent
+ ///
+ public string Id { get; set; }
+
+ ///
+ /// The current status of the purchase intent
+ ///
+ public PurchaseIntentStatusType? Status { get; set; }
+
+ ///
+ /// The scheme of the purchase intent
+ ///
+ public string Scheme { get; set; }
+
+ ///
+ /// The tokenid of the purchase intent
+ ///
+ public string TokenId { get; set; }
+
+ ///
+ /// The device information of the purchase intent
+ ///
+ public Device DeviceData { get; set; }
+
+ ///
+ /// The customer prompt of the purchase intent
+ ///
+ public string CustomerPrompt { get; set; }
+
+ ///
+ /// List of mandates for the purchase intent
+ ///
+ public IList Mandates { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/CheckoutSdk/CheckoutApi.cs b/src/CheckoutSdk/CheckoutApi.cs
index db137cd4..afe2b4f5 100644
--- a/src/CheckoutSdk/CheckoutApi.cs
+++ b/src/CheckoutSdk/CheckoutApi.cs
@@ -1,4 +1,5 @@
using Checkout.Accounts;
+using Checkout.AgenticCommerce;
using Checkout.Authentication;
using Checkout.Balances;
using Checkout.Issuing;
@@ -47,6 +48,7 @@ public class CheckoutApi : ICheckoutApi
private readonly IPaymentSessionsClient _paymentSessionsClient;
private readonly IForwardClient _forwardClient;
private readonly INetworkTokensClient _networkTokensClient;
+ private readonly IAgenticClient _agenticClient;
public CheckoutApi(CheckoutConfiguration configuration)
{
@@ -78,6 +80,7 @@ public CheckoutApi(CheckoutConfiguration configuration)
_paymentSessionsClient = new PaymentSessionsClient(baseApiClient, configuration);
_forwardClient = new ForwardClient(baseApiClient, configuration);
_networkTokensClient = new NetworkTokensClient(baseApiClient, configuration);
+ _agenticClient = new AgenticClient(baseApiClient, configuration);
}
private static ApiClient BaseApiClient(CheckoutConfiguration configuration)
@@ -221,5 +224,9 @@ public INetworkTokensClient NetworkTokensClient()
return _networkTokensClient;
}
+ public IAgenticClient AgenticClient()
+ {
+ return _agenticClient;
+ }
}
}
diff --git a/src/CheckoutSdk/ICheckoutApi.cs b/src/CheckoutSdk/ICheckoutApi.cs
index 37262804..3959c5f2 100644
--- a/src/CheckoutSdk/ICheckoutApi.cs
+++ b/src/CheckoutSdk/ICheckoutApi.cs
@@ -1,4 +1,5 @@
using Checkout.Accounts;
+using Checkout.AgenticCommerce;
using Checkout.Authentication;
using Checkout.Balances;
using Checkout.Issuing;
@@ -68,5 +69,7 @@ public interface ICheckoutApi : ICheckoutApiClient
IForwardClient ForwardClient();
INetworkTokensClient NetworkTokensClient();
+
+ IAgenticClient AgenticClient();
}
}
diff --git a/src/CheckoutSdk/OAuthScope.cs b/src/CheckoutSdk/OAuthScope.cs
index 1ae96aa1..f2ecc1a7 100644
--- a/src/CheckoutSdk/OAuthScope.cs
+++ b/src/CheckoutSdk/OAuthScope.cs
@@ -53,5 +53,6 @@ public enum OAuthScope
[OAuthScope("Payment Context")] PaymentContext,
[OAuthScope("forward")] Forward,
[OAuthScope("vault:network-tokens")] VaultNetworkTokens,
+ [OAuthScope("agentic:enroll")] AgenticEnroll,
}
}
diff --git a/test/CheckoutSdkTest/AgenticCommerce/AgenticClientTest.cs b/test/CheckoutSdkTest/AgenticCommerce/AgenticClientTest.cs
new file mode 100644
index 00000000..7ce42f26
--- /dev/null
+++ b/test/CheckoutSdkTest/AgenticCommerce/AgenticClientTest.cs
@@ -0,0 +1,896 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Moq;
+using Shouldly;
+using Xunit;
+
+using Checkout.AgenticCommerce.Common;
+using Checkout.AgenticCommerce.Requests;
+using Checkout.AgenticCommerce.Responses;
+using Checkout.Common;
+
+namespace Checkout.AgenticCommerce
+{
+ public class AgenticClientTest : UnitTestFixture
+ {
+ private readonly SdkAuthorization _authorization = new SdkAuthorization(PlatformType.DefaultOAuth, ValidDefaultSk);
+ private readonly Mock _apiClient = new Mock();
+ private readonly Mock _sdkCredentials = new Mock(PlatformType.DefaultOAuth);
+ private readonly Mock _httpClientFactory = new Mock();
+ private readonly Mock _configuration;
+
+ public AgenticClientTest()
+ {
+ _sdkCredentials.Setup(credentials => credentials.GetSdkAuthorization(SdkAuthorizationType.OAuth))
+ .Returns(_authorization);
+
+ _configuration = new Mock(_sdkCredentials.Object,
+ Environment.Sandbox, _httpClientFactory.Object);
+ }
+
+ [Fact]
+ private async Task EnrollShouldEnroll()
+ {
+ var agenticEnrollRequest = new EnrollACardRequest
+ {
+ Source = new Source
+ {
+ Number = "4242424242424242",
+ ExpiryMonth = 12,
+ ExpiryYear = 2025,
+ Cvv = "123",
+ Type = "Card"
+ },
+ Device = new Device
+ {
+ IpAddress = "192.168.1.1",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
+ },
+ Customer = new Customer
+ {
+ Email = "test@example.com",
+ CountryCode = CountryCode.US,
+ LanguageCode = "en"
+ }
+ };
+
+ var expectedResponse = new EnrollACardResponse
+ {
+ TokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Status = "enrolled",
+ CreatedAt = System.DateTime.UtcNow
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post("agentic/enroll", _authorization, agenticEnrollRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => expectedResponse);
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var response = await client.EnrollACard(agenticEnrollRequest, CancellationToken.None);
+
+ response.ShouldNotBeNull();
+ response.TokenId.ShouldBe(expectedResponse.TokenId);
+ response.Status.ShouldBe(expectedResponse.Status);
+ response.CreatedAt.ShouldBe(expectedResponse.CreatedAt);
+ }
+
+ [Fact]
+ private async Task EnrollShouldThrowExceptionWhenEnrollRequestIsNull()
+ {
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var exception = await Should.ThrowAsync(
+ async () => await client.EnrollACard(null, CancellationToken.None));
+
+ exception.Message.ShouldContain("agenticEnrollRequest");
+ }
+
+ [Fact]
+ private async Task EnrollShouldCallCorrectEnrollEndpoint()
+ {
+ var agenticEnrollRequest = new EnrollACardRequest
+ {
+ Source = new Source
+ {
+ Number = "4242424242424242",
+ ExpiryMonth = 12,
+ ExpiryYear = 2025,
+ Cvv = "123",
+ Type = "card"
+ },
+ Device = new Device
+ {
+ IpAddress = "192.168.1.1",
+ UserAgent = "Mozilla/5.0 Test"
+ },
+ Customer = new Customer
+ {
+ Email = "test@example.com",
+ CountryCode = CountryCode.US,
+ LanguageCode = "en"
+ }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post("agentic/enroll", _authorization, agenticEnrollRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => new EnrollACardResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.EnrollACard(agenticEnrollRequest, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Post("agentic/enroll", _authorization, agenticEnrollRequest,
+ CancellationToken.None, null), Times.Once);
+ }
+
+ [Fact]
+ private async Task EnrollShouldUseCorrectAuthorizationForEnroll()
+ {
+ var agenticEnrollRequest = new EnrollACardRequest
+ {
+ Source = new Source { Type = "card" },
+ Device = new Device(),
+ Customer = new Customer { Email = "test@example.com", CountryCode = CountryCode.US, LanguageCode = "en" }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post(It.IsAny(), It.IsAny(),
+ It.IsAny(), It.IsAny(), It.IsAny()))
+ .ReturnsAsync(() => new EnrollACardResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.EnrollACard(agenticEnrollRequest, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Post(It.IsAny(), _authorization,
+ It.IsAny(), It.IsAny(), It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentShouldCreatePurchaseIntent()
+ {
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
+ DeviceBrand = "apple",
+ DeviceType = "tablet"
+ },
+ CustomerPrompt = "I'm looking for running shoes in a size 10, for under $150.",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 100,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Purchase running shoes in size 10.",
+ ExpirationDate = DateTime.Parse("2026-08-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var expectedResponse = new PurchaseIntentResponse
+ {
+ Id = "pi_f3egwppx6rde3hg6itlqzp3h7e",
+ Scheme = "visa",
+ Status = PurchaseIntentStatusType.Created,
+ TokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ DeviceData = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
+ DeviceBrand = "apple",
+ DeviceType = "tablet"
+ },
+ CustomerPrompt = "Hey AI, I need Nike running shoes in size 10 under $130.00",
+ Mandates = new List
+ {
+ new MandateExtended
+ {
+ Id = "mandate_123",
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 100,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Purchase Nike Air Max 270 running shoes in size 10",
+ ExpirationDate = System.DateTime.Parse("2026-08-31T23:59:59.000Z")
+ }
+ },
+ Links = new Dictionary
+ {
+ { "self", new Link { Href = "https://api.example.com/agentic/purchase-intents/intent_789" } },
+ { "create-credentials", new Link { Href = "https://api.example.com/agentic/purchase-intents/intent_789/credentials" } },
+ { "update", new Link { Href = "https://api.example.com/agentic/purchase-intents/intent_789" } },
+ { "cancel", new Link { Href = "https://api.example.com/agentic/purchase-intents/intent_789/cancel" } }
+ }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post("agentic/purchase-intent", _authorization, createPurchaseIntentRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => expectedResponse);
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var response = await client.CreatePurchaseIntent(createPurchaseIntentRequest, CancellationToken.None);
+
+ response.ShouldNotBeNull();
+ response.Id.ShouldBe(expectedResponse.Id);
+ response.Scheme.ShouldBe(expectedResponse.Scheme);
+ response.Status.ShouldBe(expectedResponse.Status);
+ response.TokenId.ShouldBe(expectedResponse.TokenId);
+ response.CustomerPrompt.ShouldBe(expectedResponse.CustomerPrompt);
+ response.Links.ShouldNotBeNull();
+ response.Links["self"].Href.ShouldBe(expectedResponse.Links["self"].Href);
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentShouldThrowExceptionWhenCreatePurchaseIntentRequestIsNull()
+ {
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var exception = await Should.ThrowAsync(
+ async () => await client.CreatePurchaseIntent(null, CancellationToken.None));
+
+ exception.Message.ShouldContain("agenticPurchaseIntentCreateRequest");
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentShouldCallCorrectCreatePurchaseIntentEndpoint()
+ {
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_test_123",
+ Device = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 Test"
+ },
+ CustomerPrompt = "Test prompt",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ Description = "Test mandate"
+ }
+ }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post("agentic/purchase-intent", _authorization, createPurchaseIntentRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => new PurchaseIntentResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.CreatePurchaseIntent(createPurchaseIntentRequest, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Post("agentic/purchase-intent", _authorization, createPurchaseIntentRequest,
+ CancellationToken.None, null), Times.Once);
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentShouldUseCorrectAuthorizationForCreatePurchaseIntent()
+ {
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_test_123",
+ Device = new Device(),
+ CustomerPrompt = "Test prompt"
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post(It.IsAny(), It.IsAny(),
+ It.IsAny(), It.IsAny(), It.IsAny()))
+ .ReturnsAsync(() => new PurchaseIntentResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.CreatePurchaseIntent(createPurchaseIntentRequest, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Post(It.IsAny(), _authorization,
+ It.IsAny(), It.IsAny(), It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentCredentialsShouldCreatePurchaseIntentCredentials()
+ {
+ var purchaseIntentId = "pi_f3egwppx6rde3hg6itlqzp3h7e";
+ var createCredentialsRequest = new PurchaseIntentCredentialsCreateRequest
+ {
+ TransactionData = new List
+ {
+ new TransactionData
+ {
+ MerchantCountryCode = CountryCode.US,
+ MerchantName = "Nike Store",
+ MerchantCategoryCode = "5661",
+ MerchantUrl = "https://www.nike.com",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 12999,
+ CurrencyCode = Currency.USD
+ }
+ }
+ }
+ };
+
+ var expectedResponse = new PurchaseIntentResponse
+ {
+ Id = purchaseIntentId,
+ Scheme = "visa",
+ Status = PurchaseIntentStatusType.Created,
+ TokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ DeviceData = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
+ DeviceBrand = "apple",
+ DeviceType = "tablet"
+ },
+ CustomerPrompt = "Hey AI, I need Nike running shoes in size 10 under $130.00",
+ Mandates = new[]
+ {
+ new MandateExtended
+ {
+ Id = "mandate_123",
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 100,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Purchase Nike Air Max 270 running shoes in size 10",
+ ExpirationDate = System.DateTime.Parse("2026-08-31T23:59:59.000Z")
+ }
+ },
+ Links = new Dictionary
+ {
+ { "self", new Link { Href = "https://api.example.com/agentic/purchase-intents/pi_f3egwppx6rde3hg6itlqzp3h7e" } },
+ { "create-credentials", new Link { Href = "https://api.example.com/agentic/purchase-intents/pi_f3egwppx6rde3hg6itlqzp3h7e/credentials" } },
+ { "update", new Link { Href = "https://api.example.com/agentic/purchase-intents/pi_f3egwppx6rde3hg6itlqzp3h7e" } },
+ { "cancel", new Link { Href = "https://api.example.com/agentic/purchase-intents/pi_f3egwppx6rde3hg6itlqzp3h7e/cancel" } }
+ }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post("agentic/purchase-intent/pi_f3egwppx6rde3hg6itlqzp3h7e/credentials", _authorization, createCredentialsRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => expectedResponse);
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var response = await client.CreatePurchaseIntentCredentials(purchaseIntentId, createCredentialsRequest, CancellationToken.None);
+
+ response.ShouldNotBeNull();
+ response.Id.ShouldBe(expectedResponse.Id);
+ response.Scheme.ShouldBe(expectedResponse.Scheme);
+ response.Status.ShouldBe(expectedResponse.Status);
+ response.TokenId.ShouldBe(expectedResponse.TokenId);
+ response.CustomerPrompt.ShouldBe(expectedResponse.CustomerPrompt);
+ response.Links.ShouldNotBeNull();
+ response.Links["self"].Href.ShouldBe(expectedResponse.Links["self"].Href);
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentCredentialsShouldThrowExceptionWhenIdIsNull()
+ {
+ var createCredentialsRequest = new PurchaseIntentCredentialsCreateRequest
+ {
+ TransactionData = new[]
+ {
+ new TransactionData
+ {
+ MerchantName = "Test Store",
+ TransactionAmount = new TransactionAmount { Amount = 1000, CurrencyCode = Currency.USD }
+ }
+ }
+ };
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var exception = await Should.ThrowAsync(
+ async () => await client.CreatePurchaseIntentCredentials(null, createCredentialsRequest, CancellationToken.None));
+
+ exception.Message.ShouldContain("id");
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentCredentialsShouldThrowExceptionWhenRequestIsNull()
+ {
+ var purchaseIntentId = "pi_test_123";
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var exception = await Should.ThrowAsync(
+ async () => await client.CreatePurchaseIntentCredentials(purchaseIntentId, null, CancellationToken.None));
+
+ exception.Message.ShouldContain("agenticPurchaseIntentCredentialsCreateRequest");
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentCredentialsShouldCallCorrectEndpoint()
+ {
+ var purchaseIntentId = "pi_test_endpoint_123";
+ var createCredentialsRequest = new PurchaseIntentCredentialsCreateRequest
+ {
+ TransactionData = new[]
+ {
+ new TransactionData
+ {
+ MerchantName = "Test Merchant",
+ MerchantCountryCode = CountryCode.US,
+ MerchantCategoryCode = "5411",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 5000,
+ CurrencyCode = Currency.USD
+ }
+ }
+ }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post($"agentic/purchase-intent/{purchaseIntentId}/credentials", _authorization, createCredentialsRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => new PurchaseIntentResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.CreatePurchaseIntentCredentials(purchaseIntentId, createCredentialsRequest, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Post($"agentic/purchase-intent/{purchaseIntentId}/credentials", _authorization, createCredentialsRequest,
+ CancellationToken.None, null), Times.Once);
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentCredentialsShouldUseCorrectAuthorization()
+ {
+ var purchaseIntentId = "pi_auth_test_123";
+ var createCredentialsRequest = new PurchaseIntentCredentialsCreateRequest
+ {
+ TransactionData = new[]
+ {
+ new TransactionData
+ {
+ MerchantName = "Auth Test Store",
+ TransactionAmount = new TransactionAmount { Amount = 2500, CurrencyCode = Currency.EUR }
+ }
+ }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post(It.IsAny(), It.IsAny(),
+ It.IsAny(), It.IsAny(), It.IsAny()))
+ .ReturnsAsync(() => new PurchaseIntentResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.CreatePurchaseIntentCredentials(purchaseIntentId, createCredentialsRequest, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Post(It.IsAny(), _authorization,
+ It.IsAny(), It.IsAny(), It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ private async Task CreatePurchaseIntentCredentialsShouldHandleMultipleTransactionData()
+ {
+ var purchaseIntentId = "pi_multi_test_123";
+ var createCredentialsRequest = new PurchaseIntentCredentialsCreateRequest
+ {
+ TransactionData = new[]
+ {
+ new TransactionData
+ {
+ MerchantCountryCode = CountryCode.US,
+ MerchantName = "Electronics Store",
+ MerchantCategoryCode = "5732",
+ MerchantUrl = "https://electronics.example.com",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 79999,
+ CurrencyCode = Currency.USD
+ }
+ },
+ new TransactionData
+ {
+ MerchantCountryCode = CountryCode.GB,
+ MerchantName = "UK Fashion Store",
+ MerchantCategoryCode = "5651",
+ MerchantUrl = "https://fashion.co.uk",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 4500,
+ CurrencyCode = Currency.GBP
+ }
+ }
+ }
+ };
+
+ var expectedResponse = new PurchaseIntentResponse
+ {
+ Id = purchaseIntentId,
+ Status = PurchaseIntentStatusType.Created,
+ TokenId = "nt_multi_test_token"
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Post($"agentic/purchase-intent/{purchaseIntentId}/credentials", _authorization, createCredentialsRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => expectedResponse);
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var response = await client.CreatePurchaseIntentCredentials(purchaseIntentId, createCredentialsRequest, CancellationToken.None);
+
+ response.ShouldNotBeNull();
+ response.Id.ShouldBe(expectedResponse.Id);
+ response.Status.ShouldBe(expectedResponse.Status);
+ response.TokenId.ShouldBe(expectedResponse.TokenId);
+ }
+
+ [Fact]
+ private async Task UpdatePurchaseIntentShouldUpdatePurchaseIntent()
+ {
+ var purchaseIntentId = "pi_f3egwppx6rde3hg6itlqzp3h7e";
+ var updatePurchaseIntentRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Updated prompt: I'm looking for Nike running shoes in size 10.5, for under $200.",
+ Mandates = new List()
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 20000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Updated: Purchase Nike running shoes in size 10.5.",
+ ExpirationDate = System.DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var expectedResponse = new PurchaseIntentResponse
+ {
+ Id = purchaseIntentId,
+ Scheme = "visa",
+ Status = PurchaseIntentStatusType.Active,
+ TokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ DeviceData = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
+ DeviceBrand = "apple",
+ DeviceType = "tablet"
+ },
+ CustomerPrompt = "Updated prompt: I'm looking for Nike running shoes in size 10.5, for under $200.",
+ Mandates = new[]
+ {
+ new MandateExtended
+ {
+ Id = "mandate_updated_123",
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 20000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Updated: Purchase Nike running shoes in size 10.5.",
+ ExpirationDate = System.DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ },
+ Links = new Dictionary
+ {
+ { "self", new Link { Href = "https://api.example.com/agentic/purchase-intents/pi_f3egwppx6rde3hg6itlqzp3h7e" } },
+ { "create-credentials", new Link { Href = "https://api.example.com/agentic/purchase-intents/pi_f3egwppx6rde3hg6itlqzp3h7e/credentials" } },
+ { "update", new Link { Href = "https://api.example.com/agentic/purchase-intents/pi_f3egwppx6rde3hg6itlqzp3h7e" } },
+ { "cancel", new Link { Href = "https://api.example.com/agentic/purchase-intents/pi_f3egwppx6rde3hg6itlqzp3h7e/cancel" } }
+ }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Put($"agentic/purchase-intent/{purchaseIntentId}", _authorization, updatePurchaseIntentRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => expectedResponse);
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var response = await client.UpdatePurchaseIntent(purchaseIntentId, updatePurchaseIntentRequest, CancellationToken.None);
+
+ response.ShouldNotBeNull();
+ response.Id.ShouldBe(expectedResponse.Id);
+ response.Scheme.ShouldBe(expectedResponse.Scheme);
+ response.Status.ShouldBe(expectedResponse.Status);
+ response.TokenId.ShouldBe(expectedResponse.TokenId);
+ response.CustomerPrompt.ShouldBe(expectedResponse.CustomerPrompt);
+ response.Links.ShouldNotBeNull();
+ response.Links["self"].Href.ShouldBe(expectedResponse.Links["self"].Href);
+ }
+
+ [Fact]
+ private async Task UpdatePurchaseIntentShouldThrowExceptionWhenIdIsNull()
+ {
+ var updatePurchaseIntentRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Test prompt",
+ Mandates = new List()
+ {
+ new Mandate
+ {
+ Description = "Test mandate"
+ }
+ }
+ };
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var exception = await Should.ThrowAsync(
+ async () => await client.UpdatePurchaseIntent(null, updatePurchaseIntentRequest, CancellationToken.None));
+
+ exception.Message.ShouldContain("id");
+ }
+
+ [Fact]
+ private async Task UpdatePurchaseIntentShouldThrowExceptionWhenRequestIsNull()
+ {
+ var purchaseIntentId = "pi_test_123";
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var exception = await Should.ThrowAsync(
+ async () => await client.UpdatePurchaseIntent(purchaseIntentId, null, CancellationToken.None));
+
+ exception.Message.ShouldContain("agenticPurchaseIntentUpdateRequest");
+ }
+
+ [Fact]
+ private async Task UpdatePurchaseIntentShouldThrowExceptionWhenIdIsEmpty()
+ {
+ var updatePurchaseIntentRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Test prompt"
+ };
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var exception = await Should.ThrowAsync(
+ async () => await client.UpdatePurchaseIntent("", updatePurchaseIntentRequest, CancellationToken.None));
+
+ exception.Message.ShouldContain("id");
+ }
+
+ [Fact]
+ private async Task UpdatePurchaseIntentShouldCallCorrectEndpoint()
+ {
+ var purchaseIntentId = "pi_test_update_123";
+ var updatePurchaseIntentRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Test update prompt",
+ Mandates = new List()
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 15000,
+ CurrencyCode = Currency.EUR
+ },
+ Description = "Test update mandate"
+ }
+ }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Put($"agentic/purchase-intent/{purchaseIntentId}", _authorization, updatePurchaseIntentRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => new PurchaseIntentResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.UpdatePurchaseIntent(purchaseIntentId, updatePurchaseIntentRequest, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Put($"agentic/purchase-intent/{purchaseIntentId}", _authorization, updatePurchaseIntentRequest,
+ CancellationToken.None, null), Times.Once);
+ }
+
+ [Fact]
+ private async Task UpdatePurchaseIntentShouldUseCorrectAuthorization()
+ {
+ var purchaseIntentId = "pi_auth_test_123";
+ var updatePurchaseIntentRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Auth test prompt",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ Description = "Auth test mandate",
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 0,
+ CurrencyCode = null
+ },
+ ExpirationDate = new DateTime()
+ }
+ }
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Put(It.IsAny(), It.IsAny(),
+ It.IsAny(), It.IsAny(), It.IsAny()))
+ .ReturnsAsync(() => new PurchaseIntentResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.UpdatePurchaseIntent(purchaseIntentId, updatePurchaseIntentRequest, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Put(It.IsAny(), _authorization,
+ It.IsAny(), It.IsAny(), It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ private async Task UpdatePurchaseIntentShouldHandlePartialUpdates()
+ {
+ var purchaseIntentId = "pi_partial_update_123";
+ var updatePurchaseIntentRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Only updating the customer prompt"
+ // Mandates is null - partial update
+ };
+
+ var expectedResponse = new PurchaseIntentResponse
+ {
+ Id = purchaseIntentId,
+ Status = PurchaseIntentStatusType.Created,
+ CustomerPrompt = "Only updating the customer prompt",
+ TokenId = "nt_partial_update_token"
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Put($"agentic/purchase-intent/{purchaseIntentId}", _authorization, updatePurchaseIntentRequest,
+ CancellationToken.None, null))
+ .ReturnsAsync(() => expectedResponse);
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var response = await client.UpdatePurchaseIntent(purchaseIntentId, updatePurchaseIntentRequest, CancellationToken.None);
+
+ response.ShouldNotBeNull();
+ response.Id.ShouldBe(expectedResponse.Id);
+ response.Status.ShouldBe(expectedResponse.Status);
+ response.CustomerPrompt.ShouldBe(expectedResponse.CustomerPrompt);
+ response.TokenId.ShouldBe(expectedResponse.TokenId);
+ }
+
+ [Fact]
+ private async Task DeletePurchaseIntentShouldDeletePurchaseIntent()
+ {
+ var purchaseIntentId = "pi_f3egwppx6rde3hg6itlqzp3h7e";
+
+ var expectedResponse = new EmptyResponse
+ {
+ HttpStatusCode = 200
+ };
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Delete($"agentic/purchase-intent/{purchaseIntentId}", _authorization,
+ CancellationToken.None))
+ .ReturnsAsync(() => expectedResponse);
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var response = await client.DeletePurchaseIntent(purchaseIntentId, CancellationToken.None);
+
+ response.ShouldNotBeNull();
+ response.HttpStatusCode.ShouldBe(200);
+ }
+
+ [Fact]
+ private async Task DeletePurchaseIntentShouldThrowExceptionWhenIdIsNull()
+ {
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var exception = await Should.ThrowAsync(
+ async () => await client.DeletePurchaseIntent(null, CancellationToken.None));
+
+ exception.Message.ShouldContain("id");
+ }
+
+ [Fact]
+ private async Task DeletePurchaseIntentShouldThrowExceptionWhenIdIsEmpty()
+ {
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var exception = await Should.ThrowAsync(
+ async () => await client.DeletePurchaseIntent("", CancellationToken.None));
+
+ exception.Message.ShouldContain("id");
+ }
+
+ [Fact]
+ private async Task DeletePurchaseIntentShouldCallCorrectEndpoint()
+ {
+ var purchaseIntentId = "pi_test_delete_123";
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Delete($"agentic/purchase-intent/{purchaseIntentId}", _authorization,
+ CancellationToken.None))
+ .ReturnsAsync(() => new EmptyResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.DeletePurchaseIntent(purchaseIntentId, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Delete($"agentic/purchase-intent/{purchaseIntentId}", _authorization,
+ CancellationToken.None), Times.Once);
+ }
+
+ [Fact]
+ private async Task DeletePurchaseIntentShouldUseCorrectAuthorization()
+ {
+ var purchaseIntentId = "pi_auth_test_123";
+
+ _apiClient.Setup(apiClient =>
+ apiClient.Delete(It.IsAny(), It.IsAny(),
+ It.IsAny()))
+ .ReturnsAsync(() => new EmptyResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ await client.DeletePurchaseIntent(purchaseIntentId, CancellationToken.None);
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Delete(It.IsAny(), _authorization,
+ It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ private async Task DeletePurchaseIntentShouldHandleDifferentPurchaseIntentIdFormats()
+ {
+ var testIds = new[]
+ {
+ "pi_short123",
+ "pi_f3egwppx6rde3hg6itlqzp3h7e",
+ "pi_very_long_purchase_intent_id_with_underscores_123456789"
+ };
+
+ foreach (var purchaseIntentId in testIds)
+ {
+ _apiClient.Setup(apiClient =>
+ apiClient.Delete($"agentic/purchase-intent/{purchaseIntentId}", _authorization,
+ CancellationToken.None))
+ .ReturnsAsync(() => new EmptyResponse());
+
+ IAgenticClient client = new AgenticClient(_apiClient.Object, _configuration.Object);
+
+ var response = await client.DeletePurchaseIntent(purchaseIntentId, CancellationToken.None);
+
+ response.ShouldNotBeNull();
+
+ _apiClient.Verify(apiClient =>
+ apiClient.Delete($"agentic/purchase-intent/{purchaseIntentId}", _authorization,
+ CancellationToken.None), Times.Once);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/CheckoutSdkTest/AgenticCommerce/AgenticIntegrationTest.cs b/test/CheckoutSdkTest/AgenticCommerce/AgenticIntegrationTest.cs
new file mode 100644
index 00000000..aca8ec43
--- /dev/null
+++ b/test/CheckoutSdkTest/AgenticCommerce/AgenticIntegrationTest.cs
@@ -0,0 +1,928 @@
+using System;
+using System.Net;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+using Shouldly;
+using Xunit;
+
+using Checkout.AgenticCommerce.Common;
+using Checkout.AgenticCommerce.Requests;
+using Checkout.Common;
+
+namespace Checkout.AgenticCommerce
+{
+ public class AgenticIntegrationTest : SandboxTestFixture
+ {
+ public AgenticIntegrationTest() : base(PlatformType.DefaultOAuth)
+ {
+ }
+
+ [Fact]
+ private async Task EnrollShouldEnroll()
+ {
+ var agenticEnrollRequest = new EnrollACardRequest
+ {
+ Source = new Source
+ {
+ Number = "4543474002249996",
+ ExpiryMonth = 12,
+ ExpiryYear = 2025,
+ Cvv = "100",
+ Type = "card"
+ },
+ Device = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
+ DeviceBrand = "Chrome",
+ DeviceType = "desktop"
+ },
+ Customer = new Customer
+ {
+ Email = GenerateRandomEmail(),
+ CountryCode = CountryCode.US,
+ LanguageCode = "en"
+ }
+ };
+
+ var response = await DefaultApi.AgenticClient().EnrollACard(agenticEnrollRequest);
+
+ response.ShouldNotBeNull();
+ response.Status.ShouldBe("enrolled");
+ response.CreatedAt.ShouldNotBe(default(DateTime));
+ }
+
+ [Fact]
+ private async Task EnrollShouldEnrollWithMinimalData()
+ {
+ var agenticEnrollRequest = new EnrollACardRequest
+ {
+ Source = new Source
+ {
+ Number = "4543474002249996",
+ ExpiryMonth = 6,
+ ExpiryYear = 2026,
+ Type = "card"
+ },
+ Device = new Device
+ {
+ IpAddress = "10.0.0.1",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
+ },
+ Customer = new Customer
+ {
+ Email = GenerateRandomEmail(),
+ CountryCode = CountryCode.US,
+ LanguageCode = "en"
+ }
+ };
+
+ var response = await DefaultApi.AgenticClient().EnrollACard(agenticEnrollRequest);
+
+ response.ShouldNotBeNull();
+ response.Status.ShouldBe("enrolled");
+ }
+
+ [Fact]
+ private async Task EnrollShouldHandleInternationalCustomers()
+ {
+ var internationalRequest = new EnrollACardRequest
+ {
+ Source = new Source
+ {
+ Number = "4543474002249996",
+ ExpiryMonth = 3,
+ ExpiryYear = 2029,
+ Cvv = "100",
+ Type = "card"
+ },
+ Device = new Device
+ {
+ IpAddress = "80.112.12.34", // European IP
+ UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
+ DeviceBrand = "Safari",
+ DeviceType = "mobile"
+ },
+ Customer = new Customer
+ {
+ Email = GenerateRandomEmail(),
+ CountryCode = CountryCode.ES,
+ LanguageCode = "es"
+ }
+ };
+
+ var response = await DefaultApi.AgenticClient().EnrollACard(internationalRequest);
+
+ response.ShouldNotBeNull();
+ response.Status.ShouldBe("enrolled");
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task CreatePurchaseIntentShouldCreatePurchaseIntent()
+ {
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
+ DeviceBrand = "apple",
+ DeviceType = "tablet"
+ },
+ CustomerPrompt = "I'm looking for running shoes in a size 10, for under $150.",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 100,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Purchase running shoes in size 10.",
+ ExpirationDate = DateTime.Parse("2026-08-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var response = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+
+ response.ShouldNotBeNull();
+ response.Id.ShouldNotBeNullOrEmpty();
+ response.Status.ShouldNotBeNull();
+ response.TokenId.ShouldNotBeNullOrEmpty();
+ response.CustomerPrompt.ShouldNotBeNullOrEmpty();
+
+ // Validate that purchase intent ID follows expected pattern
+ response.Id.ShouldStartWith("pi_");
+
+ // Validate status is one of expected values
+ response.Status.ShouldBe(PurchaseIntentStatusType.Active);
+
+ // Validate links are present
+ response.Links.ShouldNotBeNull();
+ response.Links["self"].Href.ShouldNotBeNullOrEmpty();
+ response.Links["create-credentials"].Href.ShouldNotBeNullOrEmpty();
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task CreatePurchaseIntentShouldCreatePurchaseIntentWithMinimalData()
+ {
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "10.0.0.1"
+ },
+ CustomerPrompt = "Basic purchase request"
+ };
+
+ var response = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+
+ response.ShouldNotBeNull();
+ response.Id.ShouldNotBeNullOrEmpty();
+ response.Status.ShouldBe(PurchaseIntentStatusType.Active);
+ response.TokenId.ShouldNotBeNullOrEmpty();
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task CreatePurchaseIntentShouldHandleDifferentMandateTypes()
+ {
+ // Test with single mandate
+ var singleMandateRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "203.0.113.195",
+ UserAgent = "Test Agent",
+ DeviceBrand = "chrome",
+ DeviceType = "desktop"
+ },
+ CustomerPrompt = "Looking for electronics under $500",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 500,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Electronics purchase",
+ ExpirationDate = DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var singleResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(singleMandateRequest);
+ singleResponse.ShouldNotBeNull();
+ singleResponse.Status.ShouldBe(PurchaseIntentStatusType.Active);
+ singleResponse.Mandates.Count.ShouldBe(1);
+
+ // Test with multiple mandates
+ var multipleMandateRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "198.51.100.42"
+ },
+ CustomerPrompt = "Shopping for clothing and accessories",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 200,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Clothing purchase",
+ ExpirationDate = DateTime.Parse("2026-06-30T23:59:59.000Z")
+ },
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 100,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Accessories purchase",
+ ExpirationDate = DateTime.Parse("2026-09-30T23:59:59.000Z")
+ }
+ }
+ };
+
+ var multipleResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(multipleMandateRequest);
+ multipleResponse.ShouldNotBeNull();
+ multipleResponse.Status.ShouldBe(PurchaseIntentStatusType.Active);
+ multipleResponse.Mandates.Count.ShouldBe(2);
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task CreatePurchaseIntentShouldHandleInternationalCurrencies()
+ {
+ var internationalRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "80.112.12.34", // European IP
+ UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
+ DeviceBrand = "safari",
+ DeviceType = "mobile"
+ },
+ CustomerPrompt = "Buscando zapatos deportivos en talla 42",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 150,
+ CurrencyCode = Currency.EUR
+ },
+ Description = "Compra de zapatos deportivos",
+ ExpirationDate = DateTime.Parse("2026-08-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var response = await DefaultApi.AgenticClient().CreatePurchaseIntent(internationalRequest);
+
+ response.ShouldNotBeNull();
+ response.Status.ShouldBe(PurchaseIntentStatusType.Active);
+ response.Id.ShouldStartWith("pi_");
+ response.Mandates.ShouldNotBeNull();
+ response.Mandates[0].PurchaseThreshold.CurrencyCode.ShouldBe(Currency.EUR);
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task CreatePurchaseIntentCredentialsShouldCreateCredentials()
+ {
+ // First create a purchase intent to get an ID
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
+ },
+ CustomerPrompt = "I need running shoes in size 10, under $150.",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 15000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Purchase running shoes for credentials test.",
+ ExpirationDate = DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+ purchaseIntentResponse.ShouldNotBeNull();
+ purchaseIntentResponse.Id.ShouldNotBeNullOrEmpty();
+
+ // Now create credentials for this purchase intent
+ var createCredentialsRequest = new PurchaseIntentCredentialsCreateRequest
+ {
+ TransactionData = new[]
+ {
+ new TransactionData
+ {
+ MerchantCountryCode = CountryCode.US,
+ MerchantName = "Nike Store",
+ MerchantCategoryCode = "5661",
+ MerchantUrl = "https://www.nike.com",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 12999,
+ CurrencyCode = Currency.USD
+ }
+ }
+ }
+ };
+
+ var credentialsResponse = await DefaultApi.AgenticClient().CreatePurchaseIntentCredentials(
+ purchaseIntentResponse.Id, createCredentialsRequest);
+
+ credentialsResponse.ShouldNotBeNull();
+ credentialsResponse.Id.ShouldBe(purchaseIntentResponse.Id);
+ credentialsResponse.Status.ShouldNotBeNull();
+ credentialsResponse.TokenId.ShouldNotBeNullOrEmpty();
+
+ // Validate that the purchase intent ID follows expected pattern
+ credentialsResponse.Id.ShouldStartWith("pi_");
+
+ // Validate links are present and updated
+ credentialsResponse.Links.ShouldNotBeNull();
+ credentialsResponse.Links["self"].Href.ShouldNotBeNullOrEmpty();
+ credentialsResponse.Links["create-credentials"].Href.ShouldNotBeNullOrEmpty();
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task CreatePurchaseIntentCredentialsShouldHandleMultipleTransactionData()
+ {
+ // First create a purchase intent
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "203.0.113.195",
+ UserAgent = "Test Agent Multi Transaction"
+ },
+ CustomerPrompt = "I need multiple items: electronics and clothing.",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 100000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Purchase multiple items across different categories.",
+ ExpirationDate = DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+ purchaseIntentResponse.ShouldNotBeNull();
+
+ // Create credentials with multiple transaction data
+ var createCredentialsRequest = new PurchaseIntentCredentialsCreateRequest
+ {
+ TransactionData = new[]
+ {
+ new TransactionData
+ {
+ MerchantCountryCode = CountryCode.US,
+ MerchantName = "Best Electronics",
+ MerchantCategoryCode = "5732",
+ MerchantUrl = "https://bestelectronics.com",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 79999,
+ CurrencyCode = Currency.USD
+ }
+ },
+ new TransactionData
+ {
+ MerchantCountryCode = CountryCode.US,
+ MerchantName = "Fashion Central",
+ MerchantCategoryCode = "5651",
+ MerchantUrl = "https://fashioncentral.com",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 15999,
+ CurrencyCode = Currency.USD
+ }
+ }
+ }
+ };
+
+ var credentialsResponse = await DefaultApi.AgenticClient().CreatePurchaseIntentCredentials(
+ purchaseIntentResponse.Id, createCredentialsRequest);
+
+ credentialsResponse.ShouldNotBeNull();
+ credentialsResponse.Id.ShouldBe(purchaseIntentResponse.Id);
+ credentialsResponse.Status.ShouldNotBeNull();
+ credentialsResponse.TokenId.ShouldNotBeNullOrEmpty();
+
+ // Validate response structure
+ credentialsResponse.Id.ShouldStartWith("pi_");
+ credentialsResponse.Links.ShouldNotBeNull();
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task CreatePurchaseIntentCredentialsShouldHandleInternationalTransactions()
+ {
+ // Create purchase intent
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "80.112.12.34", // European IP
+ UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
+ },
+ CustomerPrompt = "Looking for luxury items in different currencies.",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 200000,
+ CurrencyCode = Currency.EUR
+ },
+ Description = "International luxury purchases.",
+ ExpirationDate = DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+ purchaseIntentResponse.ShouldNotBeNull();
+
+ // Create credentials with international transaction data
+ var createCredentialsRequest = new PurchaseIntentCredentialsCreateRequest
+ {
+ TransactionData = new[]
+ {
+ new TransactionData
+ {
+ MerchantCountryCode = CountryCode.FR,
+ MerchantName = "Luxury Paris Boutique",
+ MerchantCategoryCode = "5944",
+ MerchantUrl = "https://luxuryparis.fr",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 89999,
+ CurrencyCode = Currency.EUR
+ }
+ },
+ new TransactionData
+ {
+ MerchantCountryCode = CountryCode.GB,
+ MerchantName = "London Fashion House",
+ MerchantCategoryCode = "5651",
+ MerchantUrl = "https://londonfashion.co.uk",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 45000,
+ CurrencyCode = Currency.GBP
+ }
+ }
+ }
+ };
+
+ var credentialsResponse = await DefaultApi.AgenticClient().CreatePurchaseIntentCredentials(
+ purchaseIntentResponse.Id, createCredentialsRequest);
+
+ credentialsResponse.ShouldNotBeNull();
+ credentialsResponse.Id.ShouldBe(purchaseIntentResponse.Id);
+ credentialsResponse.Status.ShouldNotBeNull();
+ credentialsResponse.TokenId.ShouldNotBeNullOrEmpty();
+
+ // Validate international handling
+ credentialsResponse.Id.ShouldStartWith("pi_");
+ credentialsResponse.Links.ShouldNotBeNull();
+ credentialsResponse.Links["self"].Href.ShouldContain(purchaseIntentResponse.Id);
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task CreatePurchaseIntentCredentialsShouldHandleMinimalTransactionData()
+ {
+ // Create purchase intent first
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "10.0.0.1"
+ },
+ CustomerPrompt = "Basic purchase for minimal test"
+ };
+
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+ purchaseIntentResponse.ShouldNotBeNull();
+
+ // Create credentials with minimal transaction data
+ var createCredentialsRequest = new PurchaseIntentCredentialsCreateRequest
+ {
+ TransactionData = new[]
+ {
+ new TransactionData
+ {
+ MerchantName = "Basic Store",
+ TransactionAmount = new TransactionAmount
+ {
+ Amount = 1000,
+ CurrencyCode = Currency.USD
+ }
+ }
+ }
+ };
+
+ var credentialsResponse = await DefaultApi.AgenticClient().CreatePurchaseIntentCredentials(
+ purchaseIntentResponse.Id, createCredentialsRequest);
+
+ credentialsResponse.ShouldNotBeNull();
+ credentialsResponse.Id.ShouldBe(purchaseIntentResponse.Id);
+ credentialsResponse.Status.ShouldNotBeNull();
+ credentialsResponse.TokenId.ShouldNotBeNullOrEmpty();
+ credentialsResponse.Id.ShouldStartWith("pi_");
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task UpdatePurchaseIntentShouldUpdatePurchaseIntent()
+ {
+ // First create a purchase intent to update
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
+ DeviceBrand = "apple",
+ DeviceType = "tablet"
+ },
+ CustomerPrompt = "I'm looking for running shoes in a size 10, for under $150.",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 15000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Purchase running shoes in size 10.",
+ ExpirationDate = System.DateTime.Parse("2026-08-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+
+ purchaseIntentResponse.ShouldNotBeNull();
+ purchaseIntentResponse.Id.ShouldNotBeNullOrEmpty();
+
+ // Now update the purchase intent
+ var updatePurchaseIntentRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Updated: I'm looking for Nike running shoes in size 10.5, for under $200.",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 20000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Updated: Purchase Nike running shoes in size 10.5.",
+ ExpirationDate = System.DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var updateResponse = await DefaultApi.AgenticClient().UpdatePurchaseIntent(purchaseIntentResponse.Id, updatePurchaseIntentRequest);
+
+ updateResponse.ShouldNotBeNull();
+ updateResponse.Id.ShouldBe(purchaseIntentResponse.Id);
+ updateResponse.CustomerPrompt.ShouldBe(updatePurchaseIntentRequest.CustomerPrompt);
+ updateResponse.Status.ShouldNotBeNull();
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task UpdatePurchaseIntentShouldHandleNonExistentPurchaseIntent()
+ {
+ var nonExistentId = "pi_nonexistent_123456";
+ var updatePurchaseIntentRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "This should fail"
+ };
+
+ var exception = await Should.ThrowAsync(
+ async () => await DefaultApi.AgenticClient().UpdatePurchaseIntent(nonExistentId, updatePurchaseIntentRequest));
+
+ exception.HttpStatusCode.ShouldBeOneOf(HttpStatusCode.NotFound, HttpStatusCode.BadRequest);
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task UpdatePurchaseIntentShouldValidateInputParameters()
+ {
+ // Test with null ID
+ var updateRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Valid prompt"
+ };
+
+ var exception = await Should.ThrowAsync(
+ async () => await DefaultApi.AgenticClient().UpdatePurchaseIntent(null, updateRequest));
+
+ exception.Message.ShouldContain("id");
+
+ // Test with null request
+ var validId = "pi_valid_123";
+ var nullRequestException = await Should.ThrowAsync(
+ async () => await DefaultApi.AgenticClient().UpdatePurchaseIntent(validId, null));
+
+ nullRequestException.Message.ShouldContain("agenticPurchaseIntentUpdateRequest");
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task UpdatePurchaseIntentShouldHandlePartialUpdates()
+ {
+ // First create a purchase intent
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 Test Browser"
+ },
+ CustomerPrompt = "Original prompt",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ Description = "Original mandate"
+ }
+ }
+ };
+
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+
+ // Update only the customer prompt (partial update)
+ var partialUpdateRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Updated prompt only"
+ // Mandates is null - testing partial update
+ };
+
+ var updateResponse = await DefaultApi.AgenticClient().UpdatePurchaseIntent(
+ purchaseIntentResponse.Id, partialUpdateRequest);
+
+ updateResponse.ShouldNotBeNull();
+ updateResponse.Id.ShouldBe(purchaseIntentResponse.Id);
+ updateResponse.CustomerPrompt.ShouldBe(partialUpdateRequest.CustomerPrompt);
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task UpdatePurchaseIntentShouldHandleDifferentPurchaseIntentStates()
+ {
+ // Create purchase intent
+ var createRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 State Test"
+ },
+ CustomerPrompt = "Test different states",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 10000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "State test mandate"
+ }
+ }
+ };
+
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createRequest);
+
+ // Try to update the purchase intent regardless of its current state
+ var updateRequest = new PurchaseIntentUpdateRequest
+ {
+ CustomerPrompt = "Updated for state testing",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 12000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Updated state test mandate"
+ }
+ }
+ };
+
+ // This should work regardless of the purchase intent's current state
+ var updateResponse = await DefaultApi.AgenticClient().UpdatePurchaseIntent(
+ purchaseIntentResponse.Id, updateRequest);
+
+ updateResponse.ShouldNotBeNull();
+ updateResponse.Id.ShouldBe(purchaseIntentResponse.Id);
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task DeletePurchaseIntentShouldDeletePurchaseIntent()
+ {
+ // First create a purchase intent to delete
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "192.168.1.100",
+ UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
+ },
+ CustomerPrompt = "I need running shoes for deletion test.",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 10000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Purchase intent for deletion test.",
+ ExpirationDate = DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+ purchaseIntentResponse.ShouldNotBeNull();
+ purchaseIntentResponse.Id.ShouldNotBeNullOrEmpty();
+ purchaseIntentResponse.Id.ShouldStartWith("pi_");
+
+ // Now delete the purchase intent
+ var deleteResponse = await DefaultApi.AgenticClient().DeletePurchaseIntent(purchaseIntentResponse.Id);
+
+ deleteResponse.ShouldNotBeNull();
+
+ // Validate successful deletion (typically 200 or 204)
+ deleteResponse.HttpStatusCode.ShouldBeOneOf(200, 204);
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task DeletePurchaseIntentShouldHandleNonExistentPurchaseIntent()
+ {
+ var nonExistentId = "pi_non_existent_123456789";
+
+ // Attempt to delete non-existent purchase intent should handle gracefully
+ var exception = await Should.ThrowAsync(
+ async () => await DefaultApi.AgenticClient().DeletePurchaseIntent(nonExistentId));
+
+ // Should return 404 Not Found for non-existent purchase intent
+ exception.HttpStatusCode.ShouldBe(HttpStatusCode.NotFound);
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task DeletePurchaseIntentShouldHandleAlreadyDeletedPurchaseIntent()
+ {
+ // First create a purchase intent
+ var createPurchaseIntentRequest = new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "203.0.113.195",
+ UserAgent = "Test Agent Double Delete"
+ },
+ CustomerPrompt = "Purchase intent for double deletion test.",
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 5000,
+ CurrencyCode = Currency.USD
+ },
+ Description = "Double deletion test mandate.",
+ ExpirationDate = DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ }
+ };
+
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createPurchaseIntentRequest);
+ purchaseIntentResponse.ShouldNotBeNull();
+
+ // Delete it once
+ var firstDeleteResponse = await DefaultApi.AgenticClient().DeletePurchaseIntent(purchaseIntentResponse.Id);
+ firstDeleteResponse.ShouldNotBeNull();
+
+ // Try to delete it again - should handle gracefully (404 or other appropriate response)
+ var exception = await Should.ThrowAsync(
+ async () => await DefaultApi.AgenticClient().DeletePurchaseIntent(purchaseIntentResponse.Id));
+
+ // Should return 404 Not Found for already deleted purchase intent
+ exception.HttpStatusCode.ShouldBe(HttpStatusCode.NotFound);
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task DeletePurchaseIntentShouldHandleDifferentPurchaseIntentStates()
+ {
+ // Test deleting purchase intents in different states
+ var testCases = new[]
+ {
+ new { Description = "Basic purchase intent", CustomerPrompt = "Basic deletion test" },
+ new { Description = "Complex purchase intent", CustomerPrompt = "Complex purchase intent with multiple mandates for deletion test" }
+ };
+
+ foreach (var createRequest in testCases.Select(testCase => new PurchaseIntentCreateRequest
+ {
+ NetworkTokenId = "nt_e7fjr77crbgmlhpjvuq3bj6jba",
+ Device = new Device
+ {
+ IpAddress = "10.0.0.1",
+ UserAgent = "Test Agent States"
+ },
+ CustomerPrompt = testCase.CustomerPrompt,
+ Mandates = new List
+ {
+ new Mandate
+ {
+ PurchaseThreshold = new PurchaseThreshold
+ {
+ Amount = 7500,
+ CurrencyCode = Currency.USD
+ },
+ Description = $"Mandate for {testCase.Description}",
+ ExpirationDate = DateTime.Parse("2026-12-31T23:59:59.000Z")
+ }
+ }
+ }))
+ {
+ var purchaseIntentResponse = await DefaultApi.AgenticClient().CreatePurchaseIntent(createRequest);
+ purchaseIntentResponse.ShouldNotBeNull();
+ purchaseIntentResponse.Id.ShouldStartWith("pi_");
+
+ // Delete the purchase intent
+ var deleteResponse = await DefaultApi.AgenticClient().DeletePurchaseIntent(purchaseIntentResponse.Id);
+
+ deleteResponse.ShouldNotBeNull();
+ deleteResponse.HttpStatusCode.ShouldBeOneOf(200, 204);
+ }
+ }
+
+ [Fact(Skip = "This test is unsupported currently, not ready to test in the sandbox")]
+ private async Task DeletePurchaseIntentShouldHandleInvalidIdFormat()
+ {
+ var invalidIds = new[]
+ {
+ "invalid_id_format",
+ "pi_",
+ "not_a_purchase_intent_id",
+ "123456789"
+ };
+
+ foreach (var invalidId in invalidIds)
+ {
+ var exception = await Should.ThrowAsync(
+ async () => await DefaultApi.AgenticClient().DeletePurchaseIntent(invalidId));
+
+ // Should return 400 Bad Request or 404 Not Found for invalid ID format
+ exception.HttpStatusCode.ShouldBeOneOf(HttpStatusCode.BadRequest, HttpStatusCode.NotFound);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/CheckoutSdkTest/Instruments/InstrumentsIntegrationTest.cs b/test/CheckoutSdkTest/Instruments/InstrumentsIntegrationTest.cs
index abdc840c..61505b42 100644
--- a/test/CheckoutSdkTest/Instruments/InstrumentsIntegrationTest.cs
+++ b/test/CheckoutSdkTest/Instruments/InstrumentsIntegrationTest.cs
@@ -149,7 +149,6 @@ private async Task ShouldUpdateCardInstrument()
cardResponse.Fingerprint.ShouldNotBeNull();
cardResponse.ExpiryMonth.ShouldBe(12);
cardResponse.ExpiryYear.ShouldBe(2030);
- cardResponse.Customer.Default.ShouldBeTrue();
cardResponse.AccountHolder.FirstName.ShouldBe("John");
cardResponse.AccountHolder.LastName.ShouldBe("Doe");
cardResponse.CardType.ShouldNotBeNull();
diff --git a/test/CheckoutSdkTest/SandboxTestFixture.cs b/test/CheckoutSdkTest/SandboxTestFixture.cs
index fcecaf6a..02bed1e3 100644
--- a/test/CheckoutSdkTest/SandboxTestFixture.cs
+++ b/test/CheckoutSdkTest/SandboxTestFixture.cs
@@ -60,7 +60,7 @@ protected SandboxTestFixture(PlatformType platformType)
OAuthScope.Accounts, OAuthScope.SessionsApp, OAuthScope.SessionsBrowser,
OAuthScope.Vault, OAuthScope.PayoutsBankDetails, OAuthScope.TransfersCreate,
OAuthScope.TransfersView, OAuthScope.BalancesView, OAuthScope.VaultCardMetadata,
- OAuthScope.FinancialActions, OAuthScope.Forward)
+ OAuthScope.FinancialActions, OAuthScope.Forward, OAuthScope.AgenticEnroll)
.Environment(Environment.Sandbox)
//.HttpClientFactory(new CustomClientFactory("3.0"))
//.EnvironmentSubdomain(System.Environment.GetEnvironmentVariable("CHECKOUT_MERCHANT_SUBDOMAIN"))