[[salesforce-component]]
= Salesforce Component
:docTitle: Salesforce
:shortname: salesforce
:artifactId: camel-salesforce
:description: Communicate with Salesforce using Java DTOs.
:since: 2.12
:supportLevel: Stable
:component-header: Both producer and consumer are supported
//Manually maintained attributes
:camel-spring-boot-name: salesforce

*Since Camel {since}*

*{component-header}*

This component supports producer and consumer endpoints to communicate
with Salesforce using Java DTOs.  +
 There is a companion maven plugin Camel Salesforce Plugin that
generates these DTOs (see further below).

Maven users will need to add the following dependency to their `pom.xml`
for this component:

[source,xml]
----
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-salesforce</artifactId>
    <version>x.x.x</version>
    <!-- use the same version as your Camel core version -->
</dependency>
----

[NOTE]
====
Developers wishing to contribute to the component are instructed
to look at the https://github.com/apache/camel/tree/main/components/camel-salesforce/camel-salesforce-component/README.md[README.md] file on instructions on how to get started and
setup your environment for running integration tests.
====

== Authenticating to Salesforce

The component supports three OAuth authentication flows:

* https://help.salesforce.com/articleView?id=remoteaccess_oauth_username_password_flow.htm[OAuth 2.0 Username-Password Flow]
* https://help.salesforce.com/articleView?id=remoteaccess_oauth_refresh_token_flow.htm[OAuth 2.0 Refresh Token Flow]
* https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm[OAuth 2.0 JWT Bearer Token Flow]

For each of the flow different set of properties needs to be set:

.Properties to set for each authentication flow
|===
| Property     | Where to find it on Salesforce     | Flow

| clientId     | Connected App, Consumer Key        | All flows
| clientSecret | Connected App, Consumer Secret     | Username-Password, Refresh Token
| userName     | Salesforce user username           | Username-Password, JWT Bearer Token
| password     | Salesforce user password           | Username-Password
| refreshToken | From OAuth flow callback           | Refresh Token
| keystore     | Connected App, Digital Certificate | JWT Bearer Token
|===

The component auto determines what flow you're trying to configure, to
be remove ambiguity set the `authenticationType` property.

[NOTE]
====
Using Username-Password Flow in production is not encouraged.
====

[NOTE]
====
The certificate used in JWT Bearer Token Flow can be a selfsigned 
certificate. The KeyStore holding the certificate and the private key
must contain only single certificate-private key entry.
====

== URI format

When used as a consumer, receiving streaming events, the URI scheme is:

[source,java]
----
salesforce:topic?options
----

When used as a producer, invoking the Salesforce REST APIs, the URI
scheme is:

[source,java]
----
salesforce:operationName?options
----

You can append query options to the URI in the following format,
`?option=value&option=value&...`

== Passing in Salesforce headers and fetching Salesforce response headers

There is support to pass https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/headers.htm[Salesforce headers]
via inbound message headers, header names that start with `Sforce` or
`x-sfdc` on the Camel message will be passed on in the request, and
response headers that start with `Sforce` will be present in the outbound
message headers.

For example to fetch API limits you can specify:

[source,java]
----
// in your Camel route set the header before Salesforce endpoint
//...
  .setHeader("Sforce-Limit-Info", constant("api-usage"))
  .to("salesforce:getGlobalObjects")
  .to(myProcessor);

// myProcessor will receive `Sforce-Limit-Info` header on the outbound
// message
class MyProcessor implements Processor {
    public void process(Exchange exchange) throws Exception {
        Message in = exchange.getIn();
        String apiLimits = in.getHeader("Sforce-Limit-Info", String.class);
   }
}
----

== Supported Salesforce APIs

The component supports the following Salesforce APIs

Producer endpoints can use the following APIs. Most of the APIs process
one record at a time, the Query API can retrieve multiple Records.

=== Rest API

You can use the following for `operationName`:

* getVersions - Gets supported Salesforce REST API versions
* getResources - Gets available Salesforce REST Resource endpoints
* getGlobalObjects - Gets metadata for all available SObject types
* getBasicInfo - Gets basic metadata for a specific SObject type
* getDescription - Gets comprehensive metadata for a specific SObject
type
* getSObject - Gets an SObject using its Salesforce Id
* createSObject - Creates an SObject
* updateSObject - Updates an SObject using Id
* deleteSObject - Deletes an SObject using Id
* getSObjectWithId - Gets an SObject using an external (user defined) id
field
* upsertSObject - Updates or inserts an SObject using an external id
* deleteSObjectWithId - Deletes an SObject using an external id
* query - Runs a Salesforce SOQL query
* queryMore - Retrieves more results (in case of large number of
results) using result link returned from the 'query' API
* search - Runs a Salesforce SOSL query
* limits - fetching organization API usage limits
* recent - fetching recent items
* approval - submit a record or records (batch) for approval process
* approvals - fetch a list of all approval processes
* composite - submit up to 25 possibly related REST requests and receive individual responses. It's also possible to use "raw" composite without limitation.
* composite-tree - create up to 200 records with parent-child relationships (up to 5 levels) in one go
* composite-batch - submit a composition of requests in batch
* compositeRetrieveSObjectCollections - Retrieve one or more records of the same object type.
* compositeCreateSObjectCollections - Add up to 200 records, returning a list of SaveSObjectResult objects.
* compositeUpdateSObjectCollections - Update up to 200 records, returning a list of SaveSObjectResult objects.
* compositeUpsertSObjectCollections - Create or update (upsert) up to 200 records based on an external ID field.
Returns a list of UpsertSObjectResult objects.
* compositeDeleteSObjectCollections - Delete up to 200 records, returning a list of SaveSObjectResult objects.
* queryAll - Runs a SOQL query. It returns the results that are deleted because of a merge (merges up to three records into one of the records, deletes the others, and reparents any related records) or delete.
Also returns
the  information about archived Task and Event records.
* getBlobField - Retrieves the specified blob field from an individual record.
* apexCall - Executes a user defined APEX REST API call.
* raw - Send requests to salesforce and have full, raw control over endpoint, parameters, body, etc.

For example, the following producer endpoint uses the upsertSObject API,
with the sObjectIdName parameter specifying 'Name' as the external id
field. 
The request message body should be an SObject DTO generated using the
maven plugin.  
The response message will either be `null` if an existing record was
updated, or `CreateSObjectResult` with an id of the new record, or a
list of errors while creating the new object.

[source,java]
----
...to("salesforce:upsertSObject?sObjectIdName=Name")...
----

=== Bulk 2.0 API

