Struggling with multiple API calls for a simple task and hitting API limits? Still making individual API calls for multiple related operations? Fortunately, the Salesforce Composite API provides a powerful solution — it allows you to execute multiple REST API requests in a single call, optimizing both API usage and performance.
Understanding Salesforce REST API
Salesforce REST API allows external applications to interact with Salesforce using HTTP methods like GET, POST, PATCH, and DELETE. It streamlines CRUD operations, making integrations simpler and more efficient.
Types of Salesforce REST API :
- Standard REST API: For basic record operations.
- Bulk API: Designed for efficiently processing large data volumes in an asynchronous manner.
- Composite API: To execute multiple REST API requests within a single call.
In this blog, we focus on the Composite API, which allows creating records along with file attachments efficiently in a single API request. However, you might wonder why we chose Composite API over the Standard REST API for this use case. Let’s explore the key differences and advantages.
Why Use Composite API Instead of Standard REST API?
When creating a record with an attached file in Salesforce, you have two primary REST API options: Standard REST API and Composite REST API. While the Standard REST API works well for basic operations, it has limitations that make the Composite API a more efficient and powerful choice.
Challenges with Standard REST API
- Multiple API Calls Required
- At least three separate API calls are needed:
- Create the parent record (e.g., a Case or Custom Object record).
- Upload the file as a ContentVersion record.
- Establish the relationship between the file and the parent record using the ContentDocumentLink object.
- This increases network overhead, making the process slower and less efficient.
- At least three separate API calls are needed:
- API Limits Consumption
- Each API call consumes Salesforce’s API limits. With the Standard REST API, multiple calls are needed, which can quickly exhaust your daily quota.
- Risk of Partial Data Creation
- If any API call fails (e.g., the file upload fails after record creation), the data remains incomplete and may require manual cleanup.
How Composite API Solves These Issues
✔ Single API Call for Multiple Actions
- The Composite API allows creating a record and attaching a file in one single request, reducing network overhead.
✔ Reduced API Limit Consumption
- Since multiple operations are executed in one call, it significantly reduces API consumption, making it ideal for bulk operations.
✔ Atomic Transactions (All or Nothing Execution)
- The Composite API ensures that either all operations succeed or none do. If any step fails, Salesforce rolls back the entire transaction, preventing partial data creation.
✔ Faster Execution
- By eliminating multiple API round trips, Composite API improves performance and enhances the user experience.
Practical Implementation: Creating a Record with File Using Composite API
Now that we understand why Composite API is the best choice, let’s walk through the step-by-step implementation.
Step 1 : Create a Connected App
Before making API calls, you need to set up a Connected App in your Salesforce Sandbox to enable external authentication.
- Navigate to Setup → App Manager → New Connected App.
- Provide a name (e.g., CompositeAPI_App).
- Enable OAuth settings and add the callback URL (https://login.salesforce.com/services/oauth2/callback).
- Select the necessary OAuth Scopes, including:
- Full Access (full)
- Perform requests on your behalf at any time (refresh_token, offline_access)
- Click Save and then copy the Consumer Key and Consumer Secret.
Step 2 : Get Access Token & Instance URL
To authenticate API requests, you need to obtain an OAuth access token using a cURL command.
Authorization Request (cURL) :
curl –location –request POST ‘{{authentication_url}}/services/oauth2/token?grant_type=password&client_id={{client_id}}&client_secret={{client_secret}}&username={{username}}&password={{password}}’ \
Expected Response :
{
"access_token": "00D5g00000XXXXXX!ABC...",
"instance_url": "https://your-instance.salesforce.com",
"id": "https://login.salesforce.com/id/00D5j00000.../0055j00000...",
"token_type": "Bearer",
"issued_at": "1738251188276",
"signature": "WFDqEU1GlDTDTBFtaMTz..."
}
Copy the access_token and instance_url because you’ll need them for the next step.
Step 3 : Create a Case with Attachment
Now, using the access_token from the previous step, we can create a Case record and attach a file using Composite API.
Case Creation with Attachment (cURL) :
curl --location '{{instance_url}}/services/data/v59.0/composite' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{access_token}}' \
--data-raw '{
"allOrNone": false,
"compositeRequest": [
{
"method": "POST",
"url": "/services/data/v59.0/sobjects/Case",
"referenceId": "refCase",
"body": {
"SuppliedEmail": "test@example.com",
"SuppliedName": "Test User",
"Subject": "Composite API Image Attachment Test",
"Description": "Case with Text File",
"Priority": "High",
"Origin": "Web"
}
},
{
"method": "POST",
"url": "/services/data/v59.0/sobjects/ContentVersion",
"referenceId": "refContentVersion",
"body": {
"PathOnClient": "Sample Text.txt",
"Title": "Sample Text",
"VersionData": "VGVzdCBGaWxl"
}
},
{
"method": "GET",
"url": "/services/data/v59.0/query/?q=SELECT+ContentDocumentId+FROM+ContentVersion+WHERE+Id='\''@{refContentVersion.id}'\''",
"referenceId": "refContentDocument"
},
{
"method": "POST",
"url": "/services/data/v59.0/sobjects/ContentDocumentLink",
"referenceId": "refContentDocumentLink",
"body": {
"LinkedEntityId": "@{refCase.id}",
"ContentDocumentId": "@{refContentDocument.records[0].ContentDocumentId}",
"ShareType": "I",
"Visibility": "AllUsers"
}
}
]
}
Expected Response :
{
"compositeResponse": [
{
"body": {
"id": "500J40000095UCCIA2",
"success": true,
"errors": []
},
"httpHeaders": {
"Location": "/services/data/v59.0/sobjects/Case/500J40000095UCCIA2"
},
"httpStatusCode": 201,
"referenceId": "refCase"
},
{
"body": {
"id": "068J4000008AHDpIAO",
"success": true,
"errors": []
},
"httpHeaders": {
"Location": "/services/data/v59.0/sobjects/ContentVersion/068J4000008AHDpIAO"
},
"httpStatusCode": 201,
"referenceId": "refContentVersion"
},
{
"body": {
"totalSize": 1,
"done": true,
"records": [
{
"attributes": {
"type": "ContentVersion",
"url": "/services/data/v59.0/sobjects/ContentVersion/068J4000008AHDpIAO"
},
"ContentDocumentId": "069J40000089iRVIAY"
}
]
},
"httpHeaders": {},
"httpStatusCode": 200,
"referenceId": "refContentDocument"
},
{
"body": {
"id": "06AJ400000B8l5iMAB",
"success": true,
"errors": []
},
"httpHeaders": {
"Location": "/services/data/v59.0/sobjects/ContentDocumentLink/06AJ400000B8l5iMAB"
},
"httpStatusCode": 201,
"referenceId": "refContentDocumentLink"
}
]
}
This example demonstrates using the Salesforce Composite API to create a Case record and associate it with a file attachment. Depending on your business requirements, the Composite API can handle any standard or custom object, allowing you to create and relate objects with attachments in a single API call. It’s ideal for bulk operations and complex workflows, enabling businesses to manage records and attachments efficiently at scale.
NOTE: Remember that When a document is uploaded or downloaded via the API, it (VersionData) should be base64 encoded (for upload) or decoded (for download).
How to Create Different Types of Attachments :
You can attach various file types, when creating attachments, use the following file types and their respective extensions in the file path: JPG (.jpg), JPEG (.jpeg), PNG (.png), GIF (.gif), SVG (.svg), and PDF (.pdf).
Conclusion
By using Salesforce Composite API, we successfully created a Case record and attached a file in one single API request. This approach is efficient, reduces API consumption, and ensures data integrity.
You can now use this method in your integration projects to simplify Salesforce record creation with file attachments!