Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
Diagram illustrating reduced HTTP calls using the Salesforce Composite API for efficient integration.
Integration

Salesforce Composite API - Reduce Latency and API Limits

Stop burning your daily limits on dozens of tiny HTTP calls. Here is how the Salesforce Composite API bundles requests, handles transactions, and makes your integrations far more efficient.

The short answer

The Salesforce Composite API lets developers bundle several REST operations into one HTTP request, which cuts network latency and saves API limits. It supports transactional rollback, record linking through reference identifiers, and separate endpoints for record hierarchies and batch operations.

Key takeaways Bundle several REST calls into one /composite request to cut round-trip latency and conserve daily API limits. Use the referenceId syntax, @{referenceId.id}, in the /composite endpoint to link child records to parent records created in the same payload. Choose /composite/tree for parent-child record trees, /composite/batch for up to 25 independent subrequests, and /composite/sobjects for collections of records of the same type. Set allOrNone to true so a single failed operation rolls back every subrequest in the payload. Standard Salesforce governor limits still apply per transaction, so budget for CPU time, SOQL queries, and DML in your subrequests.

Ever felt like you're killing your org's performance with a hundred tiny HTTP calls? That's where the Salesforce Composite API comes in. I've seen teams struggle with latency and daily limits purely because they were making a separate call for every single record update, and once you start bundling them you wonder how you ever managed without it.

Why you should care about the Salesforce Composite API

The math is simple. Every time your external system talks to Salesforce there's overhead: the handshake, the headers, and the network travel time. If you're doing that 50 times for 50 records, you're wasting resources. The Salesforce Composite API lets you bundle those operations into one single request, so 50 round-trips become one. It's a huge part of building a Salesforce API Integration that actually scales as your data grows.

Transactional control matters as much as speed. If you're creating an Account and a Contact, you probably don't want the Account to exist when the Contact fails. With the right settings, this API handles that "all-or-none" logic for you. Anyone who has worked on REST integrations knows how much of a headache manual rollbacks can be.

A tip: always use the referenceId. It lets you link records together in one go, without waiting for the first call to finish and hand the ID back to your client.

Breaking down the Salesforce Composite API endpoints

Not all composite requests are the same. Salesforce gives us a few different flavors depending on what we're trying to do. Here's the breakdown of what I actually use in the field:

  • /composite: the heavy lifter. You can mix and match different objects and even different methods (like a POST and a PATCH) in one call, and use the ID from the first step in the second step.
  • /composite/batch: think of this as a bucket of unrelated tasks. You can send up to 25 subrequests, but they don't talk to each other, and if one fails the others keep going.
  • /composite/tree/sObjectName: the best way to handle parent-child relationships. You send a nested JSON, and Salesforce builds the whole tree for you in one shot.
  • /composite/sobjects: for those times when you have a bunch of records of the same type. It's a solid way of managing Salesforce large data volumes without moving all the way to the Bulk API.

An architectural diagram illustrating a single API request creating multiple linked parent and child records in a cloud database.

An architectural diagram illustrating a single API request creating multiple linked parent and child records in a cloud database.

Example: Linking an Account and Contact

In my experience, this is the most common use case: you want to create a customer and their primary contact at the same time. Here is how that looks in a standard composite request. Notice how we use the referenceId to link them.


POST /services/data/v60.0/composite
{
  "allOrNone" : true,
  "compositeRequest" : [
    {
      "method" : "POST",
      "url" : "/services/data/v60.0/sobjects/Account",
      "referenceId" : "newAcc",
      "body" : { "Name" : "Cloud Tech Inc" }
    },
    {
      "method" : "POST",
      "url" : "/services/data/v60.0/sobjects/Contact",
      "referenceId" : "newCon",
      "body" : {
        "FirstName" : "Alex",
        "LastName" : "Smith",
        "AccountId" : "@{newAcc.id}"
      }
    }
  ]
}

Salesforce creates the Account first. Then @{newAcc.id} tells the Contact which Account it belongs to, and the system handles the ID mapping internally. No extra code is needed on your end.

Example: Using the Tree resource

If you're doing a deep hierarchy, the Tree resource is even easier. The nesting implies the relationship, so you don't need the @{...} syntax at all. Here's a quick look at that:


POST /services/data/v60.0/composite/tree/Account
{
  "records" : [
    {
      "attributes" : { "type" : "Account", "referenceId" : "ref1" },
      "Name" : "Global Corp",
      "Contacts" : {
        "records" : [
          { "attributes" : { "type" : "Contact", "referenceId" : "con1" }, "FirstName" : "Sarah", "LastName" : "Connor" }
        ]
      }
    }
  ]
}

Things that might trip you up

One HTTP request does not mean you've escaped governor limits. People treat this as a "get out of jail free" card for SOQL or DML limits, and it isn't one. Each subrequest still counts against your transaction limits. If your triggers are heavy, you can still hit CPU timeouts.

Error handling also gets a bit more interesting. When you use allOrNone=true, the whole thing rolls back if one piece fails. That's great for data integrity, and your error parsing logic needs to be ready for it. You'll get a response body that tells you exactly which subrequest failed and why, so don't stop at a 200 OK status: look at the status of each item in the results array.

Key takeaways

  • The Salesforce Composite API cuts network latency by bundling calls.
  • Use /composite when you need to link different objects using referenceId.
  • Use /composite/tree for simple parent-child record creation.
  • Remember that governor limits (CPU, DML, SOQL) still apply to every subrequest.
  • Set allOrNone to true if you need the entire batch to succeed or fail together.

Start by identifying your most chatty integrations. If you see a pattern of creating a parent and then immediately creating children, that's your first candidate for a rewrite. It'll save your API limits and make your external systems feel much faster. Building the JSON payload takes a little more effort, and the performance gains are worth it every single time.

Frequently asked questions

How do you link records in a Salesforce Composite API request?

Give the parent record's creation subrequest a referenceId, then point the child subrequests at its generated ID with the @{referenceId.id} syntax. Salesforce resolves the ID mapping internally while it runs the request.

What is the difference between /composite and /composite/batch?

Subrequests in /composite can pass data along and link records with referenceId. /composite/batch runs up to 25 independent subrequests that never communicate or share data with each other.

Do Salesforce governor limits apply to Composite API requests?

Yes. Every subrequest in a composite payload still counts against the platform transaction limits, including CPU timeouts, SOQL queries, and DML limits.

How do you handle rollbacks in Salesforce Composite API?

Set the allOrNone property to true in the request body. If any subrequest fails, Salesforce rolls back the whole set of operations and returns error details for each subrequest in the response payload.

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