Skip to main content

Salesforce SObject Sink Connector

sh.oso.salesforce.sink.SalesforceSinkConnector

Writes Kafka records into Salesforce SObjects using Bulk API 2.0 ingest jobs for throughput or REST Composite calls for low latency (sf.write.mode=auto picks per batch size).

Operation mapping​

By default the operation is driven by the record's _EventType field (the shape emitted by the source connector):

_EventTypeOperationWith sf.<obj>.use.custom.id.field=true
createdinsertupsert (external ID)
updatedupdate (by Id)upsert (external ID)
deleteddeletedelete (Id resolved via external ID)

Set sf.<obj>.override.event.type=true + sf.<obj>.operation to force a single operation regardless of _EventType.

Read-only Salesforce fields (createable=false / updateable=false in the object describe) are silently excluded — a record carrying CreatedDate or IsDeleted doesn't fail the batch. _EventType/_ObjectType and configured ignore.fields are also stripped.

Cross-org sync with external IDs​

Id values are only valid in the originating org. For org-to-org sync, mark a field as an External ID in the target org and configure:

sf.Lead.use.custom.id.field=true
sf.Lead.custom.id.field.name=External_Id__c

All creates/updates become idempotent upserts keyed on the external ID — this also makes at-least-once redelivery safe.

Big Objects​

sf.<obj>.type=big_object enables Big Object (__b) targets. Big Objects are insert-only: records with _EventType of updated/deleted are routed to the DLQ instead of being written.

Error handling & DLQ​

Per-record failures (Bulk failedResults rows, Composite per-record errors, mapping failures) are reported to Kafka Connect's errant-record reporter — configure errors.tolerance=all + errors.deadletterqueue.topic.name to land them in a DLQ with the failure reason. behavior.on.api.errors then controls the task:

ValueBehaviour
fail (default)Report failures, then fail the task
logReport failures, log a warning, keep going
ignoreReport failures silently

Configuration reference​

Full property reference

Every property with types, defaults, and valid values — generated from the connector's ConfigDef: SObject Sink Configuration.

Auth properties (sf.auth.grant.type, sf.instance.url, sf.consumer.key, …) are the same as the source connector.

Global​

PropertyTypeDefaultDescription
topics / topics.regexlist/string—Source Kafka topics
sf.objectslist—Target SObject API names
sf.write.modeenumautobulk2, rest, or auto (REST at or below the threshold)
sf.write.rest.thresholdint200Max records for the REST path in auto mode
behavior.on.api.errorsenumfailfail, log, or ignore
sf.max.batch.recordsint10000Records per Bulk ingest job
sf.request.max.retries.time.mslong30000Retry budget
sf.api.versionstring60.0API version

Per-object (sf.<object>.*)​

PropertyTypeDefaultDescription
sf.<obj>.topicslist—Kafka topic(s) feeding this object (a topic maps to exactly one object)
sf.<obj>.operationenuminsertinsert, update, upsert, or delete
sf.<obj>.override.event.typebooleanfalseIgnore _EventType; force sf.<obj>.operation
sf.<obj>.use.custom.id.fieldbooleanfalseUse an external ID for upsert/delete
sf.<obj>.custom.id.field.namestring—External ID field API name
sf.<obj>.typeenumstandard_customstandard_custom or big_object
sf.<obj>.ignore.fieldslist—Record fields to skip

Example — cross-org Lead sync​

{
"name": "salesforce-lead-sink",
"config": {
"connector.class": "sh.oso.salesforce.sink.SalesforceSinkConnector",
"tasks.max": "2",
"topics": "salesforce.Lead",
"sf.auth.grant.type": "client_credentials",
"sf.instance.url": "https://target-org.my.salesforce.com",
"sf.consumer.key": "...",
"sf.consumer.secret": "...",
"sf.objects": "Lead",
"sf.Lead.topics": "salesforce.Lead",
"sf.Lead.use.custom.id.field": "true",
"sf.Lead.custom.id.field.name": "External_Id__c",
"sf.write.mode": "auto",
"behavior.on.api.errors": "log",
"errors.tolerance": "all",
"errors.deadletterqueue.topic.name": "dlq-salesforce-lead-sink",
"errors.deadletterqueue.context.headers.enable": "true"
}
}