The Bulk 2.0 API has a simplified model over the original Bulk API. Use it to quickly load a large
amount of data into salesforce, or query a large amount of data out of salesforce. Data must be
provided in CSV format. The minimum API version for Bulk 2.0 is v41.0. The minimum API version for
Bulk Queries is v47.0. DTO classes mentioned below are from the
`org.apache.camel.component.salesforce.api.dto.bulkv2` package. The following operations are supported:

* *bulk2CreateJob* - Create a bulk job. Supply an instance of `Job` in the message body.
* *bulk2GetJob* - Get an existing Job. `jobId` parameter is required.
* *bulk2CreateBatch* - Add a Batch of CSV records to a job. Supply CSV data in the message body.
The first row must contain headers. `jobId` parameter is required.
* *bulk2CloseJob* - Close a job. You must close the job in order for it to be processed or
aborted/deleted. `jobId` parameter is required.
* *bulk2AbortJob* - Abort a job. `jobId` parameter is required.
* *bulk2DeleteJob* - Delete a job. `jobId` parameter is required.
* *bulk2GetSuccessfulResults* - Get successful results for a job. Returned message body will contain
an InputStream of CSV data. `jobId` parameter is required.
* *bulk2GetFailedResults* - Get failed results for a job. Returned message body will contain an
InputStream of CSV data. `jobId` parameter is required.
* *bulk2GetUnprocessedRecords* - Get unprocessed records for a job. Returned message body will
contain an InputStream of CSV data. `jobId` parameter is required.
* *bulk2GetAllJobs* - Get all jobs. Response body is an instance of `Jobs`. If the `done` property
is false, there are additional pages to fetch, and the `nextRecordsUrl` property contains the value
to be set in the `queryLocator` parameter on subsequent calls.
* *bulk2CreateQueryJob* - Create a bulk query job. Supply an instance of `QueryJob` in the message
body.
* *bulk2GetQueryJob* - Get a bulk query job. `jobId` parameter is required.
* *bulk2GetQueryJobResults* - Get bulk query job results. `jobId` parameter is required.
* *bulk2AbortQueryJob* - Abort a bulk query job. `jobId` parameter is required.
* *bulk2DeleteQueryJob* - Delete a bulk query job. `jobId` parameter is required.
* *bulk2GetAllQueryJobs* - Get all jobs. Response body is an instance of `QueryJobs`. If the `done`
property is false, there are additional pages to fetch, and the `nextRecordsUrl` property contains
the value to be set in the `queryLocator` parameter on subsequent calls.

=== Rest Bulk (original) API

Producer endpoints can use the following APIs. All Job data formats,
i.e. xml, csv, zip/xml, and zip/csv are supported.  +
 The request and response have to be marshalled/unmarshalled by the
route. Usually the request will be some stream source like a CSV file,
 +
 and the response may also be saved to a file to be correlated with the
request.

You can use the following for `operationName`:

* *createJob* - Creates a Salesforce Bulk Job. Must supply a `JobInfo` instance in body. PK Chunking
is supported via the pkChunking* options. See an explanation https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/async_api_headers_enable_pk_chunking.htm[here].
* *getJob* - Gets a Job using its Salesforce Id
* *closeJob* - Closes a Job
* *abortJob* - Aborts a Job
* *createBatch* - Submits a Batch within a Bulk Job
* *getBatch* - Gets a Batch using Id
* *getAllBatches* - Gets all Batches for a Bulk Job Id
* *getRequest* - Gets Request data (XML/CSV) for a Batch
* *getResults* - Gets the results of the Batch when its complete
* *createBatchQuery* - Creates a Batch from an SOQL query
* *getQueryResultIds* - Gets a list of Result Ids for a Batch Query
* *getQueryResult* - Gets results for a Result Id
* *getRecentReports* - Gets up to 200 of the reports you most recently viewed by sending a GET request to the Report List resource.
* *getReportDescription* - Retrieves the report, report type, and related metadata for a report, either in a tabular or summary or matrix format.
* *executeSyncReport* - Runs a report synchronously with or without changing filters and returns the latest summary data.
* *executeAsyncReport* - Runs an instance of a report asynchronously with or without filters and returns the summary data with or without details.
* *getReportInstances* - Returns a list of instances for a report that you requested to be run asynchronously. Each item in the list is treated as a separate instance of the report.
* *getReportResults*: Contains the results of running a report.

For example, the following producer endpoint uses the createBatch API to
create a Job Batch. The in message must contain a body that can be converted into an
`InputStream` (usually UTF-8 CSV or XML content from a file, etc.) and
header fields 'jobId' for the Job and 'contentType' for the Job content
type, which can be XML, CSV, ZIP_XML or ZIP_CSV. The put message body
will contain `BatchInfo` on success, or throw a `SalesforceException` on
error.

[source,java]
----
...to("salesforce:createBatch")..
----

=== Rest Streaming API

Consumer endpoints can use the following syntax for streaming endpoints
to receive Salesforce notifications on create/update.

To create and subscribe to a topic

[source,java]
----
from("salesforce:CamelTestTopic?notifyForFields=ALL&notifyForOperations=ALL&sObjectName=Merchandise__c&updateTopic=true&sObjectQuery=SELECT Id, Name FROM Merchandise__c")...
----

To subscribe to an existing topic

[source,java]
----
from("salesforce:CamelTestTopic&sObjectName=Merchandise__c")...
----

=== Platform events

To emit a platform event use `createSObject` operation. And set the
message body can be JSON string or InputStream with key-value data --
in that case `sObjectName` needs to be set to the API name of the
event, or a class that extends from AbstractDTOBase with the
appropriate class name for the event.

For example using a DTO:

[source,java]
----
class Order_Event__e extends AbstractDTOBase {
  @JsonProperty("OrderNumber")
  private String orderNumber;
  // ... other properties and getters/setters
}

from("timer:tick")
    .process(exchange -> {
        final Message in = exchange.getIn();
        String orderNumber = "ORD" + String.valueOf(in.getHeader(Exchange.TIMER_COUNTER));
        Order_Event__e event = new Order_Event__e();
        event.setOrderNumber(orderNumber);
        in.setBody(event);
    })
    .to("salesforce:createSObject");
----

Or using JSON event data:

[source,java]
----
from("timer:tick")
    .process(exchange -> {
        final Message in = exchange.getIn();
        String orderNumber = "ORD" + String.valueOf(in.getHeader(Exchange.TIMER_COUNTER));
        in.setBody("{\"OrderNumber\":\"" + orderNumber + "\"}");
    })
    .to("salesforce:createSObject?sObjectName=Order_Event__e");
----

To receive platform events use the consumer endpoint with the API name of
the platform event prefixed with `event/` (or `/event/`), e.g.:
`salesforce:events/Order_Event__e`. Processor consuming from that
endpoint will receive either `org.apache.camel.component.salesforce.api.dto.PlatformEvent`
object or `org.cometd.bayeux.Message` in the body depending on the
`rawPayload` being `false` or `true` respectively.

