Network Working Group B. Venkateswaran Internet-Draft A. Jamwal Intended status: Experimental Salesforce Expires: 22 January 2027 21 July 2026 2-Phase HTTP Protocol for Distributed Transaction Tracking (2PHP-DTT) draft-venkateswaran-jamwal-twophp-01 Abstract This document specifies the 2-Phase HTTP Protocol for Distributed Transaction Tracking (2PHP-DTT), a backward-compatible, opt-in extension to HTTP mutation semantics that introduces a two-phase handshake at service request boundaries. 2PHP ensures that a mutation request is durably registered on both the client and the server before any processing commences, addressing a structural gap in existing HTTP REST semantics where no standard mechanism exists to confirm bilateral intent registration prior to execution. The acronym DTT expands to Distributed Transaction Tracking. 2PHP is not Two-Phase Commit (2PC). Microservices architectures deliberately avoid the cross-service locking and blocking that 2PC requires. 2PHP standardizes the intent-tracking pattern that implementations currently build ad hoc, providing a common wire contract and a queryable ledger of registered intent without introducing a distributed transaction coordinator. A primary motivator for this work is the growing use of agent-driven HTTP invocations, including Model Context Protocol (MCP) tool calls and agent-to-agent (A2A) integrations. When an agent does not receive a response, its default behavior is to retry. Absent a queryable record of prior intent, retries pile onto services that may already be overwhelmed, causing deadlocks, resource exhaustion, and full outages. 2PHP's Phase 1 ledger record enables the client to inspect whether the prior intent was registered before issuing a retry, breaking the retry-storm feedback loop at the protocol layer. 2PHP operates at the HTTP protocol layer, requires no new transport mechanisms, and is composable across independently operating service boundaries. This document further defines a standardized Intent Ledger model for durable, queryable, cross-service correlation of request intent, distinct from execution telemetry provided by distributed tracing systems. This document does not claim novelty over existing intent-tracking, idempotency, or distributed-tracing patterns. Its goal is to define a common HTTP-layer wire contract and a common ledger schema so that Venkateswaran & Jamwal Expires 22 January 2027 [Page 1] Internet-Draft 2PHP-DTT July 2026 a single reference implementation--packaged as a library or framework module--can serve multiple deployments, replacing the per-team ad hoc implementations that currently reinvent this pattern. This document defines the protocol headers, phase state machine, idempotency and replay behavior, the three-tier Intent Ledger architecture, cross-service correlation model, and IANA registration of the associated HTTP header fields. 2PHP-DTT targets the synchronous request-response boundary, where no standard acknowledgement primitive exists to confirm bilateral intent registration before processing. Asynchronous HTTP patterns -- 202 Accepted with Location-based polling in HTTP Semantics, Prefer: respond-async negotiation, webhooks, and message-broker delivery -- already provide durable acknowledgement of intent by construction, and are therefore out of scope for this specification. Status of This Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on 22 January 2027. Copyright Notice Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/ license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Venkateswaran & Jamwal Expires 22 January 2027 [Page 2] Internet-Draft 2PHP-DTT July 2026 Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 2. Conventions and Definitions . . . . . . . . . . . . . . . . . 6 3. Problem Statement . . . . . . . . . . . . . . . . . . . . . . 7 3.1. The Request Boundary Gap . . . . . . . . . . . . . . . . 7 3.2. Limitations of Existing Telemetry . . . . . . . . . . . . 7 3.3. Limitations of Existing Patterns . . . . . . . . . . . . 8 4. Protocol Overview . . . . . . . . . . . . . . . . . . . . . . 8 5. Protocol Specification . . . . . . . . . . . . . . . . . . . 9 5.1. Opt-In Header . . . . . . . . . . . . . . . . . . . . . . 9 5.2. Phase 1 -- Intent Registration . . . . . . . . . . . . . 9 5.2.1. Client Request . . . . . . . . . . . . . . . . . . . 9 5.2.2. Server Response . . . . . . . . . . . . . . . . . . . 10 5.2.3. Client Ledger Write . . . . . . . . . . . . . . . . . 11 5.3. Phase 2 -- Client Confirmation . . . . . . . . . . . . . 11 5.3.1. Client Request . . . . . . . . . . . . . . . . . . . 11 5.3.2. Server Response . . . . . . . . . . . . . . . . . . . 11 5.4. TTL Expiry . . . . . . . . . . . . . . . . . . . . . . . 12 5.5. Auto-Confirm Mode . . . . . . . . . . . . . . . . . . . . 12 5.5.1. Overview . . . . . . . . . . . . . . . . . . . . . . 12 5.5.2. Activation Header . . . . . . . . . . . . . . . . . . 13 5.5.3. Protocol Flow . . . . . . . . . . . . . . . . . . . . 14 5.5.4. State Machine -- Auto-Confirm Mode . . . . . . . . . 14 5.5.5. Mode Comparison . . . . . . . . . . . . . . . . . . . 15 6. State Machine . . . . . . . . . . . . . . . . . . . . . . . . 15 7. Phase States . . . . . . . . . . . . . . . . . . . . . . . . 16 8. Idempotency and Replay Behavior . . . . . . . . . . . . . . . 16 8.1. Replay Before TTL . . . . . . . . . . . . . . . . . . . . 16 8.2. Replay After TTL . . . . . . . . . . . . . . . . . . . . 16 9. Intent Ledger . . . . . . . . . . . . . . . . . . . . . . . . 17 9.1. Overview . . . . . . . . . . . . . . . . . . . . . . . . 17 9.2. Relationship to Distributed Tracing . . . . . . . . . . . 17 9.3. Normative Role . . . . . . . . . . . . . . . . . . . . . 18 9.4. Ledger Schema . . . . . . . . . . . . . . . . . . . . . . 18 10. Cross-Service Correlation . . . . . . . . . . . . . . . . . . 19 10.1. Overview . . . . . . . . . . . . . . . . . . . . . . . . 19 10.2. Propagation Rules . . . . . . . . . . . . . . . . . . . 19 10.3. Example Call Chain . . . . . . . . . . . . . . . . . . . 20 10.4. Tree Reconstruction Query Patterns . . . . . . . . . . . 20 11. Backward Compatibility . . . . . . . . . . . . . . . . . . . 20 12. Implementation Considerations . . . . . . . . . . . . . . . . 21 12.1. Reference Implementation Targets . . . . . . . . . . . . 21 12.2. Durable Storage for Phase 1 Persistence . . . . . . . . 21 12.3. TTL Defaults . . . . . . . . . . . . . . . . . . . . . . 21 12.4. Service Ledger Registration . . . . . . . . . . . . . . 22 12.5. Recommended Ledger Architecture . . . . . . . . . . . . 22 12.6. On-Demand Pull from Central Ledger . . . . . . . . . . . 23 Venkateswaran & Jamwal Expires 22 January 2027 [Page 3] Internet-Draft 2PHP-DTT July 2026 12.7. Operational Modes . . . . . . . . . . . . . . . . . . . 23 13. Security Considerations . . . . . . . . . . . . . . . . . . . 24 13.1. Correlation ID Confidentiality . . . . . . . . . . . . . 24 13.2. Phase 2 Spoofing . . . . . . . . . . . . . . . . . . . . 24 13.3. Replay Semantics . . . . . . . . . . . . . . . . . . . . 24 13.4. Intent Payload Confidentiality . . . . . . . . . . . . . 25 13.5. Ledger Access Control . . . . . . . . . . . . . . . . . 25 13.6. Transport Security . . . . . . . . . . . . . . . . . . . 25 14. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 25 14.1. HTTP Field Name Registrations . . . . . . . . . . . . . 25 15. Normative References . . . . . . . . . . . . . . . . . . . . 26 16. Informative References . . . . . . . . . . . . . . . . . . . 26 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 27 1. Introduction Microservices architectures built on HTTP REST APIs are widely deployed for distributed systems communication. Mutation requests-- those using HTTP methods POST, PUT, PATCH, and DELETE--are treated as single atomic operations from the client's perspective. In practice, however, no standard protocol mechanism exists to confirm that both the client and server have durably registered the intent of a request before processing begins. Existing approaches--including the Saga pattern [SAGA], Transactional Outbox [OUTBOX], and application-layer idempotency keys--address failure recovery after the fact or are implemented ad hoc without a standard contract. Distributed tracing systems such as OpenTelemetry [OTEL] provide execution telemetry but cannot answer whether both parties registered intent before processing commenced. This document specifies the 2-Phase HTTP Protocol for Distributed Transaction Tracking (2PHP-DTT), an opt-in, backward-compatible extension to HTTP that introduces a lightweight two-phase handshake at each service boundary. 2PHP ensures bilateral durable registration of request intent before any business logic is executed. It further defines a standardized Intent Ledger model that enables cross-service correlation of request intent across distributed call trees. Venkateswaran & Jamwal Expires 22 January 2027 [Page 4] Internet-Draft 2PHP-DTT July 2026 The acronym DTT expands to Distributed Transaction Tracking. 2PHP is not Two-Phase Commit (2PC). 2PC requires cross-service locking and blocking coordination that microservices architectures deliberately avoid. 2PHP introduces no distributed transaction coordinator, no cross-service locks, and no thread-blocking. Each service boundary owns its own handshake independently; the Intent Ledger is a passive, queryable record of that handshake, not a coordinator. What is standardized here is the tracking pattern that implementations currently build ad hoc: a common wire contract and a common ledger contract, rather than a per-team reinvention. A primary motivator for this work is the growing use of agent-driven HTTP invocations, including Model Context Protocol (MCP) tool calls and agent-to-agent (A2A) integrations. Agents default to retrying when a response is not received within an expected window. Without a queryable record of prior intent, successive retries--often from multiple relays or peer agents--pile onto services that may already be overwhelmed. The result is server-side deadlocks, resource exhaustion, and cascading outages. 2PHP's Phase1 ledger record enables the client, upstream service, or orchestrating agent to inspect whether the prior intent was durably registered before issuing a retry, breaking the retry-storm feedback loop at the protocol layer. This inspection step is the first line of defense in agent-driven integration topologies where retry pressure is otherwise unbounded. This gap is specific to synchronous HTTP invocations. Asynchronous integration patterns--202 Accepted responses with Location-based status polling ([RFC9110]), Prefer: respond-async negotiation ([RFC7240]), webhooks, and message-broker delivery--already provide a durable acknowledgement of intent as part of their wire contract: the client receives a handle or ack the moment the server accepts the request, and inspecting prior state before retrying is built in. 2PHP-DTT does not attempt to duplicate those mechanisms. It addresses the boundary they leave open: synchronous request-response calls, which remain the dominant integration style for microservices and agent-driven tool invocations. The value proposition of this specification is standardization, not novel mechanism. Intent tracking, idempotent retries, and correlation-based inspection are all patterns implemented today across microservices deployments, typically ad hoc and per-team. This document does not claim to be the only solution to any of these problems, nor does it claim novelty over existing patterns. Its aim is a consistent, standardized wire contract for intent registration and Distributed Transaction Tracking: client-supplied correlation identifiers, an explicit phase state contract carried in HTTP header fields, and a queryable Intent Ledger schema, specified together so Venkateswaran & Jamwal Expires 22 January 2027 [Page 5] Internet-Draft 2PHP-DTT July 2026 that a common implementation--packaged as a library in Spring Boot, Express.js, an API gateway policy, or an agent framework middleware-- can serve heterogeneous deployments without per-vendor reinvention. Where deployments already use client-supplied identifiers for retry safety, the correlation identifier defined here MAY carry the same value; nothing in this document precludes composing 2PHP-DTT with existing idempotency, retry, or tracing conventions. 2PHP is designed to be: * *Backward compatible*--servers and clients that do not implement 2PHP are unaffected. * *Lightweight*--two HTTP round trips; no new transport layer. * *Composable*--each service boundary operates independently; no distributed coordination is required. * *Standardized*--a consistent header contract enabling uniform tooling, observability, and governance. 2. Conventions and Definitions The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. 2PHP: The 2-Phase HTTP Protocol, as defined in this document. Phase 1: The Intent Registration phase, in which the client sends a mutation request and the server durably persists the request payload and an initial ledger record before responding. Phase 2: The Client Confirmation phase, in which the client confirms receipt of the Phase1 acknowledgement, triggering server-side business logic execution. PONR (Point of No Return): The moment at which the server begins executing business logic after receiving Phase2 confirmation. Processing cannot be rolled back after this point. TTL (Time to Live): The server-defined duration, in milliseconds, within which the client MUST send Phase2 confirmation. Delta (delta): A server-internal grace window applied after TTL Venkateswaran & Jamwal Expires 22 January 2027 [Page 6] Internet-Draft 2PHP-DTT July 2026 expiry to handle race conditions at the PONR boundary. Not exposed to the client. Intent Ledger: A durable, queryable log of 2PHP transactions, distinct from execution telemetry. Local Ledger: A per-service, in-process ledger authoritative for that service's phase states. Central Ledger: A read-optimized aggregate view of all local ledgers, populated via background batch sync. Client Correlation ID: A client-assigned identifier for a specific request, included in all protocol headers and ledger entries for that interaction. Server Correlation ID: A server-assigned identifier for a specific intent registration, returned in the Phase1 response. Parent Reference ID: The correlation ID that the immediate upstream caller provided when initiating the call to a downstream service. Used to reconstruct distributed call trees. 3. Problem Statement 3.1. The Request Boundary Gap Current HTTP REST semantics treat a mutation request as a single atomic operation from the client's perspective. In reality, a server may: * Receive and process the request without the client ever confirming receipt of the response. * Fail mid-processing with no durable record of the original intent. * Return a success response that is lost in transit. No standard HTTP mechanism exists to confirm that both the client and the server have registered the intent of a request before processing commences. 3.2. Limitations of Existing Telemetry Modern distributed tracing systems provide visibility into what executed across services, how long operations took, and where failures occurred. However, they cannot answer: Venkateswaran & Jamwal Expires 22 January 2027 [Page 7] Internet-Draft 2PHP-DTT July 2026 * Did both client and server register the intent before processing? * Was a request abandoned or confirmed? * At what phase did a distributed transaction stall? 3.3. Limitations of Existing Patterns +===============+=============+===========+==========+=========+ | Pattern | Scope | Client | Protocol | Intent | | | | Involved? | Level? | Ledger? | +===============+=============+===========+==========+=========+ | Two-Phase | Database | No | No | No | | Commit (2PC) | | | | | +---------------+-------------+-----------+----------+---------+ | Saga Pattern | Application | No | No | No | +---------------+-------------+-----------+----------+---------+ | Transactional | Server-side | No | No | No | | Outbox | | | | | +---------------+-------------+-----------+----------+---------+ | Idempotency | Application | Partial | No | No | | Keys | | | | | +---------------+-------------+-----------+----------+---------+ | HTTP 100 | Protocol | Yes | Yes | No | | Continue | | | | | +---------------+-------------+-----------+----------+---------+ | 2PHP (this | Protocol | Yes | Yes | Yes | | document) | | | | | +---------------+-------------+-----------+----------+---------+ Table 1 4. Protocol Overview 2PHP extends HTTP mutation semantics with an opt-in two-phase handshake. Each service boundary owns its own independent handshake. Cross-service traceability is the responsibility of the centralized Intent Ledger, not the protocol itself. Venkateswaran & Jamwal Expires 22 January 2027 [Page 8] Internet-Draft 2PHP-DTT July 2026 Client Server | | |-- Phase 1: POST + payload --------> | | | Persist payload + | | ledger record atomically | <-- 200 OK + Server-Corr-ID ------- | | | | (Client writes local ledger entry) | | | |-- Phase 2: POST confirm ----------> | | | PONR crossed; | | business logic executes | <-- 200 OK + Resource-ID ---------- | | | Figure 1: 2PHP Protocol Flow (Synchronous Mode) The server MUST atomically persist the intent payload and the initial ledger record before returning the Phase1 response. The resource is created only after Phase2 confirmation is received and business logic has successfully executed. 5. Protocol Specification 5.1. Opt-In Header Clients signal 2PHP intent by including the following header on any mutation request: DTT-2PHP-Enabled: true Servers that do not recognize this header MUST ignore it and process the request normally, preserving backward compatibility. 5.2. Phase 1 -- Intent Registration 5.2.1. Client Request POST /orders HTTP/1.1 DTT-2PHP-Enabled: true DTT-2PHP-Requested-TTL: DTT-2PHP-Client-Correlation-ID: Content-Type: application/json { ...payload... } Venkateswaran & Jamwal Expires 22 January 2027 [Page 9] Internet-Draft 2PHP-DTT July 2026 The client MUST include DTT-2PHP-Client-Correlation-ID with a unique identifier for this request. This identifier MUST be used in all subsequent protocol exchanges and ledger entries for this interaction. The server MUST NOT substitute a server-generated proxy for this identifier: without a client-supplied identifier the client cannot deterministically query the ledger for prior intent, which is the retry-inspection guarantee that motivates this specification. If a request carries DTT-2PHP-Enabled: true but omits DTT-2PHP- Client-Correlation-ID, the server MUST reject the request with 400 Bad Request and populate DTT-2PHP-Message to identify the missing header. The server MUST NOT synthesize a correlation identifier on the client's behalf. This requirement applies to both Standard 2PHP (Section 5.3) and Auto-Confirm mode (Section 5.5). The client MAY include DTT-2PHP-Requested-TTL (in milliseconds) to request that the server override its default TTL setting. 5.2.2. Server Response The server MUST atomically persist the intent payload and an initial ledger record with phase state WAITING_CONFIRM before returning the response. HTTP/1.1 200 OK DTT-2PHP-Server-Correlation-ID: DTT-2PHP-Phase-State: WAITING_CONFIRM DTT-2PHP-TTL: DTT-2PHP-PONR-Deadline: Response header semantics: DTT-2PHP-Server-Correlation-ID: Server-assigned identifier for this intent registration. The client MUST echo this value in the Phase2 confirmation. DTT-2PHP-TTL: Milliseconds the server will wait for Phase2 confirmation. Server-defined. The client MUST send Phase2 before this duration elapses. If the client includes DTT-2PHP-Requested- TTL, the server MAY accommodate by increasing the TTL. DTT-2PHP-PONR-Deadline: Server-computed absolute deadline in ISO8601 format. The client MUST send Phase2 before this timestamp. DTT-2PHP-Phase-State: Current phase state. Value is WAITING_CONFIRM on Phase1 response. Venkateswaran & Jamwal Expires 22 January 2027 [Page 10] Internet-Draft 2PHP-DTT July 2026 No DTT-2PHP-Resource-ID is returned in Phase1. The resource does not yet exist; it is created only after Phase2 confirmation is received and business logic has successfully executed. 5.2.3. Client Ledger Write After receiving the Phase1 response, the client MUST write a ledger entry to its local ledger. The client writes after the Phase1 response so that both client_correlation_id and server_correlation_id are available at write time. The client's parent_reference_id MUST be set to its own client_correlation_id as the root anchor. 5.3. Phase 2 -- Client Confirmation 5.3.1. Client Request The client confirms receipt of the Phase1 acknowledgement: POST /orders/confirm HTTP/1.1 DTT-2PHP-Enabled: true DTT-2PHP-Client-Correlation-ID: DTT-2PHP-Server-Correlation-ID: The client MUST send Phase2 before the DTT-2PHP-PONR-Deadline timestamp received in the Phase1 response. A 2PHP-capable client MUST NOT send a Phase2 confirmation if the Phase1 response omitted the DTT-2PHP-Server-Correlation-ID header. The absence of that header indicates the server did not process the request under 2PHP semantics--typically because the server does not implement this specification. In that case the response MUST be treated as a conventional terminal HTTP response and the client MUST NOT issue a Phase2 request against any derived path. This preserves backward compatibility with servers that ignore the DTT-2PHP-Enabled opt-in header (see Section 11). 5.3.2. Server Response This revision specifies synchronous operation only. On receipt of a valid Phase2 confirmation, the server crosses the PONR, executes business logic inline, and responds once processing is complete: HTTP/1.1 200 OK DTT-2PHP-Phase-State: COMMITTED DTT-2PHP-Resource-ID: Venkateswaran & Jamwal Expires 22 January 2027 [Page 11] Internet-Draft 2PHP-DTT July 2026 The server MUST return 200 OK only after business logic has completed and the resource is fully created. The DTT-2PHP-Resource-ID is authoritative--the resource exists at the point this response is returned. If business logic fails after PONR is crossed, the server MUST return 500 Internal Server Error. If the request is invalid, the server MUST return the appropriate 4xx response. In both cases the client receives a definitive outcome in the Phase2 response--no polling is required. Asynchronous operation is out of scope for this specification by design, not deferred. Asynchronous HTTP already provides a durable acknowledgement primitive: 202 Accepted with a Location handle for status polling as defined in [RFC9110], optionally negotiated with Prefer: respond-async as defined in [RFC7240]. Webhook and message- broker delivery models similarly bake acknowledgement into their wire contract. In all of these, the client learns whether the server registered its intent the moment the request is accepted, which is precisely the gap 2PHP-DTT addresses for synchronous calls. Servers requiring asynchronous execution semantics SHOULD use those established mechanisms rather than extending 2PHP-DTT. 5.4. TTL Expiry Any Phase2 confirmation received after TTL expiry MUST be rejected with: HTTP/1.1 408 Request Timeout DTT-2PHP-Phase-State: TTL_EXPIRED DTT-2PHP-Message: Request TTL exceeded. Re-submit as new request. The server MAY apply an internal grace window (delta) after TTL expiry to handle race conditions at the PONR boundary. This grace window is server-internal and MUST NOT be exposed in protocol headers or communicated to the client. 5.5. Auto-Confirm Mode 5.5.1. Overview Auto-Confirm mode is an opt-in server-side mode that eliminates the explicit Phase2 client confirmation round trip. When Auto-Confirm is enabled, the server writes the ledger record and crosses the PONR immediately after Phase1, then executes business logic inline on the original request channel. The final result (200 OK + DTT-2PHP- Resource-ID) is returned synchronously on that same channel-- behaviorally identical to a standard HTTP request from the client's Venkateswaran & Jamwal Expires 22 January 2027 [Page 12] Internet-Draft 2PHP-DTT July 2026 perspective. Auto-Confirm mode does not include an out-of-band callback. Earlier revisions of this specification described an asynchronous server-to- client callback to deliver the intent acknowledgement independently of the original response channel. That mechanism has been removed because it introduced failure modes (callback delivery loss, client callback endpoint availability, and server-side SSRF exposure via a client-supplied URL) that outweighed its observability benefit. Clients that require an out-of-band record of registered intent SHOULD use Standard 2PHP (Section 5.3), which records client-side intent by construction. The client MUST include DTT-2PHP-Client-Correlation-ID on the Phase1 request in Auto-Confirm mode, as in Standard 2PHP (Section 5.2.1). The server MUST NOT substitute a server-generated proxy for this identifier: without a client-supplied correlation identifier the client cannot deterministically query the ledger for prior intent, which defeats the retry-inspection guarantee that motivates this specification. Requests missing this header MUST be rejected with 400 Bad Request and DTT-2PHP-Message indicating the missing header. The server MUST return DTT-2PHP-Server-Correlation-ID in the response so the client can correlate the ledger record with its own request. Auto-Confirm mode is valuable for: * *Low-latency critical paths*--the Phase2 round trip cost is eliminated while preserving bilateral ledger participation. * *Server-side opt-in*--platform teams can enable ledger tracking without requiring clients to implement the Phase2 confirmation step, provided the client is willing to attach a correlation identifier. * *Idempotent retries by inspection*-- because the client supplies the correlation identifier, a client that does not receive the final response can query the ledger by DTT-2PHP-Client- Correlation-ID to determine whether the intent was registered and, if so, its terminal outcome, before issuing any retry. 5.5.2. Activation Header DTT-2PHP-Auto-Confirm: true DTT-2PHP-Auto-Confirm: When true, the server does not wait for a Phase2 confirmation before crossing the PONR and executing business logic. The final outcome is returned synchronously on the original request channel. Venkateswaran & Jamwal Expires 22 January 2027 [Page 13] Internet-Draft 2PHP-DTT July 2026 5.5.3. Protocol Flow Client Server | | |-- POST /orders ------------------> | | DTT-2PHP-Enabled: true | | DTT-2PHP-Auto-Confirm: true | | DTT-2PHP-Client-Corr-ID: C1 | | | | Ledger write | | (WAITING_CONFIRM -> | | PROCESSING, atomic) | | PONR crossed | | | | Server processes inline | | | | <-- 200 OK + Resource-ID -------- | | DTT-2PHP-Phase-State: | | COMMITTED | | DTT-2PHP-Server-Corr-ID: S1 | | | Figure 2: Auto-Confirm Mode 5.5.4. State Machine -- Auto-Confirm Mode Client POST (Phase 1, DTT-2PHP-Auto-Confirm: true) | v ( WAITING_CONFIRM ) <-- ledger write (transient, atomic) | v (immediate -- PONR crossed, no client confirmation) ( PROCESSING ) | +-- Success --> ( COMMITTED ) <-- 200 OK + Resource-ID | on original channel | +-- Failure --> ( FAILED ) <-- 500 / 4xx on original channel Figure 3: Auto-Confirm Phase State Machine In Auto-Confirm mode, WAITING_CONFIRM is a transient internal state written and immediately superseded by PROCESSING within the same atomic ledger operation. It is never visible to the client on the original channel. Venkateswaran & Jamwal Expires 22 January 2027 [Page 14] Internet-Draft 2PHP-DTT July 2026 5.5.5. Mode Comparison +==============+==========+=========+==============+===============+ | Mode | Phase 2 | Latency | Client 2PHP | Ledger | | | Required | | Support | Participation | +==============+==========+=========+==============+===============+ | Standard | Yes | 2 round | Full | Both sides | | 2PHP | | trips | (correlation | | | | | | ID + Phase2) | | +--------------+----------+---------+--------------+---------------+ | Auto-Confirm | No | 1 round | Correlation | Both sides | | | | trip | ID only | | +--------------+----------+---------+--------------+---------------+ Table 2 6. State Machine Client POST (Phase 1) | v ( WAITING_CONFIRM ) <-- persisted in durable storage | +-- Client confirms within TTL | | | v | ( PROCESSING ) <-- PONR crossed; business logic | | executing | | | +-- Success --> ( COMMITTED ) <- 200 OK + | | Resource-ID | +-- Failure --> ( FAILED ) <- 500 / 4xx | +-- TTL expires without confirmation | v ( TTL_EXPIRED ) -- after PONR + delta grace --> ( ABANDONED ) Figure 4: 2PHP Phase State Machine Venkateswaran & Jamwal Expires 22 January 2027 [Page 15] Internet-Draft 2PHP-DTT July 2026 7. Phase States +=================+===============================================+ | State | Description | +=================+===============================================+ | WAITING_CONFIRM | Phase1 received and persisted. Awaiting | | | client Phase2 confirmation. | +-----------------+-----------------------------------------------+ | PROCESSING | Phase2 confirmed. PONR crossed. Business | | | logic executing (synchronous mode). | +-----------------+-----------------------------------------------+ | COMMITTED | Processing complete. Resource created. | | | Terminal success state. | +-----------------+-----------------------------------------------+ | FAILED | Processing failed after PONR. Server | | | returned 500 or 4xx. Terminal failure state. | +-----------------+-----------------------------------------------+ | TTL_EXPIRED | Client did not confirm within TTL. Pending | | | cleanup. | +-----------------+-----------------------------------------------+ | ABANDONED | Cleaned up after TTL + delta grace window. | | | Terminal state. | +-----------------+-----------------------------------------------+ Table 3 8. Idempotency and Replay Behavior 8.1. Replay Before TTL If a client replays Phase2 before TTL expiry, the server MUST return the same response associated with the original DTT-2PHP-Server- Correlation-ID. No duplicate processing occurs. 8.2. Replay After TTL Any Phase2 confirmation received after TTL expiry MUST be rejected with 408 Request Timeout and DTT-2PHP-Phase-State: TTL_EXPIRED, consistent with Section 5.4. The client MUST re-submit as a new Phase1 request with a new DTT-2PHP-Client-Correlation-ID. A late Phase2 confirmation carrying the same correlation IDs MUST NOT be reused to trigger execution of the persisted intent. Venkateswaran & Jamwal Expires 22 January 2027 [Page 16] Internet-Draft 2PHP-DTT July 2026 This revision defines a single replay behavior. Earlier revisions described a per-endpoint REUSE policy that allowed acceptance of a late Phase2 within the server-internal delta grace window. That policy has been removed because it created an ambiguous boundary with Section 5.4 and expanded the replay-attack surface without a durable operational benefit. 9. Intent Ledger 9.1. Overview The Intent Ledger is a durable, queryable log of all 2PHP transactions. It is distinct from execution telemetry--it is an intent registry, not a trace of execution. Its purpose is to provide provable bilateral registration of every mutation intent across all participating services. 9.2. Relationship to Distributed Tracing The Intent Ledger is complementary to distributed tracing systems such as OpenTelemetry [OTEL], not a replacement. Distributed tracing records what executed: spans, timings, causal links, and error paths, typically aggregated in a downstream store with some ingestion lag. It is the appropriate tool for post-hoc analysis of execution behavior. The Intent Ledger records what was _registered as intent_ before execution began, and makes that record queryable in real time at the point of registration. This serves a different question than tracing: not "what happened?" but "did the server acknowledge my intent, and should I retry?" A client that does not receive the expected response can query the ledger by DTT-2PHP-Client- Correlation-ID to determine whether the prior intent was durably registered before issuing a retry. This inspection step is only useful if the answer is available synchronously and locally to the participating service, which is why the ledger is normatively local- first (Section 12.5) rather than a downstream aggregation. Deployments SHOULD run both. Tracing answers questions about execution across services; the Intent Ledger answers questions about registered intent at each service boundary. Neither subsumes the other. Venkateswaran & Jamwal Expires 22 January 2027 [Page 17] Internet-Draft 2PHP-DTT July 2026 9.3. Normative Role At each service boundary, the Intent Ledger MUST record a durable entry for every Phase1 receipt and every subsequent phase transition, and that entry MUST be queryable by DTT-2PHP-Client-Correlation-ID and by DTT-2PHP-Server-Correlation-ID before Phase2 is processed. The ledger write and the intent-payload persistence MUST be committed as a single unit of work (see Section 5.2.2). 2PHP-DTT is not a Distributed Transaction Coordinator: no cross- service locking, thread blocking, or two-phase commit is defined or required. Each service boundary owns its own handshake and its own ledger authoritative record. How the ledger is stored, tiered, replicated, or exposed for aggregate query is an implementation matter and is discussed in Section 12.5. 9.4. Ledger Schema Each ledger entry MUST include the following fields: +=======================+==========================================+ | Field | Description | +=======================+==========================================+ | client_correlation_id | Client-assigned request identifier. | +-----------------------+------------------------------------------+ | server_correlation_id | Server-assigned intent identifier. | +-----------------------+------------------------------------------+ | service_ledger_id | GUID issued to the service at ledger | | | registration. | +-----------------------+------------------------------------------+ | service_endpoint | Target service and resource path. | +-----------------------+------------------------------------------+ | actor | Role of the entry writer: client or | | | server. | +-----------------------+------------------------------------------+ | source | Identity of the participant writing this | | | entry (e.g., client, serviceA, | | | serviceB1). | +-----------------------+------------------------------------------+ | target | The downstream service being called. | | | Populated only when actor = client. | | | MUST be null for actor = server entries. | +-----------------------+------------------------------------------+ | parent_reference_id | The correlation ID that the immediate | | | upstream caller provided when calling | | | this service. Used to reconstruct the | | | full distributed call tree. | +-----------------------+------------------------------------------+ Venkateswaran & Jamwal Expires 22 January 2027 [Page 18] Internet-Draft 2PHP-DTT July 2026 | phase | Current or terminal phase state. | +-----------------------+------------------------------------------+ | phase_1_timestamp | When Phase1 was received (ISO8601). | +-----------------------+------------------------------------------+ | phase_2_timestamp | When Phase2 confirmation was received, | | | if applicable (ISO8601). | +-----------------------+------------------------------------------+ | ttl_ms | Configured TTL for this request, in | | | milliseconds. | +-----------------------+------------------------------------------+ | outcome | Terminal outcome: COMMITTED, ABANDONED, | | | or TTL_EXPIRED. | +-----------------------+------------------------------------------+ | payload_ref | Reference to the persisted payload. Not | | | the payload itself. | +-----------------------+------------------------------------------+ | sync_timestamp | When this entry was synced to the | | | Central Ledger (ISO8601). | +-----------------------+------------------------------------------+ | transaction_reference | Reference to transaction ID (optional). | +-----------------------+------------------------------------------+ Table 4 10. Cross-Service Correlation 10.1. Overview When a service fans out to multiple downstream services, the Intent Ledger captures every participant's view of every call--both the caller (actor = client) and the callee (actor = server). This produces a unified, traversable ledger that can reconstruct the full distributed call tree without any distributed coordination at the protocol level. 10.2. Propagation Rules * Every service MUST write its own ledger entry after each phase transition. * The client MUST write its ledger entry after receiving the Phase1 response, so that both client_correlation_id and server_correlation_id are available at write time. * parent_reference_id MUST always record what the immediate upstream caller provided as its correlation ID when calling this service-- enabling upward tree traversal. Venkateswaran & Jamwal Expires 22 January 2027 [Page 19] Internet-Draft 2PHP-DTT July 2026 * Each call MUST produce exactly two matching ledger rows: one actor = client and one actor = server, linked by the same client_correlation_id + server_correlation_id pair. This confirms dual-side registration--the core guarantee of 2PHP. * target MUST be populated only on actor = client rows. It MUST be null on actor = server rows. 10.3. Example Call Chain Client --> Service A --> Service B1 --> Service C1 --> Service B2 --> Service D1 --> Service B3 --> Service E1 Figure 5: Fan-Out Call Chain The complete ledger for this call chain contains 14 entries--two rows (one actor = client, one actor = server) for each of the seven service-boundary interactions. The root client entry uses client- corr-id1 as both its client_correlation_id and its parent_reference_id, establishing the tree anchor. Each subsequent tier sets parent_reference_id to the correlation ID received from its immediate upstream caller. 10.4. Tree Reconstruction Query Patterns * *Full tree from root:* Query parent_reference_id = client-corr-id1 recursively--walks the entire fan-out tree. * *Everything a service initiated:* Query source = serviceA AND actor = client. * *Confirm dual registration:* Match rows by client_correlation_id + server_correlation_id--one actor = client, one actor = server. * *Find stalled transactions:* Query phase = WAITING_CONFIRM or phase = TTL_EXPIRED across any source. 11. Backward Compatibility 2PHP is designed to be fully backward compatible: * Clients that do not include DTT-2PHP-Enabled: true MUST experience no change in behavior. * Servers that do not implement 2PHP MUST ignore the header and process normally. Venkateswaran & Jamwal Expires 22 January 2027 [Page 20] Internet-Draft 2PHP-DTT July 2026 * A 2PHP-capable client MUST NOT send a Phase2 confirmation against a server that did not return DTT-2PHP-Server-Correlation-ID in the response to the initial mutation request (see Section 5.3.1). The absence of that header identifies the response as originating from a non-2PHP server; the response MUST be treated as a conventional terminal HTTP response. This prevents a 2PHP client from issuing a spurious Phase2 request to a legacy server that has already committed the mutation. * 2PHP MAY be adopted incrementally--per endpoint, per service, or organization-wide. * 2PHP makes no changes to existing HTTP methods (POST, PUT, PATCH, DELETE). It is purely additive. * No new transport layer or connection upgrade is required. 12. Implementation Considerations 12.1. Reference Implementation Targets * *Spring Boot*-- OncePerRequestFilter interceptor * *Express.js*--middleware * *Azure API Management*--inbound policy * *MuleSoft*--HTTP request/response interceptor policy 12.2. Durable Storage for Phase 1 Persistence Implementations SHOULD use one of the following for durable storage of intent payload and ledger records: * Relational database with TTL-aware cleanup job. * Redis with TTL-based key expiry (plus delta buffer). * Distributed queue (e.g., Azure Service Bus, AWS SQS) with visibility timeout. 12.3. TTL Defaults The following are recommended starting values. Implementations MAY adjust these per endpoint. Venkateswaran & Jamwal Expires 22 January 2027 [Page 21] Internet-Draft 2PHP-DTT July 2026 +=========================+============+=========================+ | Scenario | TTL | delta (server-internal) | +=========================+============+=========================+ | Low-latency APIs | 5,000 ms | 1,000 ms | +-------------------------+------------+-------------------------+ | Standard APIs | 30,000 ms | 5,000 ms | +-------------------------+------------+-------------------------+ | Long-running operations | 120,000 ms | 10,000 ms | +-------------------------+------------+-------------------------+ Table 5 delta values are server implementation defaults and MUST NOT be exposed in protocol headers. 12.4. Service Ledger Registration Each service SHOULD register with the Intent Ledger at onboarding and be issued a GUID (service_ledger_id) that is included in all ledger entries for that service. This enables cross-service querying while maintaining service-level isolation. 12.5. Recommended Ledger Architecture The normative requirement (Section 9.3) is that each service maintains a durable, locally queryable Intent Ledger. This section describes a recommended local-first, batch-sync architecture that satisfies that requirement without placing the ledger on the critical path of request processing. Implementations MAY choose a different architecture provided the normative requirements are met. Tier1 -- Local Ledger: Per-service, in-process write. Synchronous but local--no network hop. Authoritative source of truth for that service's phase states. Tier2 -- Batch Sync: Scheduled background job syncing local ledger entries to the Central Ledger. Frequency configurable per service. Not on the critical path. Tier3 -- Central Ledger: Read-optimized aggregate view across all services. Used for audit, incident investigation, and SLA reporting. Does not require the same availability or latency guarantees as the Local Ledger. Venkateswaran & Jamwal Expires 22 January 2027 [Page 22] Internet-Draft 2PHP-DTT July 2026 For highly critical services, the intent payload and the ledger entry SHOULD be co-located in the same durable store so the atomic write required by Section 9.3 can be satisfied without a distributed transaction. For less critical services, a temporary co-located copy is sufficient for Phase1 and Phase2 lifecycle management, with the ledger entry propagated to the Central Ledger via event publish. Phase 1 received | v Persist as single unit of work: - Intent payload (durable store) - Ledger record (Local Ledger, phase: WAITING_CONFIRM) | v 200 OK returned to client | v (async background batch job) Local Ledger --> Central Ledger (eventually consistent) Figure 6: Recommended Ledger Write Flow 12.6. On-Demand Pull from Central Ledger Where a Central Ledger is deployed, its management application MAY trigger an on-demand pull from any service's Local Ledger. This is intended for incident investigation, where the latest data is required immediately without waiting for the next scheduled batch sync. Access controls for on-demand pull are discussed in Section 13.5. 12.7. Operational Modes The following table summarizes typical operational modes for the recommended architecture: Venkateswaran & Jamwal Expires 22 January 2027 [Page 23] Internet-Draft 2PHP-DTT July 2026 +========================+===================+======================+ | Scenario | Ledger Used | Trigger | +========================+===================+======================+ | Normal operation | Local Ledger only | Per phase transition | +------------------------+-------------------+----------------------+ | Retry-inspection | Local Ledger | Client query before | | query | | retry | +------------------------+-------------------+----------------------+ | Routine audit | Central Ledger | Batch sync | | | | (scheduled) | +------------------------+-------------------+----------------------+ | Incident | Central Ledger | On-demand pull from | | investigation | | management app | +------------------------+-------------------+----------------------+ | Compliance | Central Ledger | Batch sync | | reporting | | (scheduled) | +------------------------+-------------------+----------------------+ Table 6 13. Security Considerations 13.1. Correlation ID Confidentiality DTT-2PHP-Client-Correlation-ID and DTT-2PHP-Server-Correlation-ID values MUST be treated as opaque identifiers. Implementations SHOULD use UUIDv4 or equivalent cryptographically random values to prevent enumeration or prediction of correlation IDs by unauthorized parties. 13.2. Phase 2 Spoofing A malicious actor in possession of both DTT-2PHP-Client-Correlation- ID and DTT-2PHP-Server-Correlation-ID could attempt to submit a spoofed Phase2 confirmation. Implementations MUST authenticate Phase2 confirmation requests using the same authentication mechanism applied to Phase1 requests. The server MUST verify that the authenticated identity of the Phase2 requester matches that of the Phase1 requester. 13.3. Replay Semantics Replay of a Phase2 confirmation is a normal, expected behavior in 2PHP-DTT and is not by itself an attack. Phase2 confirmations are idempotent within the TTL window (Section 8.1) and are rejected after TTL expiry (Section 8.2). This design allows legitimate clients to safely re-send Phase2 in the face of transient network loss without duplicating server-side effects, and bounds the window in which any captured Phase2 request remains useful to a party that possesses both Venkateswaran & Jamwal Expires 22 January 2027 [Page 24] Internet-Draft 2PHP-DTT July 2026 correlation identifiers. Because a re-sent Phase2 within TTL is honored, an unauthenticated party in possession of both correlation identifiers could re-drive the server's idempotent response. This is a confidentiality-of- identifiers concern rather than a duplication concern. Implementations MUST authenticate Phase2 requests under the same authentication mechanism used for Phase1 (see Section 13.2) and SHOULD pair Phase2 requests with short-lived credentials or request signing where the deployment threat model warrants it. 13.4. Intent Payload Confidentiality The intent payload persisted during Phase1 may contain sensitive data. Implementations MUST ensure that persisted payloads are protected at rest using appropriate encryption mechanisms consistent with the sensitivity of the data. 13.5. Ledger Access Control The Central Ledger aggregates intent records across all services. Access to the Central Ledger MUST be restricted to authorized audit, operations, and compliance consumers. The on-demand pull mechanism (Section 12.6) MUST be protected by appropriate authentication and authorization controls. 13.6. Transport Security All 2PHP exchanges MUST be conducted over TLS (HTTPS). Use of 2PHP over unencrypted HTTP is NOT RECOMMENDED. 14. IANA Considerations 14.1. HTTP Field Name Registrations This document requests registration of the following HTTP field names in the "Hypertext Transfer Protocol (HTTP) Field Name Registry" defined in [RFC9110], Section16.3.1: Venkateswaran & Jamwal Expires 22 January 2027 [Page 25] Internet-Draft 2PHP-DTT July 2026 +================================+==============+===============+ | Field Name | Status | Reference | +================================+==============+===============+ | DTT-2PHP-Enabled | Experimental | This document | +--------------------------------+--------------+---------------+ | DTT-2PHP-Client-Correlation-ID | Experimental | This document | +--------------------------------+--------------+---------------+ | DTT-2PHP-Auto-Confirm | Experimental | This document | +--------------------------------+--------------+---------------+ | DTT-2PHP-Requested-TTL | Experimental | This document | +--------------------------------+--------------+---------------+ | DTT-2PHP-Server-Correlation-ID | Experimental | This document | +--------------------------------+--------------+---------------+ | DTT-2PHP-Phase-State | Experimental | This document | +--------------------------------+--------------+---------------+ | DTT-2PHP-TTL | Experimental | This document | +--------------------------------+--------------+---------------+ | DTT-2PHP-PONR-Deadline | Experimental | This document | +--------------------------------+--------------+---------------+ | DTT-2PHP-Resource-ID | Experimental | This document | +--------------------------------+--------------+---------------+ | DTT-2PHP-Message | Experimental | This document | +--------------------------------+--------------+---------------+ Table 7 15. Normative References [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997, . [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, May 2017, . [RFC9110] Fielding, R., Nottingham, M., and J. Reschke, "HTTP Semantics", RFC 9110, June 2022, . [RFC7240] Snell, J., "Prefer Header for HTTP", RFC 7240, June 2014, . 16. Informative References [OTEL] OpenTelemetry Authors, "OpenTelemetry Specification", https://opentelemetry.io/docs/specs/otel/, 2024. Venkateswaran & Jamwal Expires 22 January 2027 [Page 26] Internet-Draft 2PHP-DTT July 2026 [SAGA] Garcia-Molina, H. and K. Salem, "Sagas", ACM SIGMOD Record, Vol. 16, Issue 3, 1987. [OUTBOX] Richardson, C., "Pattern: Transactional outbox", 2018. Authors' Addresses Barathan Venkateswaran Salesforce Email: bvenkateswaran@salesforce.com Aditya Jamwal Salesforce Email: ajamwal@salesforce.com Venkateswaran & Jamwal Expires 22 January 2027 [Page 27]