This document specifies the Kafka protocol APIs used for transactions and exactly-once semantics. These APIs enable atomic writes across multiple partitions and exactly-once processing guarantees.
API Key Name Purpose 22 InitProducerId Initialize producer for idempotence/transactions 24 AddPartitionsToTxn Add partitions to active transaction 25 AddOffsetsToTxn Add consumer offsets to transaction 26 EndTxn Commit or abort transaction 27 WriteTxnMarkers Write transaction markers (internal) 28 TxnOffsetCommit Commit offsets within transaction 65 DescribeTransactions Describe active transactions 66 ListTransactions List transactions on broker
Transaction lifecycle from InitProducerId to commit markers Producer Transaction Partition Group Producer Producer Transaction Coordinator Transaction Coordinator Partition Leader Partition Leader Group Coordinator Group Coordinator Initialization InitProducerId(txn_id) (PID, epoch) Begin Transaction beginTransaction() Local state only Produce AddPartitionsToTxn(topic, partition) OK Produce(PID, epoch, records) Ack Offset Commit (optional) AddOffsetsToTxn(group_id) OK TxnOffsetCommit(offsets) OK Commit EndTxn(COMMIT) WriteTxnMarkers(COMMIT) OK WriteTxnMarkers(COMMIT) OK OK
Transaction coordinator state transitions Transaction coordinator state transitions Empty Ongoing PrepareCommit PrepareAbort CompleteCommit CompleteAbort Dead InitProducerId AddPartitionsToTxn AddPartitionsToTxn AddOffsetsToTxn Produce EndTxn(COMMIT) EndTxn(ABORT) timeout markers written markers written ready ready expiration producer fenced
The InitProducerId API initializes a producer for idempotent or transactional operation by assigning a unique Producer ID (PID) and epoch.
Version Kafka Key Changes 0 0.11.0 Initial version 2 2.4.0 Flexible versions 3 2.5.0 Producer ID/epoch in request 4 2.6.0 PRODUCER_FENCED error 5 3.9.0 TRANSACTION_ABORTABLE error (KIP-890) 6 4.0.0 2PC support (KIP-939)
transactional_id: NULLABLE_STRING
transaction_timeout_ms: INT32
keep_prepared_txn: BOOLEAN
Field Type Description transactional_idNULLABLE_STRING Transaction ID (null for idempotent only) transaction_timeout_msINT32 Transaction timeout producer_idINT64 Existing PID to recover (-1 for new) producer_epochINT16 Existing epoch to recover (-1 for new) enable2pcBOOLEAN Enable two-phase commit (v6+) keep_prepared_txnBOOLEAN Keep prepared transaction (v6+)
InitProducerIdResponse =>
ongoing_txn_producer_id: INT64
ongoing_txn_producer_epoch: INT16
Field Type Description producer_idINT64 Assigned Producer ID producer_epochINT16 Producer epoch ongoing_txn_producer_idINT64 Producer ID for ongoing txn (v6+) ongoing_txn_producer_epochINT16 Producer epoch for ongoing txn (v6+)
Producer ID and epoch assignment across initialization and restart Producer ID and epoch assignment across initialization and restart First InitProducerId Transactional InitProducerId Producer Restart transactional_id=null producer_id=-1 Response: PID=12345 epoch=0 transactional_id='my-txn' producer_id=-1 Response: PID=67890 epoch=0 transactional_id='my-txn' producer_id=-1 Response: PID=67890 epoch=1 Same PID, incremented epoch fences old producer
Aspect Guarantee PID uniqueness PID is globally unique per broker lifetime Epoch increment Epoch increments on each init with same transactional_id Fencing Old producers with same transactional_id are fenced Timeout Transaction must complete within transaction_timeout_ms
Error Code Retriable Cause Recovery COORDINATOR_NOT_AVAILABLE ✅ Coordinator unavailable Retry NOT_COORDINATOR ✅ Wrong coordinator FindCoordinator, retry CONCURRENT_TRANSACTIONS ✅ Another init in progress Wait, retry INVALID_TRANSACTION_TIMEOUT ❌ Timeout out of range Fix timeout TRANSACTIONAL_ID_AUTHORIZATION_FAILED ❌ No permission Check ACLs
The AddPartitionsToTxn API adds topic partitions to an active transaction before producing to them.
Version Kafka Key Changes 0 0.11.0 Initial version 2 2.1.0 PRODUCER_FENCED error 3 2.4.0 Flexible versions 4 2.8.0 VerifyOnly + batched transactions 5 3.9.0 TRANSACTION_ABORTABLE (KIP-890)
AddPartitionsToTxnRequest =>
v3_and_below_transactional_id: STRING
v3_and_below_producer_id: INT64
v3_and_below_producer_epoch: INT16
v3_and_below_topics: [Topic]
transactions: [Transaction]
Field Type Description transactional_idSTRING Transaction identifier producer_idINT64 Producer ID from InitProducerId producer_epochINT16 Producer epoch ongoing_txn_producer_idINT64 Producer ID for ongoing txn (v6+) ongoing_txn_producer_epochINT16 Producer epoch for ongoing txn (v6+) topicsARRAY Partitions to add
AddPartitionsToTxnResponse =>
results_by_transaction: [TransactionResult]
results_by_topic_v3_and_below: [TopicResult]
results_by_partition: [PartitionResult]
partition_error_code: INT16
Aspect Guarantee Precondition Transaction must be ongoing (after InitProducerId) Idempotence Adding same partition multiple times is safe Order Must add partition before producing to it
Produce Before Add
Producing to a partition before adding it to the transaction results in INVALID_PRODUCER_EPOCH or UNKNOWN_PRODUCER_ID error.
The AddOffsetsToTxn API adds a consumer group's offsets to an active transaction, enabling exactly-once consume-transform-produce patterns.
Version Kafka Key Changes 0 0.11.0 Initial version 2 2.1.0 PRODUCER_FENCED error 3 2.4.0 Flexible versions 4 3.9.0 TRANSACTION_ABORTABLE (KIP-890)
AddOffsetsToTxnRequest =>
Field Type Description group_idSTRING Consumer group for offset commit
AddOffsetsToTxnResponse =>
Aspect Guarantee Coordination Offsets committed atomically with transaction Group ownership Does not require group membership Prerequisite Must call before TxnOffsetCommit
The TxnOffsetCommit API commits consumer offsets as part of a transaction.
Version Kafka Key Changes 0 0.11.0 Initial version 2 2.1.0 Committed leader epoch 3 2.4.0 Flexible versions + member fields 4 3.9.0 TRANSACTION_ABORTABLE (KIP-890) 5 4.0.0 Txn V2 add-offsets path (KIP-890 part 2)
TxnOffsetCommitRequest =>
group_instance_id: NULLABLE_STRING
committed_leader_epoch: INT32
committed_metadata: NULLABLE_STRING
Field Type Description generation_idINT32 Consumer group generation (-1 if not member) member_idSTRING Consumer member ID (empty if not member) committed_offsetINT64 Offset to commit
TxnOffsetCommitResponse =>
Aspect Guarantee Atomicity Offsets committed/aborted with transaction Visibility Offsets visible after transaction commit Prerequisite Must call AddOffsetsToTxn first
The EndTxn API commits or aborts an active transaction.
Version Kafka Key Changes 0 0.11.0 Initial version 2 2.1.0 PRODUCER_FENCED error 3 2.4.0 Flexible versions 4 3.9.0 TRANSACTION_ABORTABLE (KIP-890) 5 4.0.0 Producer ID/epoch in response
Field Type Description committedBOOLEAN true=COMMIT, false=ABORT
Transaction commit and marker writes to partitions and __consumer_offsets Transaction Producer Transaction Partition __consumer_offsets Producer Producer Transaction Coordinator Transaction Coordinator Partition Leaders Partition Leaders __consumer_offsets Leader __consumer_offsets Leader Transaction EndTxn(COMMIT) Move to PrepareCommit Write markers to partitions (in parallel) WriteTxnMarkers(COMMIT) OK Write markers to __consumer_offsets (in parallel) WriteTxnMarkers(COMMIT) OK Move to CompleteCommit OK
Aspect Guarantee Atomicity All partitions commit or abort together Durability Committed transactions survive broker failures Visibility After COMMIT, records visible to read_committed consumers Abort cleanup Aborted records filtered by read_committed consumers
Error Code Retriable Cause Recovery INVALID_PRODUCER_ID_MAPPING ❌ PID not found Reinitialize INVALID_PRODUCER_EPOCH ❌ Producer fenced Close producer INVALID_TXN_STATE ❌ No active transaction Start new transaction COORDINATOR_NOT_AVAILABLE ✅ Coordinator down Retry CONCURRENT_TRANSACTIONS ✅ Another end in progress Wait, retry
The WriteTxnMarkers API is an internal API used by transaction coordinators to write commit/abort markers to partitions.
Internal API
This API is used internally by the Kafka transaction protocol. Clients should not call this API directly.
Version Kafka Key Changes 0 0.11.0 Initial version (removed in 4.0) 1 2.4.0 Flexible versions (4.0 baseline) 2 4.0.0 TransactionVersion (KIP-1228)
WriteTxnMarkersRequest =>
transaction_result: BOOLEAN
transaction_version: INT8
partition_indexes: [INT32]
Field Type Description transaction_resultBOOLEAN true=COMMIT, false=ABORT coordinator_epochINT32 Coordinator epoch for fencing
WriteTxnMarkersResponse =>
The DescribeTransactions API retrieves information about active transactions.
Version Kafka Key Changes 0 3.0.0 Initial version
DescribeTransactionsRequest =>
transactional_ids: [STRING]
DescribeTransactionsResponse =>
transaction_states: [TransactionState]
transaction_state: STRING
transaction_timeout_ms: INT32
transaction_start_time_ms: INT64
Field Type Description transaction_stateSTRING Current state (Empty, Ongoing, etc.) transaction_start_time_msINT64 Transaction start timestamp topicsARRAY Partitions in transaction
The ListTransactions API lists transactions on a broker with optional filtering.
Version Kafka Key Changes 0 3.0.0 Initial version 1 3.5.0 Duration filter 2 4.0.0 TransactionalIdPattern (KIP-1152)
ListTransactionsRequest =>
producer_id_filters: [INT64]
transactional_id_pattern: NULLABLE_STRING
Field Type Description state_filtersARRAY Filter by state (empty for all) producer_id_filtersARRAY Filter by PID (empty for all) duration_filterINT64 Minimum transaction duration (ms) transactional_id_patternNULLABLE_STRING Regex filter for transactional.id (v2+)
ListTransactionsResponse =>
unknown_state_filters: [STRING]
transaction_states: [TransactionState]
transaction_state: STRING
Consume, transform, and produce loop within a transaction Consumer.Producer Source Topic Transaction Dest Topic Group Consumer/Producer Consumer/Producer Source Topic Source Topic Transaction Coordinator Transaction Coordinator Dest Topic Dest Topic Group Coordinator Group Coordinator Setup InitProducerId(txn_id) (PID, epoch) Processing Loop loop [for each batch] Fetch(read_committed) records Transform records AddPartitionsToTxn(dest) OK Produce(transformed) OK AddOffsetsToTxn(group) OK TxnOffsetCommit(offsets) OK EndTxn(COMMIT) OK
Consumer Isolation Behavior read_uncommittedSees all records including uncommitted read_committedOnly sees committed records, filters aborted
Records visible to read_uncommitted and read_committed consumers Records visible to read_uncommitted and read_committed consumers Log (partition) Record 1 (committed) Record 2 (committed) Record 3 (txn1-ongoing) Record 4 (committed) Record 5 (txn2-aborted) ABORT marker Record 6 (committed) read_uncommitted: R1, R2, R3, R4, R5, R6 read_committed: R1, R2, R4, R6 (R3 pending, R5 filtered)
Setting Default Description transactional.idnull Unique transaction identifier transaction.timeout.ms60000 Maximum transaction duration enable.idempotencetrue Required for transactions
Setting Default Description transaction.state.log.replication.factor3 Replication for transaction log transaction.state.log.min.isr2 Min ISR for transaction log transactional.id.expiration.ms604800000 Transaction ID expiration transaction.max.timeout.ms900000 Maximum allowed timeout
Setting Default Description isolation.levelread_uncommitted Transaction isolation
Practice Rationale Use unique transactional.id per producer instance Prevents conflicts Keep transactions short Avoid timeout and resource pressure Handle ProducerFencedException Indicates another producer took over Abort on any error Clean up partial transactions
Practice Rationale Use read_committed for exactly-once Filter uncommitted and aborted Process in batches within transactions Amortize transaction overhead Store offsets in transaction Atomic offset updates
Transaction error recovery decision flow Transaction error recovery decision flow Receive error from transaction API yes ProducerFencedException? Close producer Create new producer yes InvalidTxnStateException? Abort transaction Retry operation yes TimeoutException? Abort transaction Retry with fresh transaction yes Retriable error? other Retry with backoff Log error Abort transaction Escalate