Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Kafka Transaction Protocol APIs

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 KeyNamePurpose
22InitProducerIdInitialize producer for idempotence/transactions
24AddPartitionsToTxnAdd partitions to active transaction
25AddOffsetsToTxnAdd consumer offsets to transaction
26EndTxnCommit or abort transaction
27WriteTxnMarkersWrite transaction markers (internal)
28TxnOffsetCommitCommit offsets within transaction
65DescribeTransactionsDescribe active transactions
66ListTransactionsList transactions on broker

Transaction lifecycle from InitProducerId to commit markersProducerTransactionPartitionGroupProducerProducerTransactionCoordinatorTransactionCoordinatorPartitionLeaderPartitionLeaderGroupCoordinatorGroupCoordinatorInitializationInitProducerId(txn_id)(PID, epoch)Begin TransactionbeginTransaction()Local state onlyProduceAddPartitionsToTxn(topic, partition)OKProduce(PID, epoch, records)AckOffset Commit (optional)AddOffsetsToTxn(group_id)OKTxnOffsetCommit(offsets)OKCommitEndTxn(COMMIT)WriteTxnMarkers(COMMIT)OKWriteTxnMarkers(COMMIT)OKOK
Transaction coordinator state transitionsTransaction coordinator state transitionsEmptyOngoingPrepareCommitPrepareAbortCompleteCommitCompleteAbortDeadInitProducerIdAddPartitionsToTxnAddPartitionsToTxnAddOffsetsToTxnProduceEndTxn(COMMIT)EndTxn(ABORT)timeoutmarkers writtenmarkers writtenreadyreadyexpirationproducer fenced

The InitProducerId API initializes a producer for idempotent or transactional operation by assigning a unique Producer ID (PID) and epoch.

VersionKafkaKey Changes
00.11.0Initial version
22.4.0Flexible versions
32.5.0Producer ID/epoch in request
42.6.0PRODUCER_FENCED error
53.9.0TRANSACTION_ABORTABLE error (KIP-890)
64.0.02PC support (KIP-939)
InitProducerIdRequest =>
transactional_id: NULLABLE_STRING
transaction_timeout_ms: INT32
producer_id: INT64
producer_epoch: INT16
enable2pc: BOOLEAN
keep_prepared_txn: BOOLEAN
FieldTypeDescription
transactional_idNULLABLE_STRINGTransaction ID (null for idempotent only)
transaction_timeout_msINT32Transaction timeout
producer_idINT64Existing PID to recover (-1 for new)
producer_epochINT16Existing epoch to recover (-1 for new)
enable2pcBOOLEANEnable two-phase commit (v6+)
keep_prepared_txnBOOLEANKeep prepared transaction (v6+)
InitProducerIdResponse =>
throttle_time_ms: INT32
error_code: INT16
producer_id: INT64
producer_epoch: INT16
ongoing_txn_producer_id: INT64
ongoing_txn_producer_epoch: INT16
FieldTypeDescription
producer_idINT64Assigned Producer ID
producer_epochINT16Producer epoch
ongoing_txn_producer_idINT64Producer ID for ongoing txn (v6+)
ongoing_txn_producer_epochINT16Producer epoch for ongoing txn (v6+)
Producer ID and epoch assignment across initialization and restartProducer ID and epoch assignment across initialization and restartFirst InitProducerIdTransactional InitProducerIdProducer Restarttransactional_id=nullproducer_id=-1Response:PID=12345epoch=0transactional_id='my-txn'producer_id=-1Response:PID=67890epoch=0transactional_id='my-txn'producer_id=-1Response:PID=67890epoch=1Same PID, incremented epochfences old producer
AspectGuarantee
PID uniquenessPID is globally unique per broker lifetime
Epoch incrementEpoch increments on each init with same transactional_id
FencingOld producers with same transactional_id are fenced
TimeoutTransaction must complete within transaction_timeout_ms
Error CodeRetriableCauseRecovery
COORDINATOR_NOT_AVAILABLECoordinator unavailableRetry
NOT_COORDINATORWrong coordinatorFindCoordinator, retry
CONCURRENT_TRANSACTIONSAnother init in progressWait, retry
INVALID_TRANSACTION_TIMEOUTTimeout out of rangeFix timeout
TRANSACTIONAL_ID_AUTHORIZATION_FAILEDNo permissionCheck ACLs

The AddPartitionsToTxn API adds topic partitions to an active transaction before producing to them.