For example, in the simplest form to consume one event:

[source,java]
----
PlatformEvent event = consumer.receiveBody("salesforce:event/Order_Event__e", PlatformEvent.class);
----

=== Change data capture events

On the one hand, Salesforce could be configured to emit notifications for record changes of select objects.
On the other hand, the Camel Salesforce component could react to such notifications, allowing for instance to
https://trailhead.salesforce.com/en/content/learn/modules/change-data-capture/understand-change-data-capture[synchronize those changes into an external system].

The notifications of interest could be specified in the `from("salesforce:XXX")` clause of a Camel route via the subscription channel, e.g:

[source,java]
----
from("salesforce:data/ChangeEvents?replayId=-1").log("being notified of all change events")
from("salesforce:data/AccountChangeEvent?replayId=-1").log("being notified of change events for Account records")
from("salesforce:data/Employee__ChangeEvent?replayId=-1").log("being notified of change events for Employee__c custom object")
----

The received message contains either `java.util.Map<String,Object>` or `org.cometd.bayeux.Message` in the body depending on the `rawPayload` being `false` or `true` respectively. The `CamelSalesforceChangeType` header could be valued to one of `CREATE`, `UPDATE`,  `DELETE` or `UNDELETE`.

More details about how to use the Camel Salesforce component change data capture capabilities could be found in the https://github.com/apache/camel/tree/main/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/ChangeEventsConsumerIntegrationTest.java[ChangeEventsConsumerIntegrationTest].

The https://developer.salesforce.com/docs/atlas.en-us.change_data_capture.meta/change_data_capture/cdc_intro.htm[Salesforce developer guide]
is a good fit to better know the subtleties of implementing a change data capture integration application.
The dynamic nature of change event body fields, high level replication steps as well as security considerations could be of interest.

== Examples

=== Uploading a document to a ContentWorkspace

Create the ContentVersion in Java, using a Processor instance:

[source,java]
----
public class ContentProcessor implements Processor {
    public void process(Exchange exchange) throws Exception {
        Message message = exchange.getIn();

        ContentVersion cv = new ContentVersion();
        ContentWorkspace cw = getWorkspace(exchange);
        cv.setFirstPublishLocationId(cw.getId());
        cv.setTitle("test document");
        cv.setPathOnClient("test_doc.html");
        byte[] document = message.getBody(byte[].class);
        ObjectMapper mapper = new ObjectMapper();
        String enc = mapper.convertValue(document, String.class);
        cv.setVersionDataUrl(enc);
        message.setBody(cv);
    }

    protected ContentWorkspace getWorkSpace(Exchange exchange) {
        // Look up the content workspace somehow, maybe use enrich() to add it to a
        // header that can be extracted here
        ....
    }
} 
----

Give the output from the processor to the Salesforce component:

[source,java]
----
from("file:///home/camel/library")
    .to(new ContentProcessor())     // convert bytes from the file into a ContentVersion SObject 
                                    // for the salesforce component
    .to("salesforce:createSObject"); 
----

== Using Salesforce Limits API

With `salesforce:limits` operation you can fetch of API limits from Salesforce and then act upon that data received.
The result of `salesforce:limits` operation is mapped to `org.apache.camel.component.salesforce.api.dto.Limits`
class and can be used in a custom processors or expressions.

For instance, consider that you need to limit the API usage of Salesforce so that 10% of daily API requests is left for
other routes. The body of output message contains an instance of
`org.apache.camel.component.salesforce.api.dto.Limits` object that can be used in conjunction with
Content Based Router and Content Based Router and 
xref:languages:spel-language.adoc[Spring Expression Language (SpEL)] to choose when to perform queries.

Notice how multiplying `1.0` with the integer value held in `body.dailyApiRequests.remaining` makes the expression
evaluate as with floating point arithmetic, without it - it would end up making integral division which would result
with either `0` (some API limits consumed) or `1` (no API limits consumed).

[source,java]
----
from("direct:querySalesforce")
    .to("salesforce:limits")
    .choice()
    .when(spel("#{1.0 * body.dailyApiRequests.remaining / body.dailyApiRequests.max < 0.1}"))
        .to("salesforce:query?...")
    .otherwise()
        .setBody(constant("Used up Salesforce API limits, leaving 10% for critical routes"))
    .endChoice()
----

== Working with approvals

All the properties are named exactly the same as in the Salesforce REST API prefixed with `approval.`. You can set
approval properties by setting `approval.PropertyName` of the Endpoint these will be used as template -- meaning
that any property not present in either body or header will be taken from the Endpoint configuration. Or you can set
the approval template on the Endpoint by assigning `approval` property to a reference onto a bean in the Registry.

You can also provide header values using the same `approval.PropertyName` in the incoming message headers.

And finally body can contain one `AprovalRequest` or an `Iterable` of `ApprovalRequest` objects to process as
a batch.

The important thing to remember is the priority of the values specified in these three mechanisms:

. value in body takes precedence before any other
. value in message header takes precedence before template value
. value in template is set if no other value in header or body was given

For example to send one record for approval using values in headers use:

Given a route:

[source,java]
----
from("direct:example1")//
        .setHeader("approval.ContextId", simple("${body['contextId']}"))
        .setHeader("approval.NextApproverIds", simple("${body['nextApproverIds']}"))
        .to("salesforce:approval?"//
            + "approval.actionType=Submit"//
            + "&approval.comments=this is a test"//
            + "&approval.processDefinitionNameOrId=Test_Account_Process"//
            + "&approval.skipEntryCriteria=true");
----

You could send a record for approval using:

[source,java]
----
final Map<String, String> body = new HashMap<>();
body.put("contextId", accountIds.iterator().next());
body.put("nextApproverIds", userId);

final ApprovalResult result = template.requestBody("direct:example1", body, ApprovalResult.class);
----

== Using Salesforce Recent Items API

To fetch the recent items use `salesforce:recent` operation. This operation returns an `java.util.List` of
`org.apache.camel.component.salesforce.api.dto.RecentItem` objects (`List<RecentItem>`) that in turn contain
the `Id`, `Name` and `Attributes` (with `type` and `url` properties). You can limit the number of returned items
by specifying `limit` parameter set to maximum number of records to return. For example:

[source,java]
----
from("direct:fetchRecentItems")
    to("salesforce:recent")
        .split().body()
            .log("${body.name} at ${body.attributes.url}");
----

== Using Salesforce Composite API to submit SObject tree

