Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
A 3D rendering showing the Box.com Salesforce integration concept with cloud and folder icons.
Apex

Box.com Salesforce Integration: Apex Backend Guide

Master the complexities of integrating Salesforce with Box.com using Apex. This guide covers secure authentication, file upload patterns, and error handling.

The short answer

This guide explains how to build a custom backend integration between Salesforce and Box.com using Apex and the Box REST API. It covers OAuth 2.0 JWT authentication, multipart file uploads, asynchronous processing, and API error handling.

Key takeaways Authenticate server-to-server Box API requests headlessly using OAuth 2.0 JWT assertions signed with Crypto.sign(). Store Box private keys securely in Custom Metadata Types or encrypted fields, and configure Named Credentials for API endpoints. Construct multipart/form-data HttpRequest bodies with unique boundary strings to upload file metadata and binary content to Box folders. Execute Box API callouts asynchronously using Queueable Apex with Database.AllowsCallouts to stay within governor limits and support retries. Capture the X-Box-Request-Id header and log API response errors to troubleshoot rate limits, missing folders, and expired tokens.

Introduction

Integrating Salesforce with Box.com is a common requirement for organizations looking to offload file storage while maintaining a seamless user experience within the CRM. While managed packages exist, building a custom backend integration using Apex provides the granular control, performance optimization, and custom logic necessary for enterprise-scale operations. In this guide, we'll explore how to architect a custom integration using the Box REST API.

Establishing Secure Connectivity with OAuth 2.0

The foundation of any backend integration is authentication. Box uses OAuth 2.0. In a server-to-server or app-user scenario, we typically use JWT (JSON Web Token) authentication to avoid manual user login prompts.

First, you must create a Custom App in the Box Developer Console, configure the public/private key pair, and add the App Service Account to your target Box folder. In Salesforce, you need to store your Private Key securely in a Custom Metadata Type or an encrypted field.

To initiate the flow, use a service class to generate a JWT assertion, sign it using Crypto.sign(), and exchange it for an access token:

public class BoxAuthService {
    private static final String BOX_TOKEN_URL = 'https://api.box.com/oauth2/token';

    public static String getAccessToken() {
        // Generate JWT assertion here...
        // Prepare request body for OAuth exchange
        HttpRequest req = new HttpRequest();
        req.setEndpoint(BOX_TOKEN_URL);
        req.setMethod('POST');
        req.setBody('grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=' + assertion + ...);
        
        Http http = new Http();
        HTTPResponse res = http.send(req);
        // Parse JSON response to extract access_token
        return token;
    }
}

Implementing File Uploads via Apex REST

Once authorized, the most frequent use case is uploading Salesforce files or attachments to Box. Box expects a multipart/form-data request for file uploads. This is often the most challenging part for developers due to the complexity of building the boundary string.

We recommend building a helper method to construct the request body. Ensure your Named Credential is configured for api.box.com to manage endpoints cleanly.

public static void uploadFileToBox(String fileName, Blob fileContent, String folderId) {
    String boundary = '--------------------------' + String.valueOf(Crypto.getRandomInteger());
    String body = '--' + boundary + '\r\n' +
        'Content-Disposition: form-data; name="attributes"; filename="' + fileName + '"\r\n' +
        'Content-Type: application/json\r\n\r\n' +
        '{"name":"' + fileName + '", "parent":{"id":"' + folderId + '"}}\r\n' +
        '--' + boundary + '\r\n' +
        'Content-Disposition: form-data; name="file"; filename="' + fileName + '"\r\n' +
        'Content-Type: application/octet-stream\r\n\r\n';
    
    // Append binary file content and closing boundary...
}

Handling Asynchronous Operations

Salesforce governor limits on heap size and callout counts make synchronous file processing risky for large files. Always offload your Box integrations to Queueable Apex. This allows you to retry failed requests and ensures that the user interface remains responsive.

Here is a pattern for an asynchronous file uploader:

public class BoxUploadQueueable implements Queueable, Database.AllowsCallouts {
    private Id contentVersionId;

    public BoxUploadQueueable(Id cvId) { this.contentVersionId = cvId; }

    public void execute(QueueableContext qc) {
        ContentVersion cv = [SELECT Title, VersionData FROM ContentVersion WHERE Id = :contentVersionId];
        // Perform Box API Callout
        // Handle 429 (Rate Limit) errors with a retry policy
    }
}

Monitoring and Error Handling

Integration failure is inevitable. Implementing a robust logging framework is critical for debugging Box API errors. We suggest capturing the X-Box-Request-Id header from every response. If an upload fails, log the response body and the request ID to a custom Integration_Log__c object.

  • 401 Unauthorized: Refresh your JWT token and retry.
  • 429 Too Many Requests: Implement a Retry-After header check.
  • 404 Not Found: Validate the parent folderId exists before proceeding.

Key Takeaways

  • Authentication: Use JWT authentication for server-side integration to ensure headless, secure connectivity.
  • Multipart/Form-Data: Carefully construct the multipart boundary when performing file uploads via HttpRequest.
  • Scalability: Always use Queueable Apex for callouts to respect governor limits and allow for asynchronous retries.
  • Security: Never hardcode credentials; use Named Credentials and Custom Metadata or Encrypted Fields for sensitive keys.
  • Monitoring: Log specific Box Request IDs to simplify troubleshooting when the API returns an error.

Frequently asked questions

How do you authenticate Salesforce to Box using Apex without user login prompts?

Configure a Custom App in Box with a public/private key pair and grant its App Service Account access to the target Box folder. In Apex, generate a JWT assertion, sign it using Crypto.sign(), and exchange it for an access token via an HTTP POST request to the Box OAuth token endpoint.

How do you upload a file to Box from Salesforce Apex?

Send an HTTP POST request formatted as multipart/form-data with a defined boundary string. The body must include JSON attributes specifying the file name and parent folder ID, followed by the binary file content as an octet-stream.

Why should Box file uploads use Queueable Apex instead of synchronous execution?

Synchronous file processing risks hitting Salesforce governor limits on heap size and callout counts during large uploads. Offloading uploads to Queueable Apex with Database.AllowsCallouts keeps the UI responsive and enables custom retry logic for failed requests.

How should Box API errors and rate limits be handled in Apex?

Capture the X-Box-Request-Id header and log failure details to a custom object. For 401 errors, refresh the JWT access token; for 429 rate limit errors, check the Retry-After header; and for 404 errors, verify the parent folder ID before retrying.

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment