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
7 changes: 7 additions & 0 deletions CHANGES.MD
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
3.23.0 (2026-08-18)
=================
- Added support for the Global Profile API: `GlobalProfileFieldSet` / `GlobalProfileRequest` for
`GET /v3/accounts/{accountId}/global_profile/users/{userId}`, and
`GlobalProfileLookupFieldSet` / `GlobalProfileLookupRequest` for
`POST /v3/accounts/{accountId}/global_profile/lookup`

3.22.0 (2026-01-05)
=================
- Added support for `$user_email`, `$review.$reviewed_user_id` fields to `$create_content`, `$update_content` events
Expand Down
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,48 @@ DecisionStatusRequest request = client.buildRequest(new DecisionStatusFieldSet()
.setUserId("a_user_id")
.setEntityId("a_content_id"));
```

### Global Profile API

[API Docs](https://sift.com/developers/docs/java/global-profile-api)

The Global Profile API returns cross-tenant identity, decision, chargeback, order, transaction, and
location signals for a user, either by user ID or by looking them up via email/phone.

#### Get a user's global profile

To retrieve a global profile by user id, build a request with a `GlobalProfileFieldSet`.
```java
GlobalProfileRequest request = client.buildRequest(new GlobalProfileFieldSet()
.setUserId("a_user_id"));
```

`global_only` (excludes the requesting tenant's own network connections, defaults to `false`) and
`include_own_data` (includes the requested user's own feature values, defaults to `true`) may
optionally be set.
```java
GlobalProfileRequest request = client.buildRequest(new GlobalProfileFieldSet()
.setUserId("a_user_id")
.setGlobalOnly(true)
.setIncludeOwnData(false));

GlobalProfileResponse response = request.send();
response.getBody().getProfileSummary().getIdentityFound();
```

If `identity_found` is `false`, every field on the response body other than `profile_summary` will
be `null`.

#### Look up a global profile by email or phone

To look up a global profile without a Sift user id, build a request with a
`GlobalProfileLookupFieldSet`, providing at least one of `email` or `phone`.
```java
GlobalProfileLookupRequest request = client.buildRequest(new GlobalProfileLookupFieldSet()
.setEmail("jane.doe@example.com")
.setPhone("+15551234567"));

