multipart/form-data. A boundary is a unique text divider placed between each piece of data so the receiving server knows where one file ends and the next form field begins.
In Salesforce development, integrating with external REST APIs to upload files or documents is a frequent requirement. When the target API expects a file payload combined with metadata, simple JSON strings won't cut it. You need to construct a multipart HTTP request.
Let's dive into how multipart data and boundary strings work under the hood, and look at a clean Apex implementation for handling file uploads.
1. Understanding Multipart Data and Boundaries
A multipart HTTP request splits the body into multiple distinct sections, separated by a unique string called a boundary.
- The Content-Type Header: When sending multipart data, your HTTP header must specify the boundary token, like this:
Content-Type: multipart/form-data; boundary=---BOUNDARY---12345 - The Boundary String: This string must be completely unique so that it never accidentally appears inside the actual binary content of your file.
- Request Body Structure: Every section starts with
--boundary, followed by headers likeContent-Disposition, a blank line, the actual data, and a final closing boundary ending with--boundary--.
2. Apex Implementation Example
Here is a complete, reusable Apex class that constructs a multipart HTTP request to upload a file (Blob) as a ContentVersion object.
public class MultipartUploader {
public void uploadFile(Blob fileBlob, String fileName) {
// 1. Generate a unique boundary string using a timestamp
String boundary = '---BOUNDARY---' + DateTime.now().getTime();
String contentType = 'multipart/form-data; boundary=' + boundary;
// 2. Set up the HTTP Request
HttpRequest req = new HttpRequest();
req.setEndpoint('https://your-salesforce-instance.com/services/data/v58.0/sobjects/ContentVersion');
req.setHeader('Content-Type', contentType);
req.setHeader('Authorization', 'Bearer YOUR_ACCESS_TOKEN');
req.setMethod('POST');
// 3. Construct the multipart body string
String body = '';
// Part 1: The File Data
body += '--' + boundary + '\r\n';
body += 'Content-Disposition: form-data; name="file"; filename="' + fileName + '"\r\n';
body += 'Content-Type: application/octet-stream\r\n\r\n';
body += EncodingUtil.base64Encode(fileBlob) + '\r\n';
// Closing boundary
body += '--' + boundary + '--';
req.setBody(body);
// 4. Send the request
Http http = new Http();
HttpResponse res = http.send(req);
if (res.getStatusCode() == 201) {
System.debug('File uploaded successfully!');
} else {
System.debug('File upload failed. Error: ' + res.getBody());
}
}
}
Multipart HTTP specifications strictly require Windows-style line breaks (
\r\n) between headers and body segments. If you omit the \r\n characters or accidentally use standard Linux line breaks (\n), the receiving server will reject the payload with a 400 Bad Request error.
- Boundary Generation: We create a random token combined with the current millisecond epoch time.
- Content-Disposition: We declare the field name (
name="file") and the original file name. - Base64 Encoding: Because binary blobs cannot be concatenated directly into a raw text string without breaking characters, we encode the file blob into Base64 format.
- Endpoint Security: Ensure your external endpoint is registered in Remote Site Settings or configured via Named Credentials.
- Payload Limits: Keep file sizes in mind; syncing massive binary files via synchronous Apex callouts can easily hit heap size limits. For large files, use chunked uploads or LWC client-side integrations.
\r\n line endings.
Conclusion
Handling multipart data and boundary strings gives you the low-level control required to interface with complex REST APIs directly from Salesforce backend code. By properly structuring your headers, wrapping your binary content in Base64 encoding, and separating segments with unique boundaries, you can successfully transmit files and form data in a single transactional request.