From 270716a8294c6f0a8d8a59c532c61af6a447354e Mon Sep 17 00:00:00 2001 From: Tetiana Holovina Date: Tue, 18 Aug 2026 21:34:24 +0300 Subject: [PATCH 1/3] Add Global Profile API support Co-Authored-By: Claude --- CHANGES.MD | 9 +- README.md | 36 ++++- Sift/Core/Client.cs | 10 ++ Sift/Request/GlobalProfileRequest.cs | 94 +++++++++++++ Sift/Response/GlobalProfileResponse.cs | 179 +++++++++++++++++++++++++ Sift/Sift.csproj | 4 +- Test/Test.cs | 172 ++++++++++++++++++++++++ 7 files changed, 500 insertions(+), 4 deletions(-) create mode 100644 Sift/Request/GlobalProfileRequest.cs create mode 100644 Sift/Response/GlobalProfileResponse.cs diff --git a/CHANGES.MD b/CHANGES.MD index c5ea4eb..e9d63d0 100644 --- a/CHANGES.MD +++ b/CHANGES.MD @@ -1,4 +1,11 @@ -# CHANGES +# CHANGES + +## 1.8.0 (2026-08-18) + +### Added +- **Global Profile API** support: `GlobalProfileRequest`/`GlobalProfileResponse` for + `GET /v3/accounts/{accountId}/global_profile/users/{userId}` and + `GlobalProfileLookupRequest` for `POST /v3/accounts/{accountId}/global_profile/lookup` ## 1.7.0 (2025-12-03) diff --git a/README.md b/README.md index f5e2940..132f4da 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The official Sift .NET client, supporting .NET Standard 2.0+ -## Latest Release (v1.7.0) +## Latest Release (v1.8.0) See [CHANGES.MD](CHANGES.MD) for full release history. @@ -1052,6 +1052,40 @@ var booking = new Booking // Handle InnerException } +### Global Profile + + // Get Global Profile for a user + try + { + GlobalProfileResponse response = sift.SendAsync(new GlobalProfileRequest + { + AccountId = "ACCOUNT_ID", + UserId = "gary", + GlobalOnly = false, + IncludeOwnData = true + }).Result; + } + catch (AggregateException ae) + { + // Handle InnerException + } + + // Look up a Global Profile by email and/or phone. + // At least one of Email or Phone is required; omitting both throws a MissingFieldException. + try + { + GlobalProfileResponse response = sift.SendAsync(new GlobalProfileLookupRequest + { + AccountId = "ACCOUNT_ID", + Email = "gary@example.com", + Phone = "+15555550100" + }).Result; + } + catch (AggregateException ae) + { + // Handle InnerException + } + ### Workflows // Workflow Status diff --git a/Sift/Core/Client.cs b/Sift/Core/Client.cs index 6049e17..5fa6d04 100644 --- a/Sift/Core/Client.cs +++ b/Sift/Core/Client.cs @@ -120,6 +120,16 @@ public async Task SendAsync(GetMerchantDetailsReques return await SendAsync(getMerchantRequest); } + public async Task SendAsync(GlobalProfileRequest globalProfileRequest) + { + return await SendAsync(globalProfileRequest); + } + + public async Task SendAsync(GlobalProfileLookupRequest globalProfileLookupRequest) + { + return await SendAsync(globalProfileLookupRequest); + } + async Task SendAsync(SiftRequest siftRequest) where T : SiftResponse { siftRequest.ApiKey = this.apiKey; diff --git a/Sift/Request/GlobalProfileRequest.cs b/Sift/Request/GlobalProfileRequest.cs new file mode 100644 index 0000000..4ae5ca6 --- /dev/null +++ b/Sift/Request/GlobalProfileRequest.cs @@ -0,0 +1,94 @@ +using Newtonsoft.Json; +using System; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; + +namespace Sift +{ + public class GlobalProfileRequest : SiftRequest + { + static readonly String GlobalProfileUrl = @"https://api.sift.com/v3/accounts/{0}/global_profile/users/{1}"; + + public string AccountId { get; set; } + public string UserId { get; set; } + public bool? GlobalOnly { get; set; } + public bool? IncludeOwnData { get; set; } + + public override HttpRequestMessage Request + { + get + { + var request = new HttpRequestMessage(HttpMethod.Get, Url); + request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.Default.GetBytes(ApiKey))); + return request; + } + } + + protected override Uri Url + { + get + { + var url = new Uri(String.Format(GlobalProfileUrl, + Uri.EscapeDataString(AccountId), + Uri.EscapeDataString(UserId))); + + if (GlobalOnly.HasValue) + { + url = url.AddQuery("global_only", GlobalOnly.Value.ToString().ToLowerInvariant()); + } + + if (IncludeOwnData.HasValue) + { + url = url.AddQuery("include_own_data", IncludeOwnData.Value.ToString().ToLowerInvariant()); + } + + return url; + } + } + } + + public class GlobalProfileLookupRequest : SiftRequest + { + static readonly String GlobalProfileLookupUrl = @"https://api.sift.com/v3/accounts/{0}/global_profile/lookup"; + + [JsonIgnore] + public string AccountId { get; set; } + + [JsonIgnore] + public override string ApiKey { get; set; } + + [JsonProperty("email", NullValueHandling = NullValueHandling.Ignore)] + public string Email { get; set; } + + [JsonProperty("phone", NullValueHandling = NullValueHandling.Ignore)] + public string Phone { get; set; } + + [JsonIgnore] + public override HttpRequestMessage Request + { + get + { + if (String.IsNullOrEmpty(Email) && String.IsNullOrEmpty(Phone)) + { + throw new MissingFieldException("At least one of Email or Phone is required."); + } + + var request = new HttpRequestMessage(HttpMethod.Post, Url); + request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.Default.GetBytes(ApiKey))); + request.Content = new StringContent(JsonConvert.SerializeObject(this), Encoding.UTF8, "application/json"); + return request; + } + } + + [JsonIgnore] + protected override Uri Url + { + get + { + return new Uri(String.Format(GlobalProfileLookupUrl, + Uri.EscapeDataString(AccountId))); + } + } + } +} diff --git a/Sift/Response/GlobalProfileResponse.cs b/Sift/Response/GlobalProfileResponse.cs new file mode 100644 index 0000000..7926c6a --- /dev/null +++ b/Sift/Response/GlobalProfileResponse.cs @@ -0,0 +1,179 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +namespace Sift +{ + public class GlobalProfileResponse : SiftResponse + { + [JsonProperty("error_code")] + public int? ErrorCode { get; set; } + + [JsonProperty("lookback_months")] + public int? LookbackMonths { get; set; } + + [JsonProperty("profile_summary")] + public ProfileSummaryJson ProfileSummary { get; set; } + + [JsonProperty("identity_age")] + public IdentityAgeJson IdentityAge { get; set; } + + [JsonProperty("user_decisions")] + public UserDecisionsJson UserDecisions { get; set; } + + [JsonProperty("chargebacks")] + public ChargebacksJson Chargebacks { get; set; } + + [JsonProperty("orders")] + public OrdersJson Orders { get; set; } + + [JsonProperty("transactions")] + public TransactionsJson Transactions { get; set; } + + [JsonProperty("locations")] + public LocationsJson Locations { get; set; } + + public class ProfileSummaryJson + { + [JsonProperty("identity_found")] + public bool IdentityFound { get; set; } + + [JsonProperty("has_links")] + public bool HasLinks { get; set; } + + [JsonProperty("link_count")] + public int LinkCount { get; set; } + + [JsonProperty("linked_accounts_count_per_industry")] + public Dictionary LinkedAccountsCountPerIndustry { get; set; } + } + + public class IdentityAgeJson + { + [JsonProperty("oldest_account_age_timestamp")] + public long? OldestAccountAgeTimestamp { get; set; } + + [JsonProperty("newest_account_age_timestamp")] + public long? NewestAccountAgeTimestamp { get; set; } + + [JsonProperty("average_account_age_timestamp")] + public long? AverageAccountAgeTimestamp { get; set; } + } + + public class UserDecisionsJson + { + [JsonProperty("total")] + public int Total { get; set; } + + [JsonProperty("blocked")] + public int Blocked { get; set; } + + [JsonProperty("watched")] + public int Watched { get; set; } + + [JsonProperty("accepted")] + public int Accepted { get; set; } + + [JsonProperty("manual")] + public int Manual { get; set; } + + [JsonProperty("auto")] + public int Auto { get; set; } + + [JsonProperty("last_type")] + public string LastType { get; set; } + + [JsonProperty("last_timestamp")] + public long? LastTimestamp { get; set; } + } + + public class ChargebacksJson + { + [JsonProperty("total")] + public int Total { get; set; } + + [JsonProperty("fraudulent")] + public int Fraudulent { get; set; } + + [JsonProperty("other")] + public int Other { get; set; } + + [JsonProperty("last_timestamp")] + public long? LastTimestamp { get; set; } + + [JsonProperty("last_fraudulent_timestamp")] + public long? LastFraudulentTimestamp { get; set; } + } + + public class OrdersJson + { + [JsonProperty("total")] + public int Total { get; set; } + + [JsonProperty("blocked")] + public int Blocked { get; set; } + + [JsonProperty("watched")] + public int Watched { get; set; } + + [JsonProperty("accepted")] + public int Accepted { get; set; } + + [JsonProperty("last_timestamp")] + public long? LastTimestamp { get; set; } + + [JsonProperty("last_blocked_timestamp")] + public long? LastBlockedTimestamp { get; set; } + } + + public class TransactionsJson + { + [JsonProperty("total")] + public int Total { get; set; } + + [JsonProperty("failed_fraud")] + public int FailedFraud { get; set; } + + [JsonProperty("failed_other")] + public int FailedOther { get; set; } + + [JsonProperty("successful")] + public int Successful { get; set; } + + [JsonProperty("last_timestamp")] + public long? LastTimestamp { get; set; } + + [JsonProperty("last_failed_fraud_timestamp")] + public long? LastFailedFraudTimestamp { get; set; } + } + + public class LocationsJson + { + [JsonProperty("unique_billing_addresses")] + public int UniqueBillingAddresses { get; set; } + + [JsonProperty("unique_shipping_addresses")] + public int UniqueShippingAddresses { get; set; } + + [JsonProperty("distinct_countries_count")] + public int DistinctCountriesCount { get; set; } + + [JsonProperty("distinct_regions_count")] + public int DistinctRegionsCount { get; set; } + + [JsonProperty("location_connected_accounts")] + public List LocationConnectedAccounts { get; set; } + + [JsonProperty("location_last_used_timestamp")] + public long? LocationLastUsedTimestamp { get; set; } + } + + public class LocationConnectedAccountJson + { + [JsonProperty("city")] + public string City { get; set; } + + [JsonProperty("country")] + public string Country { get; set; } + } + } +} diff --git a/Sift/Sift.csproj b/Sift/Sift.csproj index 76009fc..7dbe498 100644 --- a/Sift/Sift.csproj +++ b/Sift/Sift.csproj @@ -4,8 +4,8 @@ Sift Sift Sift - 1.7.0 - Release 1.7.0 + 1.8.0 + Release 1.8.0 netstandard2.0 Sift sift;siftscience;client;api;client;async diff --git a/Test/Test.cs b/Test/Test.cs index 35648b2..edf4b4a 100644 --- a/Test/Test.cs +++ b/Test/Test.cs @@ -1083,6 +1083,178 @@ public void TestGetMerchantDetailsRequest() getMerchantDetailRequest.Request.RequestUri!.ToString()); } + [Fact] + public void TestGlobalProfileRequest() + { + //Please provide the valid account id in place of dummy number; + var accountId = "12345678"; + var userId = "user-1"; + //Please provide the valid api key in place of 'key' + var apiKey = "key"; + var globalProfileRequest = new GlobalProfileRequest + { + AccountId = accountId, + UserId = userId + }; + globalProfileRequest.ApiKey = apiKey; + + Assert.Equal(Convert.ToBase64String(Encoding.Default.GetBytes(apiKey)), + globalProfileRequest.Request.Headers.Authorization!.Parameter); + + Assert.Equal("https://api.sift.com/v3/accounts/" + accountId + "/global_profile/users/" + userId, + globalProfileRequest.Request.RequestUri!.ToString()); + } + + [Fact] + public void TestGlobalProfileRequestWithQueryParams() + { + var accountId = "12345678"; + var userId = "user-1"; + var apiKey = "key"; + var globalProfileRequest = new GlobalProfileRequest + { + AccountId = accountId, + UserId = userId, + GlobalOnly = true, + IncludeOwnData = false + }; + globalProfileRequest.ApiKey = apiKey; + + Assert.Equal("https://api.sift.com/v3/accounts/" + accountId + "/global_profile/users/" + userId + + "?global_only=true&include_own_data=false", + Uri.UnescapeDataString(globalProfileRequest.Request.RequestUri!.ToString())); + } + + [Fact] + public void TestGlobalProfileLookupRequest() + { + var accountId = "12345678"; + var apiKey = "key"; + var globalProfileLookupRequest = new GlobalProfileLookupRequest + { + AccountId = accountId, + Email = "gary@example.com", + Phone = "+15555550100" + }; + globalProfileLookupRequest.ApiKey = apiKey; + + Assert.Equal(Convert.ToBase64String(Encoding.Default.GetBytes(apiKey)), + globalProfileLookupRequest.Request.Headers.Authorization!.Parameter); + + Assert.Equal("https://api.sift.com/v3/accounts/" + accountId + "/global_profile/lookup", + globalProfileLookupRequest.Request.RequestUri!.ToString()); + + Assert.Equal("{\"email\":\"gary@example.com\",\"phone\":\"+15555550100\"}", + JsonConvert.SerializeObject(globalProfileLookupRequest)); + } + + [Fact] + public void TestGlobalProfileLookupRequestRequiresEmailOrPhone() + { + var globalProfileLookupRequest = new GlobalProfileLookupRequest + { + AccountId = "12345678" + }; + globalProfileLookupRequest.ApiKey = "key"; + + Assert.Throws( + () => globalProfileLookupRequest.Request + ); + } + + [Fact] + public void TestGlobalProfileResponseDeserialization() + { + var json = "{" + + "\"status\":0," + + "\"error_message\":\"OK\"," + + "\"error_code\":null," + + "\"lookback_months\":12," + + "\"profile_summary\":{" + + "\"identity_found\":true," + + "\"has_links\":true," + + "\"link_count\":7," + + "\"linked_accounts_count_per_industry\":{\"finances\":3,\"internet\":4}" + + "}," + + "\"identity_age\":{" + + "\"oldest_account_age_timestamp\":1681090536," + + "\"newest_account_age_timestamp\":1881090536," + + "\"average_account_age_timestamp\":1781090536" + + "}," + + "\"user_decisions\":{" + + "\"total\":12,\"blocked\":2,\"watched\":3,\"accepted\":6," + + "\"manual\":4,\"auto\":8,\"last_type\":\"BLOCK\",\"last_timestamp\":1881090536" + + "}," + + "\"chargebacks\":{" + + "\"total\":3,\"fraudulent\":2,\"other\":1," + + "\"last_timestamp\":1881090536,\"last_fraudulent_timestamp\":1881090536" + + "}," + + "\"orders\":{" + + "\"total\":50,\"blocked\":2,\"watched\":5,\"accepted\":40," + + "\"last_timestamp\":1881090536,\"last_blocked_timestamp\":1881090536" + + "}," + + "\"transactions\":{" + + "\"total\":120,\"failed_fraud\":3,\"failed_other\":5,\"successful\":112," + + "\"last_timestamp\":1881090536,\"last_failed_fraud_timestamp\":1881090536" + + "}," + + "\"locations\":{" + + "\"unique_billing_addresses\":2,\"unique_shipping_addresses\":4," + + "\"distinct_countries_count\":3,\"distinct_regions_count\":5," + + "\"location_connected_accounts\":[{\"city\":\"Kyiv\",\"country\":\"UA\"}]," + + "\"location_last_used_timestamp\":1881090536" + + "}" + + "}"; + + var response = JsonConvert.DeserializeObject(json); + + Assert.Equal(0, response!.Status); + Assert.Equal(12, response.LookbackMonths); + Assert.True(response.ProfileSummary!.IdentityFound); + Assert.Equal(7, response.ProfileSummary.LinkCount); + Assert.Equal(3, response.ProfileSummary.LinkedAccountsCountPerIndustry!["finances"]); + Assert.Equal(1681090536, response.IdentityAge!.OldestAccountAgeTimestamp); + Assert.Equal(12, response.UserDecisions!.Total); + Assert.Equal(3, response.Chargebacks!.Total); + Assert.Equal(50, response.Orders!.Total); + Assert.Equal(120, response.Transactions!.Total); + Assert.Equal(2, response.Locations!.UniqueBillingAddresses); + Assert.Single(response.Locations.LocationConnectedAccounts!); + Assert.Equal("Kyiv", response.Locations.LocationConnectedAccounts![0].City); + } + + [Fact] + public void TestGlobalProfileResponseWhenIdentityNotFound() + { + var json = "{" + + "\"status\":0," + + "\"error_message\":\"OK\"," + + "\"error_code\":null," + + "\"lookback_months\":null," + + "\"profile_summary\":{" + + "\"identity_found\":false," + + "\"has_links\":false," + + "\"link_count\":0," + + "\"linked_accounts_count_per_industry\":{}" + + "}," + + "\"identity_age\":null," + + "\"user_decisions\":null," + + "\"chargebacks\":null," + + "\"orders\":null," + + "\"transactions\":null," + + "\"locations\":null" + + "}"; + + var response = JsonConvert.DeserializeObject(json); + + Assert.False(response!.ProfileSummary!.IdentityFound); + Assert.Null(response.IdentityAge); + Assert.Null(response.UserDecisions); + Assert.Null(response.Chargebacks); + Assert.Null(response.Orders); + Assert.Null(response.Transactions); + Assert.Null(response.Locations); + } + [Fact] public void TestChargebackEvent() { From 83df067a939ef8df86cbe96d9f3af5ab7e09a187 Mon Sep 17 00:00:00 2001 From: Tetiana Holovina Date: Wed, 19 Aug 2026 17:22:55 +0300 Subject: [PATCH 2/3] fix: address Global Profile API code review findings - Add missing Region field to LocationConnectedAccountJson (P2) - Make HasLinks/LinkCount nullable in ProfileSummaryJson (P2) - Change count fields from int to long to match server types (P3) Co-Authored-By: Claude --- Sift/Response/GlobalProfileResponse.cs | 51 ++++++++++++++------------ Test/Test.cs | 35 ++++++++++++++---- 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/Sift/Response/GlobalProfileResponse.cs b/Sift/Response/GlobalProfileResponse.cs index 7926c6a..75782ec 100644 --- a/Sift/Response/GlobalProfileResponse.cs +++ b/Sift/Response/GlobalProfileResponse.cs @@ -38,13 +38,13 @@ public class ProfileSummaryJson public bool IdentityFound { get; set; } [JsonProperty("has_links")] - public bool HasLinks { get; set; } + public bool? HasLinks { get; set; } [JsonProperty("link_count")] - public int LinkCount { get; set; } + public int? LinkCount { get; set; } [JsonProperty("linked_accounts_count_per_industry")] - public Dictionary LinkedAccountsCountPerIndustry { get; set; } + public Dictionary LinkedAccountsCountPerIndustry { get; set; } } public class IdentityAgeJson @@ -62,22 +62,22 @@ public class IdentityAgeJson public class UserDecisionsJson { [JsonProperty("total")] - public int Total { get; set; } + public long Total { get; set; } [JsonProperty("blocked")] - public int Blocked { get; set; } + public long Blocked { get; set; } [JsonProperty("watched")] - public int Watched { get; set; } + public long Watched { get; set; } [JsonProperty("accepted")] - public int Accepted { get; set; } + public long Accepted { get; set; } [JsonProperty("manual")] - public int Manual { get; set; } + public long Manual { get; set; } [JsonProperty("auto")] - public int Auto { get; set; } + public long Auto { get; set; } [JsonProperty("last_type")] public string LastType { get; set; } @@ -89,13 +89,13 @@ public class UserDecisionsJson public class ChargebacksJson { [JsonProperty("total")] - public int Total { get; set; } + public long Total { get; set; } [JsonProperty("fraudulent")] - public int Fraudulent { get; set; } + public long Fraudulent { get; set; } [JsonProperty("other")] - public int Other { get; set; } + public long Other { get; set; } [JsonProperty("last_timestamp")] public long? LastTimestamp { get; set; } @@ -107,16 +107,16 @@ public class ChargebacksJson public class OrdersJson { [JsonProperty("total")] - public int Total { get; set; } + public long Total { get; set; } [JsonProperty("blocked")] - public int Blocked { get; set; } + public long Blocked { get; set; } [JsonProperty("watched")] - public int Watched { get; set; } + public long Watched { get; set; } [JsonProperty("accepted")] - public int Accepted { get; set; } + public long Accepted { get; set; } [JsonProperty("last_timestamp")] public long? LastTimestamp { get; set; } @@ -128,16 +128,16 @@ public class OrdersJson public class TransactionsJson { [JsonProperty("total")] - public int Total { get; set; } + public long Total { get; set; } [JsonProperty("failed_fraud")] - public int FailedFraud { get; set; } + public long FailedFraud { get; set; } [JsonProperty("failed_other")] - public int FailedOther { get; set; } + public long FailedOther { get; set; } [JsonProperty("successful")] - public int Successful { get; set; } + public long Successful { get; set; } [JsonProperty("last_timestamp")] public long? LastTimestamp { get; set; } @@ -149,16 +149,16 @@ public class TransactionsJson public class LocationsJson { [JsonProperty("unique_billing_addresses")] - public int UniqueBillingAddresses { get; set; } + public long UniqueBillingAddresses { get; set; } [JsonProperty("unique_shipping_addresses")] - public int UniqueShippingAddresses { get; set; } + public long UniqueShippingAddresses { get; set; } [JsonProperty("distinct_countries_count")] - public int DistinctCountriesCount { get; set; } + public long DistinctCountriesCount { get; set; } [JsonProperty("distinct_regions_count")] - public int DistinctRegionsCount { get; set; } + public long DistinctRegionsCount { get; set; } [JsonProperty("location_connected_accounts")] public List LocationConnectedAccounts { get; set; } @@ -174,6 +174,9 @@ public class LocationConnectedAccountJson [JsonProperty("country")] public string Country { get; set; } + + [JsonProperty("region")] + public string Region { get; set; } } } } diff --git a/Test/Test.cs b/Test/Test.cs index edf4b4a..48489c1 100644 --- a/Test/Test.cs +++ b/Test/Test.cs @@ -1148,6 +1148,25 @@ public void TestGlobalProfileLookupRequest() JsonConvert.SerializeObject(globalProfileLookupRequest)); } + [Fact] + public void TestGlobalProfileLookupRequestWithEmailOnly() + { + var accountId = "12345678"; + var apiKey = "key"; + var globalProfileLookupRequest = new GlobalProfileLookupRequest + { + AccountId = accountId, + Email = "gary@example.com" + }; + globalProfileLookupRequest.ApiKey = apiKey; + + Assert.Equal("https://api.sift.com/v3/accounts/" + accountId + "/global_profile/lookup", + globalProfileLookupRequest.Request.RequestUri!.ToString()); + + Assert.Equal("{\"email\":\"gary@example.com\"}", + JsonConvert.SerializeObject(globalProfileLookupRequest)); + } + [Fact] public void TestGlobalProfileLookupRequestRequiresEmailOrPhone() { @@ -1200,7 +1219,7 @@ public void TestGlobalProfileResponseDeserialization() "\"locations\":{" + "\"unique_billing_addresses\":2,\"unique_shipping_addresses\":4," + "\"distinct_countries_count\":3,\"distinct_regions_count\":5," + - "\"location_connected_accounts\":[{\"city\":\"Kyiv\",\"country\":\"UA\"}]," + + "\"location_connected_accounts\":[{\"city\":\"Kyiv\",\"country\":\"UA\",\"region\":\"Kyiv Oblast\"}]," + "\"location_last_used_timestamp\":1881090536" + "}" + "}"; @@ -1211,15 +1230,17 @@ public void TestGlobalProfileResponseDeserialization() Assert.Equal(12, response.LookbackMonths); Assert.True(response.ProfileSummary!.IdentityFound); Assert.Equal(7, response.ProfileSummary.LinkCount); - Assert.Equal(3, response.ProfileSummary.LinkedAccountsCountPerIndustry!["finances"]); + Assert.Equal(3L, response.ProfileSummary.LinkedAccountsCountPerIndustry!["finances"]); Assert.Equal(1681090536, response.IdentityAge!.OldestAccountAgeTimestamp); - Assert.Equal(12, response.UserDecisions!.Total); - Assert.Equal(3, response.Chargebacks!.Total); - Assert.Equal(50, response.Orders!.Total); - Assert.Equal(120, response.Transactions!.Total); - Assert.Equal(2, response.Locations!.UniqueBillingAddresses); + Assert.Equal(12L, response.UserDecisions!.Total); + Assert.Equal(3L, response.Chargebacks!.Total); + Assert.Equal(50L, response.Orders!.Total); + Assert.Equal(120L, response.Transactions!.Total); + Assert.Equal(2L, response.Locations!.UniqueBillingAddresses); Assert.Single(response.Locations.LocationConnectedAccounts!); Assert.Equal("Kyiv", response.Locations.LocationConnectedAccounts![0].City); + Assert.Equal("UA", response.Locations.LocationConnectedAccounts![0].Country); + Assert.Equal("Kyiv Oblast", response.Locations.LocationConnectedAccounts![0].Region); } [Fact] From a867d64c4f04eac801f5b7c621ce6552970c0e49 Mon Sep 17 00:00:00 2001 From: Tetiana Holovina Date: Thu, 20 Aug 2026 15:16:56 +0300 Subject: [PATCH 3/3] fix: qualify MissingFieldException to resolve CS0104 ambiguity System.MissingFieldException and Sift.MissingFieldException are both in scope; use the fully qualified Sift.MissingFieldException. Co-Authored-By: Claude --- Test/Test.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/Test.cs b/Test/Test.cs index 48489c1..1654b18 100644 --- a/Test/Test.cs +++ b/Test/Test.cs @@ -1176,7 +1176,7 @@ public void TestGlobalProfileLookupRequestRequiresEmailOrPhone() }; globalProfileLookupRequest.ApiKey = "key"; - Assert.Throws( + Assert.Throws( () => globalProfileLookupRequest.Request ); }