VersionKafkaKey Changes
00.11.0Initial version
22.1.0PRODUCER_FENCED error
32.4.0Flexible versions
42.8.0VerifyOnly + batched transactions
53.9.0TRANSACTION_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]
Topic =>
name: STRING
partitions: [INT32]
Transaction =>
transactional_id: STRING
producer_id: INT64
producer_epoch: INT16
verify_only: BOOLEAN
topics: [Topic]
FieldTypeDescription
transactional_idSTRINGTransaction identifier
producer_idINT64Producer ID from InitProducerId
producer_epochINT16Producer epoch
ongoing_txn_producer_idINT64Producer ID for ongoing txn (v6+)
ongoing_txn_producer_epochINT16Producer epoch for ongoing txn (v6+)
topicsARRAYPartitions to add
AddPartitionsToTxnResponse =>
throttle_time_ms: INT32
error_code: INT16
results_by_transaction: [TransactionResult]
results_by_topic_v3_and_below: [TopicResult]
TopicResult =>
name: STRING
results_by_partition: [PartitionResult]
PartitionResult =>
partition_index: INT32
partition_error_code: INT16
AspectGuarantee
PreconditionTransaction must be ongoing (after InitProducerId)
IdempotenceAdding same partition multiple times is safe
OrderMust 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.

VersionKafkaKey Changes
00.11.0Initial version
22.1.0PRODUCER_FENCED error
32.4.0Flexible versions
43.9.0TRANSACTION_ABORTABLE (KIP-890)
AddOffsetsToTxnRequest =>
transactional_id: STRING
producer_id: INT64
producer_epoch: INT16
group_id: STRING
FieldTypeDescription
group_idSTRINGConsumer group for offset commit
AddOffsetsToTxnResponse =>
throttle_time_ms: INT32
error_code: INT16
AspectGuarantee
CoordinationOffsets committed atomically with transaction
Group ownershipDoes not require group membership
PrerequisiteMust call before TxnOffsetCommit

The TxnOffsetCommit API commits consumer offsets as part of a transaction.

VersionKafkaKey Changes
00.11.0Initial version
22.1.0Committed leader epoch
32.4.0Flexible versions + member fields
43.9.0TRANSACTION_ABORTABLE (KIP-890)
54.0.0Txn V2 add-offsets path (KIP-890 part 2)
TxnOffsetCommitRequest =>
transactional_id: STRING
group_id: STRING
producer_id: INT64
producer_epoch: INT16
generation_id: INT32
member_id: STRING
group_instance_id: NULLABLE_STRING
topics: [Topic]
Topic =>
name: STRING
partitions: [Partition]
Partition =>
partition_index: INT32
committed_offset: INT64
committed_leader_epoch: INT32
committed_metadata: NULLABLE_STRING
FieldTypeDescription
generation_idINT32Consumer group generation (-1 if not member)
member_idSTRINGConsumer member ID (empty if not member)
committed_offsetINT64Offset to commit
TxnOffsetCommitResponse =>
throttle_time_ms: INT32
topics: [Topic]
Topic =>
name: STRING
partitions: [Partition]
Partition =>
partition_index: INT32
error_code: INT16
AspectGuarantee
AtomicityOffsets committed/aborted with transaction
VisibilityOffsets visible after transaction commit
PrerequisiteMust call AddOffsetsToTxn first

The EndTxn API commits or aborts an active transaction.

VersionKafkaKey Changes
00.11.0Initial version
22.1.0PRODUCER_FENCED error
32.4.0Flexible versions
43.9.0TRANSACTION_ABORTABLE (KIP-890)
54.0.0Producer ID/epoch in response
EndTxnRequest =>
transactional_id: STRING
producer_id: INT64
producer_epoch: INT16
committed: BOOLEAN
FieldTypeDescription
committedBOOLEANtrue=COMMIT, false=ABORT
EndTxnResponse =>
throttle_time_ms: INT32
error_code: INT16
Transaction commit and marker writes to partitions and __consumer_offsetsTransactionProducerTransactionPartition__consumer_offsetsProducerProducerTransactionCoordinatorTransactionCoordinatorPartitionLeadersPartitionLeaders__consumer_offsetsLeader__consumer_offsetsLeaderTransactionEndTxn(COMMIT)Move to PrepareCommitWrite markers to partitions (in parallel)WriteTxnMarkers(COMMIT)OKWrite markers to __consumer_offsets (in parallel)WriteTxnMarkers(COMMIT)OKMove to CompleteCommitOK
AspectGuarantee
AtomicityAll partitions commit or abort together
DurabilityCommitted transactions survive broker failures
VisibilityAfter COMMIT, records visible to read_committed consumers
Abort cleanupAborted records filtered by read_committed consumers
Error CodeRetriableCauseRecovery
INVALID_PRODUCER_ID_MAPPINGPID not foundReinitialize
INVALID_PRODUCER_EPOCHProducer fencedClose producer
INVALID_TXN_STATENo active transactionStart new transaction
COORDINATOR_NOT_AVAILABLECoordinator downRetry
CONCURRENT_TRANSACTIONSAnother end in progressWait, 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.