To create up to 200 records including parent-child relationships use `salesforce:composite-tree` operation. This
requires an instance of `org.apache.camel.component.salesforce.api.dto.composite.SObjectTree` in the input 
message and returns the same tree of objects in the output message. The 
`org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase` instances within the tree get updated with
the identifier values (`Id` property) or their corresponding
`org.apache.camel.component.salesforce.api.dto.composite.SObjectNode` is populated with `errors` on failure.

Note that for some records operation can succeed and for some it can fail -- so you need to manually check for errors.

Easiest way to use this functionality is to use the DTOs generated by the `camel-salesforce-maven-plugin`, but you
also have the option of customizing the references that identify the each object in the tree, for instance primary keys
from your database.

Lets look at an example:

[source,java]
----
Account account = ...
Contact president = ...
Contact marketing = ...

Account anotherAccount = ...
Contact sales = ...
Asset someAsset = ...

// build the tree
SObjectTree request = new SObjectTree();
request.addObject(account).addChildren(president, marketing);
request.addObject(anotherAccount).addChild(sales).addChild(someAsset);

final SObjectTree response = template.requestBody("salesforce:composite-tree", tree, SObjectTree.class);
final Map<Boolean, List<SObjectNode>> result = response.allNodes()
                                                   .collect(Collectors.groupingBy(SObjectNode::hasErrors));

final List<SObjectNode> withErrors = result.get(true);
final List<SObjectNode> succeeded = result.get(false);

final String firstId = succeeded.get(0).getId();
----

== Using Salesforce Composite API to submit multiple requests in a batch
The Composite API batch operation (`composite-batch`) allows you to accumulate multiple requests in a batch and then
submit them in one go, saving the round trip cost of multiple individual requests. Each response is then received in a
list of responses with the order preserved, so that the n-th requests response is in the n-th place of the response.

[NOTE]
====
The results can vary from API to API so the result of the request is given as a `java.lang.Object`. In most cases
the result will be a `java.util.Map` with string keys and values or other `java.util.Map` as value. Requests made in
JSON format hold some type information (i.e. it is known what values are strings and what values are numbers), so in
general those will be more type friendly. Note that the responses will vary between XML and JSON, this is due to the
responses from Salesforce API being different. So be careful if you switch between formats without changing the response
handling code.
====

Lets look at an example:

[source,java]
----
final String acountId = ...
final SObjectBatch batch = new SObjectBatch("38.0");

final Account updates = new Account();
updates.setName("NewName");
batch.addUpdate("Account", accountId, updates);

final Account newAccount = new Account();
newAccount.setName("Account created from Composite batch API");
batch.addCreate(newAccount);

batch.addGet("Account", accountId, "Name", "BillingPostalCode");

batch.addDelete("Account", accountId);

final SObjectBatchResponse response = template.requestBody("salesforce:composite-batch?format=JSON", batch, SObjectBatchResponse.class);

boolean hasErrors = response.hasErrors(); // if any of the requests has resulted in either 4xx or 5xx HTTP status
final List<SObjectBatchResult> results = response.getResults(); // results of three operations sent in batch

final SObjectBatchResult updateResult = results.get(0); // update result
final int updateStatus = updateResult.getStatusCode(); // probably 204
final Object updateResultData = updateResult.getResult(); // probably null

final SObjectBatchResult createResult = results.get(1); // create result
@SuppressWarnings("unchecked")
final Map<String, Object> createData = (Map<String, Object>) createResult.getResult();
final String newAccountId = createData.get("id"); // id of the new account, this is for JSON, for XML it would be createData.get("Result").get("id")

final SObjectBatchResult retrieveResult = results.get(2); // retrieve result
@SuppressWarnings("unchecked")
final Map<String, Object> retrieveData = (Map<String, Object>) retrieveResult.getResult();
final String accountName = retrieveData.get("Name"); // Name of the retrieved account, this is for JSON, for XML it would be createData.get("Account").get("Name")
final String accountBillingPostalCode = retrieveData.get("BillingPostalCode"); // Name of the retrieved account, this is for JSON, for XML it would be createData.get("Account").get("BillingPostalCode")

final SObjectBatchResult deleteResult = results.get(3); // delete result
final int updateStatus = deleteResult.getStatusCode(); // probably 204
final Object updateResultData = deleteResult.getResult(); // probably null
----

== Using Salesforce Composite API to submit multiple chained requests
The `composite` operation allows submitting up to 25 requests that can be chained together, for instance identifier
generated in previous request can be used in subsequent request. Individual requests and responses are linked with the
provided _reference_.

[NOTE]
====
Composite API supports only JSON payloads.
====

[NOTE]
====
As with the batch API the results can vary from API to API so the result of the request is given as a
`java.lang.Object`. In most cases the result will be a `java.util.Map` with string keys and values or other
`java.util.Map` as value. Requests made in JSON format hold some type information (i.e. it is known what values are
strings and what values are numbers), so in general those will be more type friendly.
====

Lets look at an example:

[source,java]
----
SObjectComposite composite = new SObjectComposite("38.0", true);

// first insert operation via an external id
final Account updateAccount = new TestAccount();
updateAccount.setName("Salesforce");
updateAccount.setBillingStreet("Landmark @ 1 Market Street");
updateAccount.setBillingCity("San Francisco");
updateAccount.setBillingState("California");
updateAccount.setIndustry(Account_IndustryEnum.TECHNOLOGY);
composite.addUpdate("Account", "001xx000003DIpcAAG", updateAccount, "UpdatedAccount");

final Contact newContact = new TestContact();
newContact.setLastName("John Doe");
newContact.setPhone("1234567890");
composite.addCreate(newContact, "NewContact");

final AccountContactJunction__c junction = new AccountContactJunction__c();
junction.setAccount__c("001xx000003DIpcAAG");
junction.setContactId__c("@{NewContact.id}");
composite.addCreate(junction, "JunctionRecord");

final SObjectCompositeResponse response = template.requestBody("salesforce:composite?format=JSON", composite, SObjectCompositeResponse.class);
final List<SObjectCompositeResult> results = response.getCompositeResponse();

final SObjectCompositeResult accountUpdateResult = results.stream().filter(r -> "UpdatedAccount".equals(r.getReferenceId())).findFirst().get()
final int statusCode = accountUpdateResult.getHttpStatusCode(); // should be 200
final Map<String, ?> accountUpdateBody = accountUpdateResult.getBody();

final SObjectCompositeResult contactCreationResult = results.stream().filter(r -> "JunctionRecord".equals(r.getReferenceId())).findFirst().get()
----

== Using "raw" Salesforce composite

It's possible to directly call Salesforce composite by preparing the Salesforce JSON request in the route thanks to the `rawPayload` option.

For instance, you can have the following route:

