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
When I talk about "One transaction needs one name everywhere", I am really asking what XID does when a message is late, duplicated, or missing.
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
I use "Checkout transaction example" to keep XID grounded in a real system, because abstract patterns are too easy to agree with and too hard to operate.
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
When I show "XID propagation code", I want the code in XID to reveal the production decision, not just the 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.