VersionKafkaKey Changes
00.11.0Initial version (removed in 4.0)
12.4.0Flexible versions (4.0 baseline)
24.0.0TransactionVersion (KIP-1228)
WriteTxnMarkersRequest =>
markers: [Marker]
Marker =>
producer_id: INT64
producer_epoch: INT16
transaction_result: BOOLEAN
topics: [Topic]
coordinator_epoch: INT32
transaction_version: INT8
Topic =>
name: STRING
partition_indexes: [INT32]
FieldTypeDescription
transaction_resultBOOLEANtrue=COMMIT, false=ABORT
coordinator_epochINT32Coordinator epoch for fencing
WriteTxnMarkersResponse =>
markers: [Marker]
Marker =>
producer_id: INT64
topics: [Topic]
Topic =>
name: STRING
partitions: [Partition]
Partition =>
partition_index: INT32
error_code: INT16

The DescribeTransactions API retrieves information about active transactions.

VersionKafkaKey Changes
03.0.0Initial version
DescribeTransactionsRequest =>
transactional_ids: [STRING]
DescribeTransactionsResponse =>
throttle_time_ms: INT32
transaction_states: [TransactionState]
TransactionState =>
error_code: INT16
transactional_id: STRING
transaction_state: STRING
transaction_timeout_ms: INT32
transaction_start_time_ms: INT64
producer_id: INT64
producer_epoch: INT16
topics: [Topic]
Topic =>
topic: STRING
partitions: [INT32]
FieldTypeDescription
transaction_stateSTRINGCurrent state (Empty, Ongoing, etc.)
transaction_start_time_msINT64Transaction start timestamp
topicsARRAYPartitions in transaction

The ListTransactions API lists transactions on a broker with optional filtering.

VersionKafkaKey Changes
03.0.0Initial version
13.5.0Duration filter
24.0.0TransactionalIdPattern (KIP-1152)
ListTransactionsRequest =>
state_filters: [STRING]
producer_id_filters: [INT64]
duration_filter: INT64
transactional_id_pattern: NULLABLE_STRING
FieldTypeDescription
state_filtersARRAYFilter by state (empty for all)
producer_id_filtersARRAYFilter by PID (empty for all)
duration_filterINT64Minimum transaction duration (ms)
transactional_id_patternNULLABLE_STRINGRegex filter for transactional.id (v2+)
ListTransactionsResponse =>
throttle_time_ms: INT32
error_code: INT16
unknown_state_filters: [STRING]
transaction_states: [TransactionState]
TransactionState =>
transactional_id: STRING
producer_id: INT64
transaction_state: STRING

Consume, transform, and produce loop within a transactionConsumer.ProducerSource TopicTransactionDest TopicGroupConsumer/ProducerConsumer/ProducerSource TopicSource TopicTransactionCoordinatorTransactionCoordinatorDest TopicDest TopicGroupCoordinatorGroupCoordinatorSetupInitProducerId(txn_id)(PID, epoch)Processing Looploop[for each batch]Fetch(read_committed)recordsTransform recordsAddPartitionsToTxn(dest)OKProduce(transformed)OKAddOffsetsToTxn(group)OKTxnOffsetCommit(offsets)OKEndTxn(COMMIT)OK
Consumer IsolationBehavior
read_uncommittedSees all records including uncommitted
read_committedOnly sees committed records, filters aborted
Records visible to read_uncommitted and read_committed consumersRecords visible to read_uncommitted and read_committed consumersLog (partition)Record 1(committed)Record 2(committed)Record 3(txn1-ongoing)Record 4(committed)Record 5(txn2-aborted)ABORT markerRecord 6(committed)read_uncommitted: R1, R2, R3, R4, R5, R6read_committed: R1, R2, R4, R6(R3 pending, R5 filtered)

SettingDefaultDescription
transactional.idnullUnique transaction identifier
transaction.timeout.ms60000Maximum transaction duration
enable.idempotencetrueRequired for transactions
SettingDefaultDescription
transaction.state.log.replication.factor3Replication for transaction log
transaction.state.log.min.isr2Min ISR for transaction log
transactional.id.expiration.ms604800000Transaction ID expiration
transaction.max.timeout.ms900000Maximum allowed timeout
SettingDefaultDescription
isolation.levelread_uncommittedTransaction isolation

PracticeRationale
Use unique transactional.id per producer instancePrevents conflicts
Keep transactions shortAvoid timeout and resource pressure
Handle ProducerFencedExceptionIndicates another producer took over
Abort on any errorClean up partial transactions
PracticeRationale
Use read_committed for exactly-onceFilter uncommitted and aborted
Process in batches within transactionsAmortize transaction overhead
Store offsets in transactionAtomic offset updates
Transaction error recovery decision flowTransaction error recovery decision flowReceive error from transaction APIyesProducerFencedException?Close producerCreate new produceryesInvalidTxnStateException?Abort transactionRetry operationyesTimeoutException?Abort transactionRetry with fresh transactionyesRetriable error?otherRetry with backoffLog errorAbort transactionEscalate