----
from("timer:fire?period=2000").setBody(constant("{\n" +
     " \"allOrNone\" : true,\n" +
     " \"records\" : [ { \n" +
     "   \"attributes\" : {\"type\" : \"FOO\"},\n" +
     "   \"Name\" : \"123456789\",\n" +
     "   \"FOO\" : \"XXXX\",\n" +
     "   \"ACCOUNT\" : 2100.0\n" +
     "   \"ExternalID\" : \"EXTERNAL\"\n"
     " }]\n" +
     "}")
   .to("salesforce:composite?rawPayload=true")
   .log("${body}");
----

The route directly creates the body as JSON and directly submit to salesforce endpoint using `rawPayload=true` option.

With this approach, you have the complete control on the Salesforce request.

`POST` is the default HTTP method used to send raw Composite requests to salesforce. Use the
`compositeMethod` option to override to the other supported value, `GET`, which returns a list of
other available composite resources.

== Using Raw Operation

Send HTTP requests to salesforce with full, raw control of all aspects of the call. Any serialization or deserialization of request and response bodies must be performed in the route. The `Content-Type` HTTP
header will be automatically set based on the `format` option, but this can be overridden with the `rawHttpHeaders` option.

|===
| Parameter | Type | Description| Default| Required

| request body | `String` or `InputStream` | Body of the HTTP request | |
| rawPath | `String` | The portion of the endpoint URL after the domain name, e.g., '/services/data/v51.0/sobjects/Account/' | | x
| rawMethod | `String` | The HTTP method | | x
| rawQueryParameters | `String` | Comma separated list of message headers to include as query parameters. Do not url-encode values as this will be done automatically. | |
| rawHttpHeaders | `String` | Comma separated list of message headers to include as HTTP headers | |
|===

=== Query example

In this example we'll send a query to the REST API. The query must be passed in a URL parameter called "q", so we'll create a message header called q and tell the
raw operation to include that message header as a URL parameter:
----
from("direct:queryExample")
  .setHeader("q", "SELECT Id, LastName FROM Contact")
  .to("salesforce:raw?format=JSON&rawMethod=GET&rawQueryParameters=q&rawPath=/services/data/v51.0/query")
  // deserialize JSON results or handle in some other way
----

=== SObject example

In this example, we'll pass a Contact the REST API in a `create` operation. Since the `raw` operation does not perform any serialization,
we make sure to pass XML in the message body

----
from("direct:createAContact")
  .setBody(constant("<Contact><LastName>TestLast</LastName></Contact>"))
  .to("salesforce:raw?format=XML&rawMethod=POST&rawPath=/services/data/v51.0/sobjects/Contact")
----
The response is:
----
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Result>
    <id>0034x00000RnV6zAAF</id>
    <success>true</success>
</Result>
----

== Using Composite SObject Collections

The SObject Collections API executes actions on multiple records in one request. Use sObject Collections to reduce the number of round-trips between the client and server. The entire request counts as a single call toward your API limits. This resource is available in API version 42.0 and later. `SObject` records (aka DTOs) supplied to these operations must be instances of subclasses of `AbstractDescribedSObjectBase`. See the Maven Plugin section for information on generating these DTO classes. These operations serialize supplied DTOs to JSON.

=== compositeRetrieveSObjectCollections
Retrieve one or more records of the same object type.
|===
| Parameter | Type | Description | Default | Required

| ids | List of String or comma-separated string | A list of one or more IDs of the objects to return. All IDs must belong to the same object type. | | x
| fields | List of String or comma-separated string | A list of fields to include in the response. The field names you specify must be valid, and you must have read-level permissions to each field. | | x
| sObjectName | String | Type of SObject, e.g. `Account` | | x
| sObjectClass | String | Fully-qualified class name of DTO class to use for deserializing the response. | | Required if `sObjectName` parameter does not resolve to a class that exists in the package specified by the `package` option.
|===

=== compositeCreateSObjectCollections
Add up to 200 records, returning a list of SaveSObjectResult objects. Mixed SObject types is supported.
|===
| Parameter | Type | Description| Default| Required

| request body | List of `SObject` | A list of SObjects to create | | x
| allOrNone | boolean | Indicates whether to roll back the entire request when the creation of any object fails (true) or to continue with the independent creation of other objects in the request. | false |
|===

=== compositeUpdateSObjectCollections
Update up to 200 records, returning a list of SaveSObjectResult objects. Mixed SObject types is supported.
|===
| Parameter | Type | Description | Default | Required

| request body | List of `SObject` | A list of SObjects to update | | x
| allOrNone | boolean | Indicates whether to roll back the entire request when the update of any object fails (true) or to continue with the independent update of other objects in the request. | false |
|===

=== compositeUpsertSObjectCollections
Create or update (upsert) up to 200 records based on an external ID field, returning a list of UpsertSObjectResult
objects. Mixed SObject types is not supported.
|===
| Parameter | Type | Description | Default | Required

| request body | List of `SObject` | A list of SObjects to upsert | | x
| allOrNone | boolean |  Indicates whether to roll back the entire request when the upsert of any object fails (true) or to continue with the independent upsert of other objects in the request. | false |
| sObjectName | String | Type of SObject, e.g. `Account` | | x
| sObjectIdName | String | Name of External ID field | | x
|===

=== compositeDeleteSObjectCollections
Delete up to 200 records, returning a list of DeleteSObjectResult objects. Mixed SObject types is supported.
|===
| Parameter | Type | Description | Default | Required

| ids | List of String or comma-separated string | A list of up to 200 IDs of objects to be deleted. | | x
| allOrNone | boolean | Indicates whether to roll back the entire request when the upsert of any object fails (true) or to continue with the independent upsert of other objects in the request. | false |
|===


==  Sending null values to salesforce

By default, SObject fields with null values are not sent to salesforce. In order to
send null values to salesforce, use the `fieldsToNull` property, as follows:

[source,java]
----
accountSObject.getFieldsToNull().add("Site");
----

== Generating SOQL query strings

`org.apache.camel.component.salesforce.api.utils.QueryHelper` contains helper
methods to generate SOQL queries. For instance to fetch all custom fields from
_Account_ SObject you can simply generate the SOQL SELECT by invoking:

[source,java]
----
String allCustomFieldsQuery = QueryHelper.queryToFetchFilteredFieldsOf(new Account(), SObjectField::isCustom);
----

== Camel Salesforce Maven Plugin

This Maven plugin generates DTOs for the Camel. 

For obvious security reasons it is recommended that the clientId,
clientSecret, userName and password fields be not set in the pom.xml.  
The plugin should be configured for the rest of the properties, and can
be executed using the following command:

[source,java]
----
mvn camel-salesforce:generate -DcamelSalesforce.clientId=<clientid> -DcamelSalesforce.clientSecret=<clientsecret> \
    -DcamelSalesforce.userName=<username> -DcamelSalesforce.password=<password>
----

The generated DTOs use Jackson and XStream annotations. All Salesforce
field types are supported. Date and time fields are mapped to
`java.time.ZonedDateTime` by default, and picklist fields are mapped to
generated Java Enumerations.

Please refer to
https://github.com/apache/camel/tree/main/components/camel-salesforce/camel-salesforce-maven-plugin[README.md]
for details on how to generate the DTO.

== Options

// component options: START
The Salesforce component supports 86 options, which are listed below.



[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *apexMethod* (common) | APEX method name |  | String
| *apexQueryParams* (common) | Query params for APEX method |  | Map
| *apiVersion* (common) | Salesforce API version. | 50.0 | String
| *backoffIncrement* (common) | Backoff interval increment for Streaming connection restart attempts for failures beyond CometD auto-reconnect. | 1000 | long
| *batchId* (common) | Bulk API Batch ID |  | String
| *contentType* (common) | Bulk API content type, one of XML, CSV, ZIP_XML, ZIP_CSV. There are 6 enums and the value can be one of: XML, CSV, JSON, ZIP_XML, ZIP_CSV, ZIP_JSON |  | ContentType
| *defaultReplayId* (common) | Default replayId setting if no value is found in initialReplayIdMap | -1 | Long
| *format* (common) | Payload format to use for Salesforce API calls, either JSON or XML, defaults to JSON. There are 2 enums and the value can be one of: JSON, XML |  | PayloadFormat
| *httpClient* (common) | Custom Jetty Http Client to use to connect to Salesforce. |  | SalesforceHttpClient
| *httpClientConnectionTimeout* (common) | Connection timeout used by the HttpClient when connecting to the Salesforce server. | 60000 | long
| *httpClientIdleTimeout* (common) | Timeout used by the HttpClient when waiting for response from the Salesforce server. | 10000 | long
| *httpMaxContentLength* (common) | Max content length of an HTTP response. |  | Integer
| *httpRequestBufferSize* (common) | HTTP request buffer size. May need to be increased for large SOQL queries. | 8192 | Integer
| *includeDetails* (common) | Include details in Salesforce1 Analytics report, defaults to false. |  | Boolean
| *initialReplayIdMap* (common) | Replay IDs to start from per channel name. |  | Map
| *instanceId* (common) | Salesforce1 Analytics report execution instance ID |  | String
| *jobId* (common) | Bulk API Job ID |  | String
| *limit* (common) | Limit on number of returned records. Applicable to some of the API, check the Salesforce documentation. |  | Integer
| *maxBackoff* (common) | Maximum backoff interval for Streaming connection restart attempts for failures beyond CometD auto-reconnect. | 30000 | long
| *notFoundBehaviour* (common) | Sets the behaviour of 404 not found status received from Salesforce API. Should the body be set to NULL NotFoundBehaviour#NULL or should a exception be signaled on the exchange NotFoundBehaviour#EXCEPTION - the default. There are 2 enums and the value can be one of: EXCEPTION, NULL | EXCEPTION | NotFoundBehaviour
| *notifyForFields* (common) | Notify for fields, options are ALL, REFERENCED, SELECT, WHERE. There are 4 enums and the value can be one of: ALL, REFERENCED, SELECT, WHERE |  | NotifyForFieldsEnum
| *notifyForOperationCreate* (common) | Notify for create operation, defaults to false (API version = 29.0) |  | Boolean
| *notifyForOperationDelete* (common) | Notify for delete operation, defaults to false (API version = 29.0) |  | Boolean
| *notifyForOperations* (common) | Notify for operations, options are ALL, CREATE, EXTENDED, UPDATE (API version 29.0). There are 4 enums and the value can be one of: ALL, CREATE, EXTENDED, UPDATE |  | NotifyForOperationsEnum
| *notifyForOperationUndelete* (common) | Notify for un-delete operation, defaults to false (API version = 29.0) |  | Boolean
| *notifyForOperationUpdate* (common) | Notify for update operation, defaults to false (API version = 29.0) |  | Boolean
| *objectMapper* (common) | Custom Jackson ObjectMapper to use when serializing/deserializing Salesforce objects. |  | ObjectMapper
| *packages* (common) | In what packages are the generated DTO classes. Typically the classes would be generated using camel-salesforce-maven-plugin. This must be set if using the XML format. Also, set it if using the generated DTOs to gain the benefit of using short SObject names in parameters/header values. Multiple packages can be separated by comma. |  | String
| *pkChunking* (common) | Use PK Chunking. Only for use in original Bulk API. Bulk 2.0 API performs PK chunking automatically, if necessary. |  | Boolean
| *pkChunkingChunkSize* (common) | Chunk size for use with PK Chunking. If unspecified, salesforce default is 100,000. Maximum size is 250,000. |  | Integer
| *pkChunkingParent* (common) | Specifies the parent object when you're enabling PK chunking for queries on sharing objects. The chunks are based on the parent object's records rather than the sharing object's records. For example, when querying on AccountShare, specify Account as the parent object. PK chunking is supported for sharing objects as long as the parent object is supported. |  | String
| *pkChunkingStartRow* (common) | Specifies the 15-character or 18-character record ID to be used as the lower boundary for the first chunk. Use this parameter to specify a starting ID when restarting a job that failed between batches. |  | String
| *queryLocator* (common) | Query Locator provided by salesforce for use when a query results in more records than can be retrieved in a single call. Use this value in a subsequent call to retrieve additional records. |  | String
| *rawPayload* (common) | Use raw payload String for request and response (either JSON or XML depending on format), instead of DTOs, false by default | false | boolean
| *reportId* (common) | Salesforce1 Analytics report Id |  | String
| *reportMetadata* (common) | Salesforce1 Analytics report metadata for filtering |  | ReportMetadata
| *resultId* (common) | Bulk API Result ID |  | String
| *sObjectBlobFieldName* (common) | SObject blob field name |  | String
| *sObjectClass* (common) | Fully qualified SObject class name, usually generated using camel-salesforce-maven-plugin |  | String
| *sObjectFields* (common) | SObject fields to retrieve |  | String
| *sObjectId* (common) | SObject ID if required by API |  | String
| *sObjectIdName* (common) | SObject external ID field name |  | String
| *sObjectIdValue* (common) | SObject external ID field value |  | String
| *sObjectName* (common) | SObject name if required or supported by API |  | String
| *sObjectQuery* (common) | Salesforce SOQL query string |  | String
| *sObjectSearch* (common) | Salesforce SOSL search string |  | String
| *updateTopic* (common) | Whether to update an existing Push Topic when using the Streaming API, defaults to false | false | boolean
| *config* (common) | Global endpoint configuration - use to set values that are common to all endpoints |  | SalesforceEndpointConfig
| *httpClientProperties* (common) | Used to set any properties that can be configured on the underlying HTTP client. Have a look at properties of SalesforceHttpClient and the Jetty HttpClient for all available options. |  | Map
| *longPollingTransportProperties* (common) | Used to set any properties that can be configured on the LongPollingTransport used by the BayeuxClient (CometD) used by the streaming api |  | Map
| *workerPoolMaxSize* (common) | Maximum size of the thread pool used to handle HTTP responses. | 20 | int
| *workerPoolSize* (common) | Size of the thread pool used to handle HTTP responses. | 10 | int
| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
| *allOrNone* (producer) | Composite API option to indicate to rollback all records if any are not successful. | false | boolean
| *apexUrl* (producer) | APEX method URL |  | String
| *compositeMethod* (producer) | Composite (raw) method. |  | String
| *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean
| *rawHttpHeaders* (producer) | Comma separated list of message headers to include as HTTP parameters for Raw operation. |  | String
| *rawMethod* (producer) | HTTP method to use for the Raw operation |  | String
| *rawPath* (producer) | The portion of the endpoint URL after the domain name. E.g., '/services/data/v52.0/sobjects/Account/' |  | String
| *rawQueryParameters* (producer) | Comma separated list of message headers to include as query parameters for Raw operation. Do not url-encode values as this will be done automatically. |  | String
| *autowiredEnabled* (advanced) | Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean
| *httpProxyExcludedAddresses* (proxy) | A list of addresses for which HTTP proxy server should not be used. |  | Set
| *httpProxyHost* (proxy) | Hostname of the HTTP proxy server to use. |  | String
| *httpProxyIncludedAddresses* (proxy) | A list of addresses for which HTTP proxy server should be used. |  | Set
| *httpProxyPort* (proxy) | Port number of the HTTP proxy server to use. |  | Integer
| *httpProxySocks4* (proxy) | If set to true the configures the HTTP proxy to use as a SOCKS4 proxy. | false | boolean
| *authenticationType* (security) | Explicit authentication method to be used, one of USERNAME_PASSWORD, REFRESH_TOKEN or JWT. Salesforce component can auto-determine the authentication method to use from the properties set, set this property to eliminate any ambiguity. There are 3 enums and the value can be one of: USERNAME_PASSWORD, REFRESH_TOKEN, JWT |  | AuthenticationType
| *clientId* (security) | *Required* OAuth Consumer Key of the connected app configured in the Salesforce instance setup. Typically a connected app needs to be configured but one can be provided by installing a package. |  | String
| *clientSecret* (security) | OAuth Consumer Secret of the connected app configured in the Salesforce instance setup. |  | String
| *httpProxyAuthUri* (security) | Used in authentication against the HTTP proxy server, needs to match the URI of the proxy server in order for the httpProxyUsername and httpProxyPassword to be used for authentication. |  | String
| *httpProxyPassword* (security) | Password to use to authenticate against the HTTP proxy server. |  | String
| *httpProxyRealm* (security) | Realm of the proxy server, used in preemptive Basic/Digest authentication methods against the HTTP proxy server. |  | String
| *httpProxySecure* (security) | If set to false disables the use of TLS when accessing the HTTP proxy. | true | boolean
| *httpProxyUseDigestAuth* (security) | If set to true Digest authentication will be used when authenticating to the HTTP proxy, otherwise Basic authorization method will be used | false | boolean
| *httpProxyUsername* (security) | Username to use to authenticate against the HTTP proxy server. |  | String
| *instanceUrl* (security) | URL of the Salesforce instance used after authentication, by default received from Salesforce on successful authentication |  | String
| *keystore* (security) | KeyStore parameters to use in OAuth JWT flow. The KeyStore should contain only one entry with private key and certificate. Salesforce does not verify the certificate chain, so this can easily be a selfsigned certificate. Make sure that you upload the certificate to the corresponding connected app. |  | KeyStoreParameters
| *lazyLogin* (security) | If set to true prevents the component from authenticating to Salesforce with the start of the component. You would generally set this to the (default) false and authenticate early and be immediately aware of any authentication issues. | false | boolean
| *loginConfig* (security) | All authentication configuration in one nested bean, all properties set there can be set directly on the component as well |  | SalesforceLoginConfig
| *loginUrl* (security) | *Required* URL of the Salesforce instance used for authentication, by default set to \https://login.salesforce.com | https://login.salesforce.com | String
| *password* (security) | Password used in OAuth flow to gain access to access token. It's easy to get started with password OAuth flow, but in general one should avoid it as it is deemed less secure than other flows. Make sure that you append security token to the end of the password if using one. |  | String
| *refreshToken* (security) | Refresh token already obtained in the refresh token OAuth flow. One needs to setup a web application and configure a callback URL to receive the refresh token, or configure using the builtin callback at \https://login.salesforce.com/services/oauth2/success or \https://test.salesforce.com/services/oauth2/success and then retrive the refresh_token from the URL at the end of the flow. Note that in development organizations Salesforce allows hosting the callback web application at localhost. |  | String
| *sslContextParameters* (security) | SSL parameters to use, see SSLContextParameters class for all available options. |  | SSLContextParameters
| *useGlobalSslContextParameters* (security) | Enable usage of global SSL context parameters | false | boolean
| *userName* (security) | Username used in OAuth flow to gain access to access token. It's easy to get started with password OAuth flow, but in general one should avoid it as it is deemed less secure than other flows. |  | String
|===
// component options: END










// endpoint options: START
The Salesforce endpoint is configured using URI syntax:

----
salesforce:operationName:topicName
----

with the following path and query parameters:

=== Path Parameters (2 parameters):


[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *operationName* | The operation to use. There are 65 enums and the value can be one of: getVersions, getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, createSObject, updateSObject, deleteSObject, getSObjectWithId, upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, queryAll, search, apexCall, recent, createJob, getJob, closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, getResults, createBatchQuery, getQueryResultIds, getQueryResult, getRecentReports, getReportDescription, executeSyncReport, executeAsyncReport, getReportInstances, getReportResults, limits, approval, approvals, composite-tree, composite-batch, composite, compositeRetrieveSObjectCollections, compositeCreateSObjectCollections, compositeUpdateSObjectCollections, compositeUpsertSObjectCollections, compositeDeleteSObjectCollections, bulk2GetAllJobs, bulk2CreateJob, bulk2GetJob, bulk2CreateBatch, bulk2CloseJob, bulk2AbortJob, bulk2DeleteJob, bulk2GetSuccessfulResults, bulk2GetFailedResults, bulk2GetUnprocessedRecords, bulk2CreateQueryJob, bulk2GetQueryJob, bulk2GetAllQueryJobs, bulk2GetQueryJobResults, bulk2AbortQueryJob, bulk2DeleteQueryJob, raw |  | OperationName
| *topicName* | The name of the topic/channel to use |  | String
|===


=== Query Parameters (54 parameters):


[width="100%",cols="2,5,^1,2",options="header"]
|===
| Name | Description | Default | Type
| *apexMethod* (common) | APEX method name |  | String
| *apexQueryParams* (common) | Query params for APEX method |  | Map
| *apiVersion* (common) | Salesforce API version. | 50.0 | String
| *backoffIncrement* (common) | Backoff interval increment for Streaming connection restart attempts for failures beyond CometD auto-reconnect. | 1000 | long
| *batchId* (common) | Bulk API Batch ID |  | String
| *contentType* (common) | Bulk API content type, one of XML, CSV, ZIP_XML, ZIP_CSV. There are 6 enums and the value can be one of: XML, CSV, JSON, ZIP_XML, ZIP_CSV, ZIP_JSON |  | ContentType
| *defaultReplayId* (common) | Default replayId setting if no value is found in initialReplayIdMap | -1 | Long
| *format* (common) | Payload format to use for Salesforce API calls, either JSON or XML, defaults to JSON. There are 2 enums and the value can be one of: JSON, XML |  | PayloadFormat
| *httpClient* (common) | Custom Jetty Http Client to use to connect to Salesforce. |  | SalesforceHttpClient
| *includeDetails* (common) | Include details in Salesforce1 Analytics report, defaults to false. |  | Boolean
| *initialReplayIdMap* (common) | Replay IDs to start from per channel name. |  | Map
| *instanceId* (common) | Salesforce1 Analytics report execution instance ID |  | String
| *jobId* (common) | Bulk API Job ID |  | String
| *limit* (common) | Limit on number of returned records. Applicable to some of the API, check the Salesforce documentation. |  | Integer
| *maxBackoff* (common) | Maximum backoff interval for Streaming connection restart attempts for failures beyond CometD auto-reconnect. | 30000 | long
| *notFoundBehaviour* (common) | Sets the behaviour of 404 not found status received from Salesforce API. Should the body be set to NULL NotFoundBehaviour#NULL or should a exception be signaled on the exchange NotFoundBehaviour#EXCEPTION - the default. There are 2 enums and the value can be one of: EXCEPTION, NULL | EXCEPTION | NotFoundBehaviour
| *notifyForFields* (common) | Notify for fields, options are ALL, REFERENCED, SELECT, WHERE. There are 4 enums and the value can be one of: ALL, REFERENCED, SELECT, WHERE |  | NotifyForFieldsEnum
| *notifyForOperationCreate* (common) | Notify for create operation, defaults to false (API version = 29.0) |  | Boolean
| *notifyForOperationDelete* (common) | Notify for delete operation, defaults to false (API version = 29.0) |  | Boolean
| *notifyForOperations* (common) | Notify for operations, options are ALL, CREATE, EXTENDED, UPDATE (API version 29.0). There are 4 enums and the value can be one of: ALL, CREATE, EXTENDED, UPDATE |  | NotifyForOperationsEnum
| *notifyForOperationUndelete* (common) | Notify for un-delete operation, defaults to false (API version = 29.0) |  | Boolean
| *notifyForOperationUpdate* (common) | Notify for update operation, defaults to false (API version = 29.0) |  | Boolean
| *objectMapper* (common) | Custom Jackson ObjectMapper to use when serializing/deserializing Salesforce objects. |  | ObjectMapper
| *pkChunking* (common) | Use PK Chunking. Only for use in original Bulk API. Bulk 2.0 API performs PK chunking automatically, if necessary. |  | Boolean
| *pkChunkingChunkSize* (common) | Chunk size for use with PK Chunking. If unspecified, salesforce default is 100,000. Maximum size is 250,000. |  | Integer
| *pkChunkingParent* (common) | Specifies the parent object when you're enabling PK chunking for queries on sharing objects. The chunks are based on the parent object's records rather than the sharing object's records. For example, when querying on AccountShare, specify Account as the parent object. PK chunking is supported for sharing objects as long as the parent object is supported. |  | String
| *pkChunkingStartRow* (common) | Specifies the 15-character or 18-character record ID to be used as the lower boundary for the first chunk. Use this parameter to specify a starting ID when restarting a job that failed between batches. |  | String
| *queryLocator* (common) | Query Locator provided by salesforce for use when a query results in more records than can be retrieved in a single call. Use this value in a subsequent call to retrieve additional records. |  | String
| *rawPayload* (common) | Use raw payload String for request and response (either JSON or XML depending on format), instead of DTOs, false by default | false | boolean
| *reportId* (common) | Salesforce1 Analytics report Id |  | String
| *reportMetadata* (common) | Salesforce1 Analytics report metadata for filtering |  | ReportMetadata
| *resultId* (common) | Bulk API Result ID |  | String
| *sObjectBlobFieldName* (common) | SObject blob field name |  | String
| *sObjectClass* (common) | Fully qualified SObject class name, usually generated using camel-salesforce-maven-plugin |  | String
| *sObjectFields* (common) | SObject fields to retrieve |  | String
| *sObjectId* (common) | SObject ID if required by API |  | String
| *sObjectIdName* (common) | SObject external ID field name |  | String
| *sObjectIdValue* (common) | SObject external ID field value |  | String
| *sObjectName* (common) | SObject name if required or supported by API |  | String
| *sObjectQuery* (common) | Salesforce SOQL query string |  | String
| *sObjectSearch* (common) | Salesforce SOSL search string |  | String
| *updateTopic* (common) | Whether to update an existing Push Topic when using the Streaming API, defaults to false | false | boolean
| *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
| *replayId* (consumer) | The replayId value to use when subscribing |  | Long
| *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
| *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. There are 3 enums and the value can be one of: InOnly, InOut, InOptionalOut |  | ExchangePattern
| *allOrNone* (producer) | Composite API option to indicate to rollback all records if any are not successful. | false | boolean
| *apexUrl* (producer) | APEX method URL |  | String
| *compositeMethod* (producer) | Composite (raw) method. |  | String
| *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean
| *rawHttpHeaders* (producer) | Comma separated list of message headers to include as HTTP parameters for Raw operation. |  | String
| *rawMethod* (producer) | HTTP method to use for the Raw operation |  | String
| *rawPath* (producer) | The portion of the endpoint URL after the domain name. E.g., '/services/data/v52.0/sobjects/Account/' |  | String
| *rawQueryParameters* (producer) | Comma separated list of message headers to include as query parameters for Raw operation. Do not url-encode values as this will be done automatically. |  | String
|===
// endpoint options: END

include::spring-boot:partial$starter.adoc[]
