- Introduction
- Migration at a glance
- Key API differences
- Authentication
- Configuration
- Convenience methods
Version availability:
- v5: ships only
BoxSDKmodule - v6: ships both
BoxSDKandBoxSdkGenmodules (side-by-side) - v10+: ships only
BoxSdkGenmodule
This document focuses on helping you migrate code from the legacy BoxSDK module to the generated BoxSdkGen module. Many APIs were redesigned for consistency and modern Swift patterns, so this guide calls out how to adopt the new shapes safely and incrementally.
Supported migration paths:
- v5 → v6: adopt
BoxSdkGengradually while legacy code still usesBoxSDK - v5 → v10+: migrate directly to
BoxSdkGenonly - v6 (within the same app): move usage from
BoxSDKtoBoxSdkGenfile-by-file
For comprehensive API docs with sample code for all methods, see the repository documentation in the root docs directory: docs/.
Recommended direction: use BoxSdkGen going forward. Because it is auto-generated from the Box OpenAPI specification, it:
- Provides first-class async/await support across the API surface
- Uses consistent method signatures with grouped parameters (path, body, query, headers)
- Ships new features and fixes faster and with higher parity with the Box API
- Offers richer convenience methods (for example, chunked uploads)
- Improves type-safety and long-term maintainability
- Teams with existing code using
BoxSDKwho want to start callingBoxSdkGenAPIs. - Teams already on an SDK release that provides both modules and want to transition usage from
BoxSDKtoBoxSdkGenwithin the same app.
- Replace
import BoxSDKwithimport BoxSdkGenin files you’re migrating. - Convert callback-based code to async/await.
- Update method calls to the new, consistent signatures that group parameters by path, body, query and headers.
- For OAuth or CCG, interact with tokens via the auth instance (
BoxOAuth/BoxCCGAuth) instead of the client.
This section compares the manually-maintained BoxSDK module with the generated BoxSdkGen module so you can quickly adopt the new APIs.
- BoxSDK:
import BoxSDK- BoxSdkGen:
import BoxSdkGenUsing different import statements lets you transition file-by-file.
BoxSdkGen adopts async/await for all API methods.
- BoxSDK (callback-based):
import BoxSDK
client.users.getCurrent(fields: ["name", "login"]) { result in
guard case let .success(user) = result else {
print("Error getting user information")
return
}
print("Authenticated as \(user.name), with login \(user.login)")
}- BoxSdkGen (async/await):
import BoxSdkGen
let user = try await client.users.getUserMe()To make the API easier to use, BoxSdkGen groups parameters by their nature (path, body, query, headers).
- BoxSDK (many parameters):
import BoxSDK
public func update(
fileId: String,
name: String? = nil,
description: String? = nil,
parentId: String? = nil,
sharedLink: NullableParameter<SharedLinkData>? = nil,
tags: [String]? = nil,
collections: [String]? = nil,
lock: NullableParameter<LockData>? = nil,
dispositionAt: Date? = nil,
ifMatch: String? = nil,
fields: [String]? = nil,
completion: @escaping Callback<File>
)- BoxSdkGen (grouped arguments):
import BoxSdkGen
public func updateFileById(
fileId: String,
requestBody: UpdateFileByIdRequestBodyArg = UpdateFileByIdRequestBodyArg(),
queryParams: UpdateFileByIdQueryParamsArg = UpdateFileByIdQueryParamsArg(),
headers: UpdateFileByIdHeadersArg = UpdateFileByIdHeadersArg()
) async throws -> FileFullAuthentication is a crucial aspect of any SDK. Below are the differences in usage between BoxSDK and BoxSdkGen:
- BoxSDK:
import BoxSDK
let client = BoxSDK.getClient(token: "YOUR_DEVELOPER_TOKEN")- BoxSdkGen:
import BoxSdkGen
let auth = BoxDeveloperTokenAuth(token: "YOUR_DEVELOPER_TOKEN")
let client = BoxClient(auth: auth)- BoxSDK:
import BoxSDK
let sdk = BoxSDK(clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET")
let client = try await sdk.getCCGClientForAccountService(enterpriseId: "YOUR_ENTERPRISE_ID")- BoxSdkGen:
import BoxSdkGen
let config = CCGConfig(
clientId: "YOUR_CLIENT_ID",
clientSecret: "YOUR_CLIENT_SECRET",
enterpriseId: "YOUR_ENTERPRISE_ID"
)
let auth = BoxCCGAuth(config: config)
let client = BoxClient(auth: auth)- BoxSDK:
import BoxSDK
let sdk = BoxSDK(clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET")
let client = try await sdk.getCCGClientForUser(userId: "YOUR_USER_ID")- BoxSdkGen:
import BoxSdkGen
let config = CCGConfig(
clientId: "YOUR_CLIENT_ID",
clientSecret: "YOUR_CLIENT_SECRET",
userId: "YOUR_USER_ID"
)
let auth = BoxCCGAuth(config: config)
let client = BoxClient(auth: auth)- BoxSdkGen:
import BoxSdkGen
auth.asEnterprise(enterpriseId: "YOUR_ENTERPRISE_ID")Using an auth code is a common way of authenticating with the Box API for existing Box users.
- BoxSDK:
import BoxSDK
let sdk = BoxSDK(clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET", callbackURL: "YOUR_REDIRECT_URL")
let client = try await sdk.getOAuth2Client(tokenStore: KeychainTokenStore())- BoxSdkGen:
import BoxSdkGen
let config = OAuthConfig(clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET", tokenStorage: KeychainTokenStorage())
let oauth = BoxOAuth(config: config)
try await oauth.runLoginFlow(options: AuthorizeUrlParams(redirectUri: "YOUR_REDIRECT_URL"), context: self)
let client = BoxClient(auth: oauth)- BoxSdkGen:
import BoxSdkGen
let config = OAuthConfig(clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET")
let oauth = BoxOAuth(config: config)
let authorizationUrl = oauth.getAuthorizeUrl()After the redirect with an authorization code:
import BoxSdkGen
try await oauth.getTokensAuthorizationCodeGrant(authorizationCode: "YOUR_AUTHORIZATION_CODE")
let client = BoxClient(auth: oauth)Both modules allow you to provide custom token storage on AuthConfig, but the APIs differ.
- BoxSDK (callbacks):
import BoxSDK
public class MyCustomTokenStore: TokenStore {
public func read(completion: @escaping (Result<TokenInfo, Error>) -> Void) {
// YOUR IMPLEMENTATION GOES HERE
}
public func write(tokenInfo: TokenInfo, completion: @escaping (Result<Void, Error>) -> Void) {
// YOUR IMPLEMENTATION GOES HERE
}
public func clear(completion: @escaping (Result<Void, Error>) -> Void) {
// YOUR IMPLEMENTATION GOES HERE
}
}- BoxSdkGen (async/await):
import BoxSdkGen
public class MyCustomTokenStore: TokenStorage {
public func store(token: AccessToken) async throws {
// YOUR IMPLEMENTATION GOES HERE
}
public func get() async throws -> AccessToken? {
// YOUR IMPLEMENTATION GOES HERE
}
public func clear() async throws {
// YOUR IMPLEMENTATION GOES HERE
}
}
let tokenStorage = MyCustomTokenStore();
let config = OAuthConfig(clientId: "YOUR_CLIENT_ID", clientSecret: "YOUR_CLIENT_SECRET", tokenStorage: tokenStorage);Downscoping exchanges an existing Access Token for a new one that is more restricted.
- BoxSDK:
import BoxSDK
client.exchangeToken(scope: ["item_preview"], resource: "https://api.box.com/2.0/files/123456789") { result in
guard case let .success(tokenInfo) = result else {
print("Error exchanging tokens")
return
}
print("Got new access token: \(tokenInfo.accessToken)")
}- BoxSdkGen:
import BoxSdkGen
let accessToken: AccessToken = try await auth.downscopeToken(scopes: ["item_preview"], resource: "https://api.box.com/2.0/files/123456789")- BoxSDK:
import BoxSDK
client.destroy() { result in
guard case .success = result else {
print("Tokens could not be revoked!")
return
}
print("Tokens were successfully revoked")
}- BoxSdkGen:
import BoxSdkGen
try await auth.revokeToken()The As-User header is used by enterprise admins to make API calls on behalf of their enterprise's users.
This requires the API request to pass an As-User: USER-ID header. The following examples assume that the client has
been instantiated with an access token with appropriate privileges to make As-User calls.
- BoxSDK:
import BoxSDK
let asUserClient = client.asUser(withId: "<USER_ID>")- BoxSdkGen:
import BoxSdkGen
let userClient: BoxClient = client.withAsUserHeader(userId: "<USER_ID>")- BoxSDK:
import BoxSDK
do {
try sdk.updateConfiguration(
apiBaseURL: URL(string: "https://my-company.com"),
uploadApiBaseURL: URL(string: "https://my-company.com/upload"),
oauth2AuthorizeURL: URL(string: "https://my-company.com/oauth2")
)
} catch {
print("An error occurred \(error)")
}- BoxSdkGen:
import BoxSdkGen
let newClient = client.withCustomBaseUrls(baseUrls: BaseUrls(
baseUrl: "https://api.box.com",
uploadUrl: "https://upload.box.com/api",
oauth2Url: "https://account.box.com/api/oauth2"
))You can specify a custom set of headers included in every API call made by the client.
import BoxSdkGen
let clientWithHeaders: BoxClient = client.withExtraHeaders(extraHeaders: ["my-custom-header": "my-custom-value"])For large files or unreliable networks, you may want to upload the file in parts. This allows a single part to fail without aborting the entire upload, and failed parts are retried automatically.
- BoxSDK (manual multi-call flow)
- BoxSdkGen (single API):
import BoxSdkGen
guard let fileByteStream = InputStream(url: URL(string: "<URL_TO_YOUR_FILE>")!) else {
fatalError("Could not read a file")
}
let fileName = "<NAME_OF_YOUR_FILE>";
let parentFolderId = "<FOLDER_ID_WHERE_FILE_WILL_BE_UPLOADED>";
let fileSize: Int64 = <SIZE_OF_YOUR_FILE_IN_BYTES>;
try await client.chunkedUploads.uploadBigFile(
file: fileByteStream,
fileName: fileName,
fileSize: Int64(fileSize),
parentFolderId: parentFolderId
)