Skip to Content
Technical Articles
Author's profile photo Mustafa Saglam

Optimizing your C4C OData interface for throughput

Dear C4Cers,

Writing this blog has been in my bucket list for a long time now… Thanks to a recent inquiry, finally, I had the opportunity to put my ideas into words.

While some of the best practices shared below are specific to C4C OData API, majority also apply to other OData APIs. Thus, I hope they will help some of you in building high-performing OData interfaces.

Furthermore, I would really appreciate it, if you could contribute to this blog with your comments by sharing your own tips and tricks. Thanks in advance for that.

With that here are a few best practices that can be used to optimize an SAP Sales and Service Cloud (C4C) OData interface for better throughput.

Reduced number of round-trips

This is achieved by using batch requests ($batch) with the optimum batch size. Considerations here are;

  • Number of requests in a change-set: All requests in a change-set are committed together. Hence, if one fails, all will be rolled back!
    • The higher the number of requests in a change-set, the higher will be the throughput. Maximum number of requests in a change-set cannot be higher than the number of requests in a batch. Hence, see batch size recommendations below for determining ideal number of requests in a change-set for your interface.
    • Quality of the data is critical as errors will require other requests with correct data to be reprocessed. Note that such a retry-logic will need be implemented by your interface!
    • Related data must be kept in the same change-set. E.g. Updating Opportunity header and Items. This ensures transactional consistency.
  • Batch size: Optimum batch size depends on several factors – object type, payload size, customization etc.. Optimum batch size for your interface can be determined by trying different values. Our recommendation is to start your tests with 10 requests per batch for deep inserts and 50 requests per batch for simple inserts or updates and determine the best batch size based on the actual throughput figures.

Parallelization of the requests

OData API can be consumed via parallel threads. Considerations:

  • A unique object record cannot be updated by two threads at the same time. Trying to do so will result in “record locked by user …” errors.
  • To ensure system’s availability for all users, the number of parallel threads in an interface should be limited. Therefore, we recommend that in a tenant the number of parallel threads making API calls should be less than 10 (total for all interfaces running in parallel). Furthermore, if such an interface(s) will run for a long time, the total number of threads should even be smaller (<7).
  • Optimum number can be determined (by testing) based on the API, customizations in the tenant and the request details.

Optimizing individual requests

Modifying calls

  • Create operations should use deep-inserts where possible.
  • Create calls should suppress create response so that it doesn’t include created entity record where possible. This is achieved using odata-no-response-payload header.
  • Updates should be based on HTTP PATCH operation and include only changed fields – where possible.

Query/Read calls

  • HTTP GET operations should only fetch the data required using $select query option.
  • Use of $expand query option should be avoided as much as possible. If used, it should be complemented with a $select query option.
  • HTTP GET operations can further be optimized by preventing to return code-list descriptions. Therefore, whenever possible HTTP GET operations should make use the of the header odata-no-codedescs.
  • Server and/or Client based pagination can be used for speeding up queries.
  • If needed, CSRF-Token should be fetched with an efficient (sub-second response time) GET call. E.g.
    • Better yet, avoid the need for CSRF token by using a technical user or using OAuth for principle propagation.
    • Reading metadata (e.g. …/c4codataapi/$metadata) or the service document (e.g. …/c4codataapi/) for fetching CSRF token should be avoided as these calls are quite expensive due to the size of the response payload.


Thanks for reading this far! 😉



Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Markus Reetz-Lamour
      Markus Reetz-Lamour

      Dear Mustafa,

      you state that in $batch requests the error handling logic is "all or nothing". What if the header attribute "prefer" is set to ‘odata.continue-on-error’. Shouldn't this change the logic to "as much as possible"?

      Thx and BR,


      Author's profile photo Mustafa Saglam
      Mustafa Saglam
      Blog Post Author

      Hi Markus,

      I stated that requests within a change-set are committed or rolled-back together. Not for the whole batch. In other words, in the same batch call, while a group of requests can be rolled back due to a failure of an individual request within that group, this will not impact the requests in other change-sets.

      Furthermore, my recommendations in this blog are specifically for C4C OData API which is OData V2 Compliant. Since the prefer header is a feature of OData V4, it is not supported by C4C OData API today.


      Author's profile photo Ricardo chen
      Ricardo chen

      Hi Mustafa,

      Thanks for your useful blog post.  I have a challenge regarding saving data in bulk to C4C Survey.  Hope you can shine some more light, here are the details:

      Business case:
      We need to save 1 answer of about 150 products in a survey during a visit.

      This is our current inefficient approach:
      ● Get the Survey Response Items (products) for the current survey/visit
      ○ GET:

      ● One by one, for each response item, create the answer (This will throw user locked error if tried in parallel)
      ○ POST

      ● IF previous POST fails, get the existing answer object id:
      ○ GET:

      ● Update existing answer:


      As you can imagine, this takes about 1 second per answer per product, making it about almost
      3 minutes per saving in case of an empty survey (no previous answers). If there are previous
      answers it goes over 5 minutes per saving making it very frustrating for the user.

      We tried $batch as mentioned in the C4C oData documentation

      However, after receiving response 202, we do not see any changes in the survey. Also if any of
      those answers are existing, it will all roll back anyways.

      What should be the “right way” to save this information to C4C?

      Is there any $batch with upsert?