Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGES.MD
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions Sift/Core/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ public async Task<GetMerchantDetailsResponse> SendAsync(GetMerchantDetailsReques
return await SendAsync<GetMerchantDetailsResponse>(getMerchantRequest);
}

public async Task<GlobalProfileResponse> SendAsync(GlobalProfileRequest globalProfileRequest)
{
return await SendAsync<GlobalProfileResponse>(globalProfileRequest);
}

public async Task<GlobalProfileResponse> SendAsync(GlobalProfileLookupRequest globalProfileLookupRequest)
{
return await SendAsync<GlobalProfileResponse>(globalProfileLookupRequest);
}

async Task<T> SendAsync<T>(SiftRequest siftRequest) where T : SiftResponse
{
siftRequest.ApiKey = this.apiKey;
Expand Down
94 changes: 94 additions & 0 deletions Sift/Request/GlobalProfileRequest.cs
Original file line number Diff line number Diff line change
@@ -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)));
}
}
}
}
182 changes: 182 additions & 0 deletions Sift/Response/GlobalProfileResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
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<string, long> 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 long Total { get; set; }

[JsonProperty("blocked")]
public long Blocked { get; set; }

[JsonProperty("watched")]
public long Watched { get; set; }

[JsonProperty("accepted")]
public long Accepted { get; set; }

[JsonProperty("manual")]
public long Manual { get; set; }

[JsonProperty("auto")]
public long 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 long Total { get; set; }

[JsonProperty("fraudulent")]
public long Fraudulent { get; set; }

[JsonProperty("other")]
public long 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 long Total { get; set; }

[JsonProperty("blocked")]
public long Blocked { get; set; }

[JsonProperty("watched")]
public long Watched { get; set; }

[JsonProperty("accepted")]
public long 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 long Total { get; set; }

[JsonProperty("failed_fraud")]
public long FailedFraud { get; set; }

[JsonProperty("failed_other")]
public long FailedOther { get; set; }

[JsonProperty("successful")]
public long 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 long UniqueBillingAddresses { get; set; }

[JsonProperty("unique_shipping_addresses")]
public long UniqueShippingAddresses { get; set; }

[JsonProperty("distinct_countries_count")]
public long DistinctCountriesCount { get; set; }

[JsonProperty("distinct_regions_count")]
public long DistinctRegionsCount { get; set; }

[JsonProperty("location_connected_accounts")]
public List<LocationConnectedAccountJson> 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; }

[JsonProperty("region")]
public string Region { get; set; }
}
}
}
4 changes: 2 additions & 2 deletions Sift/Sift.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<Authors>Sift</Authors>
<AssemblyTitle>Sift</AssemblyTitle>
<AssemblyName>Sift</AssemblyName>
<VersionPrefix>1.7.0</VersionPrefix>
<PackageReleaseNotes>Release 1.7.0</PackageReleaseNotes>
<VersionPrefix>1.8.0</VersionPrefix>
<PackageReleaseNotes>Release 1.8.0</PackageReleaseNotes>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Sift</PackageId>
<PackageTags>sift;siftscience;client;api;client;async</PackageTags>
Expand Down
Loading
Loading