I use an XID when a business transaction crosses services and needs one identity everywhere. It is not just an idempotency key; it is the shared transaction id operators, logs, traces, and participants can all follow.
One transaction needs one name everywhere
I use this section to force the failure case into the conversation, not just the clean path.
Without a shared transaction id, each service may store its own local id. During an incident, operators then have to stitch together order id, payment id, ledger id, and message id. XID gives the distributed transaction one system wide identity.
Checkout transaction example
A practical example makes the hidden cost visible, especially around ownership and recovery.
A checkout creates XID TX 891. Order, payment, inventory, and ledger all store TX 891 so support can trace the complete transaction from one value.
XID propagation code
I use the code here to show the decision boundary, not just syntax.
Create the transaction id once and carry it through every participant:
String xid = xidGenerator.next();
orderService.create(xid, order);
paymentService.authorize(xid, payment);
ledgerService.post(xid, ledgerEntry);
The same XID travels through order, payment, and ledger calls. That gives the whole transaction one system-wide identity for audit and recovery.
Sequence diagram: carry the transaction id
The same XID appears in every participant so the transaction has one system wide identity.
The system wide identity rule
- Generate the XID once at the transaction boundary.
- Store it in every participant record and log line.
- Do not confuse it with an idempotency key for a single retryable request.