GlobalProfileLookupResponse response = request.send();
```

Omitting both `email` and `phone` will raise a `MissingFieldException` before any request is sent.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ apply plugin: 'signing'
apply plugin: 'java-library-distribution'

group = 'com.siftscience'
version = '3.22.0'
version = '3.23.0'

repositories {
mavenCentral()
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/com/siftscience/GlobalProfileLookupRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.siftscience;

import java.io.IOException;

import com.siftscience.model.GlobalProfileLookupFieldSet;
import okhttp3.Credentials;
import okhttp3.HttpUrl;
import okhttp3.Request;

public class GlobalProfileLookupRequest extends SiftRequest<GlobalProfileLookupResponse> {

GlobalProfileLookupRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient,
GlobalProfileLookupFieldSet fields) {
super(baseUrl, accountId, httpClient, fields);
}

@Override
protected HttpUrl path(HttpUrl baseUrl) {
return baseUrl.newBuilder("/v3/accounts")
.addPathSegment(getAccountId())
.addPathSegment("global_profile")
.addPathSegment("lookup")
.build();
}

@Override
GlobalProfileLookupResponse buildResponse(okhttp3.Response response, FieldSet requestFields)
throws IOException {
return new GlobalProfileLookupResponse(response, requestFields);
}

@Override
protected void modifyRequestBuilder(Request.Builder builder) {
super.modifyRequestBuilder(builder);
builder.header("Authorization", Credentials.basic(fieldSet.getApiKey(), ""));
}
}
20 changes: 20 additions & 0 deletions src/main/java/com/siftscience/GlobalProfileLookupResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.siftscience;

import com.siftscience.model.GlobalProfileResponseBody;
import okhttp3.Response;

import java.io.IOException;

import static com.siftscience.FieldSet.gson;

public class GlobalProfileLookupResponse extends SiftResponse<GlobalProfileResponseBody> {

public GlobalProfileLookupResponse(Response okResponse, FieldSet requestBody) throws IOException {
super(okResponse, requestBody);
}

@Override
void populateBodyFromJson(String jsonBody) {
body = gson.fromJson(jsonBody, GlobalProfileResponseBody.class);
}
}
66 changes: 66 additions & 0 deletions src/main/java/com/siftscience/GlobalProfileRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.siftscience;

import java.io.IOException;

import com.siftscience.model.GlobalProfileFieldSet;
import okhttp3.Credentials;
import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;

public class GlobalProfileRequest extends SiftRequest<GlobalProfileResponse> {

GlobalProfileRequest(HttpUrl baseUrl, String accountId, HttpClient httpClient,
GlobalProfileFieldSet fields) {
super(baseUrl, accountId, httpClient, fields);
}

public enum Query {
GLOBAL_ONLY("global_only"),
INCLUDE_OWN_DATA("include_own_data");

private final String value;

Query(String value) {
this.value = value;
}

@Override
public String toString() {
return value;
}
}

@Override
protected HttpUrl path(HttpUrl baseUrl) {
GlobalProfileFieldSet fieldSet = (GlobalProfileFieldSet) this.fieldSet;
HttpUrl.Builder path = baseUrl.newBuilder("/v3/accounts")
.addPathSegment(getAccountId())
.addPathSegment("global_profile")
.addPathSegment("users")
.addPathSegment(fieldSet.getUserId());

if (fieldSet.getGlobalOnly() != null) {
path.addQueryParameter(Query.GLOBAL_ONLY.toString(),
String.valueOf(fieldSet.getGlobalOnly()));
}
if (fieldSet.getIncludeOwnData() != null) {
path.addQueryParameter(Query.INCLUDE_OWN_DATA.toString(),
String.valueOf(fieldSet.getIncludeOwnData()));
}

return path.build();
}

@Override
GlobalProfileResponse buildResponse(Response response, FieldSet requestFields)
throws IOException {
return new GlobalProfileResponse(response, requestFields);
}

@Override
protected void modifyRequestBuilder(Request.Builder builder) {
super.modifyRequestBuilder(builder);
builder.header("Authorization", Credentials.basic(fieldSet.getApiKey(), "")).get();
}
}
20 changes: 20 additions & 0 deletions src/main/java/com/siftscience/GlobalProfileResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.siftscience;

import com.siftscience.model.GlobalProfileResponseBody;
import okhttp3.Response;

import java.io.IOException;

import static com.siftscience.FieldSet.gson;

public class GlobalProfileResponse extends SiftResponse<GlobalProfileResponseBody> {

public GlobalProfileResponse(Response okResponse, FieldSet requestBody) throws IOException {
super(okResponse, requestBody);
}

@Override
void populateBodyFromJson(String jsonBody) {
body = gson.fromJson(jsonBody, GlobalProfileResponseBody.class);
}
}
14 changes: 14 additions & 0 deletions src/main/java/com/siftscience/SiftClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.siftscience.model.ApplyDecisionFieldSet;
import com.siftscience.model.DecisionStatusFieldSet;
import com.siftscience.model.GetDecisionFieldSet;
import com.siftscience.model.GlobalProfileFieldSet;
import com.siftscience.model.GlobalProfileLookupFieldSet;
import com.siftscience.model.LabelFieldSet;
import com.siftscience.model.ScoreFieldSet;
import com.siftscience.model.UnlabelFieldSet;
Expand Down Expand Up @@ -108,6 +110,18 @@ public GetDecisionsRequest buildRequest(GetDecisionFieldSet fields) {
return new GetDecisionsRequest(baseUrl, getAccountId(), httpClient, fields);
}

public GlobalProfileRequest buildRequest(GlobalProfileFieldSet fields) {
assertAccountIdIsNotNull();
setupApiKey(fields);
return new GlobalProfileRequest(baseUrl, getAccountId(), httpClient, fields);
}

public GlobalProfileLookupRequest buildRequest(GlobalProfileLookupFieldSet fields) {
assertAccountIdIsNotNull();
setupApiKey(fields);
return new GlobalProfileLookupRequest(baseUrl, getAccountId(), httpClient, fields);
}

public DecisionStatusRequest buildRequest(DecisionStatusFieldSet fields) {
assertAccountIdIsNotNull();
setupApiKey(fields);
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/com/siftscience/model/GlobalProfileChargebacks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.siftscience.model;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class GlobalProfileChargebacks {
@Expose @SerializedName("total") private Long total;
@Expose @SerializedName("fraudulent") private Long fraudulent;
@Expose @SerializedName("other") private Long other;
@Expose @SerializedName("last_timestamp") private Long lastTimestamp;
@Expose @SerializedName("last_fraudulent_timestamp") private Long lastFraudulentTimestamp;

public Long getTotal() {
return total;
}

public GlobalProfileChargebacks setTotal(Long total) {
this.total = total;
return this;
}

public Long getFraudulent() {
return fraudulent;
}

public GlobalProfileChargebacks setFraudulent(Long fraudulent) {
this.fraudulent = fraudulent;
return this;
}

public Long getOther() {
return other;
}

public GlobalProfileChargebacks setOther(Long other) {
this.other = other;
return this;
}

public Long getLastTimestamp() {
return lastTimestamp;
}

public GlobalProfileChargebacks setLastTimestamp(Long lastTimestamp) {
this.lastTimestamp = lastTimestamp;
return this;
}

public Long getLastFraudulentTimestamp() {
return lastFraudulentTimestamp;
}

public GlobalProfileChargebacks setLastFraudulentTimestamp(Long lastFraudulentTimestamp) {
this.lastFraudulentTimestamp = lastFraudulentTimestamp;
return this;
}
}
64 changes: 64 additions & 0 deletions src/main/java/com/siftscience/model/GlobalProfileFieldSet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.siftscience.model;

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.siftscience.FieldSet;
import com.siftscience.exception.MissingFieldException;

/**
* Field set for {@code GET /v3/accounts/{accountId}/global_profile/users/{userId}}.
*/
public class GlobalProfileFieldSet extends FieldSet<GlobalProfileFieldSet> {
@Expose @SerializedName("user_id") private String userId;
@Expose @SerializedName("global_only") private Boolean globalOnly;
@Expose @SerializedName("include_own_data") private Boolean includeOwnData;

public GlobalProfileFieldSet() {}

public static GlobalProfileFieldSet fromJson(String json) {
return gson.fromJson(json, GlobalProfileFieldSet.class);
}

@Override
public void validate() {
super.validate();
if (userId == null || userId.isEmpty()) {
throw new MissingFieldException("'userId' is required for a global profile request.");
}
}

public String getUserId() {
return userId;
}

public GlobalProfileFieldSet setUserId(String userId) {
this.userId = userId;
return this;
}

/**
* If true, excludes the requesting tenant's own network connections from the response.
* Defaults to false server-side if not set.
*/
public Boolean getGlobalOnly() {
return globalOnly;
}

public GlobalProfileFieldSet setGlobalOnly(Boolean globalOnly) {
this.globalOnly = globalOnly;
return this;
}

/**
* If true, includes the requested user's own feature values in the response. Defaults to
* true server-side if not set.
*/
public Boolean getIncludeOwnData() {
return includeOwnData;
}

public GlobalProfileFieldSet setIncludeOwnData(Boolean includeOwnData) {
this.includeOwnData = includeOwnData;
return this;
}
}
Loading
Loading