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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [x.x.x] - unreleased

## [3.6.0] - 2025-08-14
### Added
- Added support for the `Smartsheet-Integration-Source` header. This can be configured using the `SmartsheetBuilder` or set directly on the `Smartsheet` client.
This header is mandatory and has to follow the format:

`INTEGRATION-TYPE, ORGANIZATION_NAME, INTEGRATOR_NAME`
(NB: Comma is used as a delimiter and is required if the value is missing)

`INTEGRATION-TYPE - Required, the type of the integrator (e.g. AI, SCRIPT, APPLICATION)`

`ORGANIZATION_NAME - Optional (but COMMA is required), organization name (e.g. Microsoft, Google, OpenAI, etc.)`

`INTEGRATOR-NAME - Required, the name of the integrator (e.g. Claude, Copilot, ChatGPT, DeepSeek, etc.)`

## [3.5.0] - 2025-08-08
### Added
- Added support for token-based pagination in WorkspaceResources.listWorkspaces() method
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ plugins {
// The group name. This dictates the prefix our dependency will have once it's published.
group = 'com.smartsheet'
// The version. This will be added to the end of the Jar and all other resources that are created during the build.
version = '3.5.0'
version = '3.6.0'
// The Java version:
sourceCompatibility = '11'

Expand Down
7 changes: 7 additions & 0 deletions src/main/java/com/smartsheet/api/Smartsheet.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ public interface Smartsheet {
*/
void setMaxRetryTimeMillis(long maxRetryTimeMillis);

/**
* <p>Sets the custom integration source identifier.</p>
*
* @param smartsheetIntegrationSource the integration source header value
*/
void setSmartsheetIntegrationSource(String smartsheetIntegrationSource) throws SmartsheetException;

/**
* <p>Returns the HomeResources instance that provides access to Home resources.</p>
*
Expand Down
42 changes: 40 additions & 2 deletions src/main/java/com/smartsheet/api/SmartsheetBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.smartsheet.api.internal.SmartsheetImpl;
import com.smartsheet.api.internal.http.HttpClient;
import com.smartsheet.api.internal.json.JsonSerializer;
import com.smartsheet.api.internal.util.SmartsheetIntegrationSourceValidator;

/**
* <p>A convenience class to help create a {@link Smartsheet} instance with the appropriate fields.</p>
Expand Down Expand Up @@ -76,6 +77,14 @@ public class SmartsheetBuilder {
*/
private String changeAgent;

/**
* <p>Represents the smartsheet integration source.</p>
*
* <p>It can be set using corresponding setter.</p>
*/
private String smartsheetIntegrationSource;


/** URI to prod-us API endpoints */
public static final String US_BASE_URI = "https://api.smartsheet.com/2.0/";
/** URI to prod-eu API endpoints */
Expand Down Expand Up @@ -180,6 +189,26 @@ public SmartsheetBuilder setChangeAgent(String changeAgent) {
return this;
}

/**
* <p>Set the smartsheet integration source.</p>
*
* Format: $TYPE,$ORG_NAME,$INTEGRATOR_NAME
* (NB: Comma is used as a delimiter and is required if the value is missing)
*
* $INTEGRATION-TYPE - Required, the type of the integrator (e.g. AI, SCRIPT, APPLICATION)
* $SMAR-ORGANIZATION-NAME - Optional (but COMMA is required), organization name (e.g. Microsoft, Google, OpenAI, etc.)
* $INTEGRATOR-NAME - Required, the name of the integrator (e.g. Claude, Copilot, ChatGPT, DeepSeek, etc.)
*
* @param smartsheetIntegrationSource the identifier to include in requests to determine the source of request maker
* @return the smartsheet builder
*/
public SmartsheetBuilder setSmartsheetIntegrationSource(String smartsheetIntegrationSource) throws SmartsheetException {
if (SmartsheetIntegrationSourceValidator.isValidFormat(smartsheetIntegrationSource)) {
this.smartsheetIntegrationSource = smartsheetIntegrationSource;
}
return this;
}

/**
* <p>Gets the http client.</p>
*
Expand Down Expand Up @@ -243,13 +272,22 @@ public String getChangeAgent() {
return changeAgent;
}

/**
* <p>Gets the Smartsheet-Integration-Source</p>
*
* @return the smartsheet integration source
*/
public String getSmartsheetIntegrationSource() {
return smartsheetIntegrationSource;
}

/**
* <p>Build the Smartsheet instance.</p>
*
* @return the Smartsheet instance
* @throws IllegalStateException if accessToken isn't set yet.
*/
public Smartsheet build() {
public Smartsheet build() throws SmartsheetException {
if (baseURI == null) {
baseURI = DEFAULT_BASE_URI;
}
Expand All @@ -258,7 +296,7 @@ public Smartsheet build() {
accessToken = System.getenv("SMARTSHEET_ACCESS_TOKEN");
}

SmartsheetImpl smartsheet = new SmartsheetImpl(baseURI, accessToken, httpClient, jsonSerializer);
SmartsheetImpl smartsheet = new SmartsheetImpl(baseURI, accessToken, httpClient, jsonSerializer, smartsheetIntegrationSource);

if (changeAgent != null) {
smartsheet.setChangeAgent(changeAgent);
Expand Down
21 changes: 12 additions & 9 deletions src/main/java/com/smartsheet/api/SmartsheetFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ public class SmartsheetFactory {

/**
* <p>Creates a Smartsheet client with default parameters. SMARTSHEET_ACCESS_TOKEN
* and SMARTSHEET_INTEGRATION_SOURCE
* must be set in the environment.</p>
*
* @return the Smartsheet client
*/
public static Smartsheet createDefaultClient() {
public static Smartsheet createDefaultClient() throws SmartsheetException {
String accessToken = System.getenv("SMARTSHEET_ACCESS_TOKEN");
SmartsheetImpl smartsheet = new SmartsheetImpl(DEFAULT_BASE_URI, accessToken);
String smartsheetIntegrationSource = System.getenv("SMARTSHEET_INTEGRATION_SOURCE");
SmartsheetImpl smartsheet = new SmartsheetImpl(DEFAULT_BASE_URI, accessToken, smartsheetIntegrationSource);
return smartsheet;
}

Expand All @@ -50,20 +52,21 @@ public static Smartsheet createDefaultClient() {
*
* @return the Smartsheet client
*/
public static Smartsheet createDefaultClient(String accessToken) {
SmartsheetImpl smartsheet = new SmartsheetImpl(DEFAULT_BASE_URI, accessToken);
public static Smartsheet createDefaultClient(String accessToken, String smartsheetIntegrationSource) throws SmartsheetException {
SmartsheetImpl smartsheet = new SmartsheetImpl(DEFAULT_BASE_URI, accessToken, smartsheetIntegrationSource);
return smartsheet;
}

/**
* <p>Creates a Smartsheet client with default parameters using the Smartsheetgov URI.
* SMARTSHEET_ACCESS_TOKEN must be set in the environment.</p>
* SMARTSHEET_ACCESS_TOKEN and SMARTSHEET_INTEGRATION_SOURCE must be set in the environment.</p>
*
* @return the Smartsheet client
*/
public static Smartsheet createDefaultGovAccountClient() {
public static Smartsheet createDefaultGovAccountClient() throws SmartsheetException {
String accessToken = System.getenv("SMARTSHEET_ACCESS_TOKEN");
SmartsheetImpl smartsheet = new SmartsheetImpl(GOV_BASE_URI, accessToken);
String smartsheetIntegrationSource = System.getenv("SMARTSHEET_INTEGRATION_SOURCE");
SmartsheetImpl smartsheet = new SmartsheetImpl(GOV_BASE_URI, accessToken, smartsheetIntegrationSource);
return smartsheet;
}

Expand All @@ -72,8 +75,8 @@ public static Smartsheet createDefaultGovAccountClient() {
*
* @return the Smartsheet client
*/
public static Smartsheet createDefaultGovAccountClient(String accessToken) {
SmartsheetImpl smartsheet = new SmartsheetImpl(GOV_BASE_URI, accessToken);
public static Smartsheet createDefaultGovAccountClient(String accessToken, String smartsheetIntegrationSource) throws SmartsheetException {
SmartsheetImpl smartsheet = new SmartsheetImpl(GOV_BASE_URI, accessToken, smartsheetIntegrationSource);
return smartsheet;
}

Expand Down
11 changes: 8 additions & 3 deletions src/main/java/com/smartsheet/api/internal/AbstractResources.java
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ protected <T, S> List<S> putAndReceiveList(String path, T objectToPut, Class<S>
* @param method the HttpMethod
* @return the http request
*/
protected HttpRequest createHttpRequest(URI uri, HttpMethod method) {
protected HttpRequest createHttpRequest(URI uri, HttpMethod method) throws SmartsheetException {
HttpRequest request = new HttpRequest();
request.setUri(uri);
request.setMethod(method);
Expand All @@ -861,7 +861,7 @@ protected HttpRequest createHttpRequest(URI uri, HttpMethod method) {
return request;
}

protected HttpPost createHttpPost(URI uri) {
protected HttpPost createHttpPost(URI uri) throws SmartsheetException {
HttpPost httpPost = new HttpPost(uri);
Map<String, String> headers = createHeaders();
for (Map.Entry<String, String> entry : headers.entrySet()) {
Expand Down Expand Up @@ -1061,7 +1061,7 @@ private static void copyStream(InputStream input, OutputStream output) throws IO
/**
* @return a map of headers to be used when making requests.
*/
Map<String, String> createHeaders() {
Map<String, String> createHeaders() throws SmartsheetException {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "Bearer " + smartsheet.getAccessToken());
headers.put(HEADER_CONTENT_TYPE, JSON_CONTENT_TYPE);
Expand All @@ -1076,6 +1076,11 @@ Map<String, String> createHeaders() {
if (smartsheet.getUserAgent() != null) {
headers.put("User-Agent", smartsheet.getUserAgent());
}
if (smartsheet.getSmartsheetIntegrationSource() != null) {
headers.put("Smartsheet-Integration-Source", smartsheet.getSmartsheetIntegrationSource());
} else {
throw new SmartsheetException("Smartsheet integration source cannot be null");
}
return headers;
}

Expand Down
63 changes: 39 additions & 24 deletions src/main/java/com/smartsheet/api/internal/SmartsheetImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,15 @@

package com.smartsheet.api.internal;

import com.smartsheet.api.AssetShareResources;
import com.smartsheet.api.ContactResources;
import com.smartsheet.api.EventResources;
import com.smartsheet.api.FavoriteResources;
import com.smartsheet.api.FolderResources;
import com.smartsheet.api.GroupResources;
import com.smartsheet.api.HomeResources;
import com.smartsheet.api.ImageUrlResources;
import com.smartsheet.api.PassthroughResources;
import com.smartsheet.api.ReportResources;
import com.smartsheet.api.SearchResources;
import com.smartsheet.api.ServerInfoResources;
import com.smartsheet.api.SheetResources;
import com.smartsheet.api.SightResources;
import com.smartsheet.api.Smartsheet;
import com.smartsheet.api.TemplateResources;
import com.smartsheet.api.TokenResources;
import com.smartsheet.api.Trace;
import com.smartsheet.api.UserResources;
import com.smartsheet.api.WebhookResources;
import com.smartsheet.api.WorkspaceResources;
import com.smartsheet.api.*;
import com.smartsheet.api.internal.http.AndroidHttpClient;
import com.smartsheet.api.internal.http.DefaultHttpClient;
import com.smartsheet.api.internal.http.HttpClient;
import com.smartsheet.api.internal.json.JacksonJsonSerializer;
import com.smartsheet.api.internal.json.JsonSerializer;
import com.smartsheet.api.internal.util.CleanerUtil;
import com.smartsheet.api.internal.util.Util;
import com.smartsheet.api.internal.util.SmartsheetIntegrationSourceValidator;
import org.apache.http.impl.client.HttpClients;

import java.io.IOException;
Expand Down Expand Up @@ -282,6 +263,18 @@ public class SmartsheetImpl implements Smartsheet {
*/
private final AtomicReference<AssetShareResources> assetShares;

/**
* Represents the AtomicReference for the smartsheet integration source header
*
* Format: $TYPE,$ORG_NAME,$INTEGRATOR_NAME
* (NB: Comma is used as a delimiter and is required if value is missing)
*
* $INTEGRATION-TYPE - Required, the type of the integrator (e.g. AI, SCRIPT, APPLICATION)
* $SMAR-ORGANIZATION-NAME - Optional (but COMMA is required), organization name (e.g. Microsoft, Google, OpenAI, etc.)
* $INTEGRATOR-NAME - Required, the name of the integrator (e.g. Claude, Copilot, ChatGPT, DeepSeek, etc.)
*/
private final AtomicReference<String> smartsheetIntegrationSource;

private static final String INVALID_OPERATION_FOR_CLASS = "Invalid operation for class ";

/**
Expand All @@ -291,9 +284,10 @@ public class SmartsheetImpl implements Smartsheet {
*
* @param baseURI the server uri
* @param accessToken the access token
* @param smartsheetIntegrationSource integration source identifier
*/
public SmartsheetImpl(String baseURI, String accessToken) {
this(baseURI, accessToken, null, null);
public SmartsheetImpl(String baseURI, String accessToken, String smartsheetIntegrationSource) throws SmartsheetException {
this(baseURI, accessToken, null, null, smartsheetIntegrationSource);
}

/**
Expand All @@ -305,8 +299,10 @@ public SmartsheetImpl(String baseURI, String accessToken) {
* @param accessToken the access token
* @param httpClient the http client (optional)
* @param jsonSerializer the json serializer (optional)
* @param smartsheetIntegrationSource integration source identifier
*/
public SmartsheetImpl(String baseURI, String accessToken, HttpClient httpClient, JsonSerializer jsonSerializer) {
public SmartsheetImpl(String baseURI, String accessToken, HttpClient httpClient, JsonSerializer jsonSerializer,
String smartsheetIntegrationSource) throws SmartsheetException {
Util.throwIfNull(baseURI);
Util.throwIfEmpty(baseURI);

Expand Down Expand Up @@ -341,6 +337,8 @@ public SmartsheetImpl(String baseURI, String accessToken, HttpClient httpClient,
this.passthrough = new AtomicReference<>();
this.events = new AtomicReference<>();
this.assetShares = new AtomicReference<>();
SmartsheetIntegrationSourceValidator.isValidFormat(smartsheetIntegrationSource);
this.smartsheetIntegrationSource = new AtomicReference<>(smartsheetIntegrationSource);
}

/**
Expand Down Expand Up @@ -484,6 +482,23 @@ public void setTracePrettyPrint(boolean pretty) {
}
}

/**
* Gets the custom integration source identifier.
*
* This value is intended to be sent as a header in API requests for integration purposes
*
* @return the integration source string.
*/
String getSmartsheetIntegrationSource() {
return smartsheetIntegrationSource.get();
}

public void setSmartsheetIntegrationSource(String smartsheetIntegrationSource) throws SmartsheetException {
if (SmartsheetIntegrationSourceValidator.isValidFormat(smartsheetIntegrationSource)) {
this.smartsheetIntegrationSource.set(smartsheetIntegrationSource);
}
}

/**
* Returns the HomeResources instance that provides access to Home resources.
*
Expand Down
Loading