Internet-Draft 2PHP June 2026
Venkateswaran & Jamwal Expires 20 December 2026 [Page]
Workgroup:
HTTP
Internet-Draft:
draft-venkateswaran-jamwal-twophp-00
Published:
Intended Status:
Experimental
Expires:
Authors:
B. Venkateswaran
Salesforce
A. Jamwal
Salesforce

2-Phase HTTP Protocol (2PHP)

Abstract

This document specifies the 2-Phase HTTP Protocol (2PHP), 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.

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 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.

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 20 December 2026.

Table of Contents

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 (2PHP), 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.

2PHP is designed to be:

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 Phase 1 acknowledgement, triggering server-side business logic execution.
PONR (Point of No Return):
The moment at which the server begins executing business logic after receiving Phase 2 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 Phase 2 confirmation.
Delta (δ):
A server-internal grace window applied after TTL 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 Phase 1 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:

  • 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

Table 1
Pattern Scope Client Involved? Protocol Level? Intent Ledger?
Two-Phase Commit (2PC) Database No No No
Saga Pattern Application No No No
Transactional Outbox Server-side No No No
Idempotency Keys Application Partial No No
HTTP 100 Continue Protocol Yes Yes No
2PHP (this document) Protocol Yes Yes Yes

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.

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 Phase 1 response. The resource is created only after Phase 2 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: <client-requested-ttl-ms>
DTT-2PHP-Client-Correlation-ID: <client-assigned-uuid>
Content-Type: application/json

{ ...payload... }

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 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: <server-assigned-uuid>
DTT-2PHP-Phase-State: WAITING_CONFIRM
DTT-2PHP-TTL: <milliseconds>
DTT-2PHP-PONR-Deadline: <ISO-8601-absolute-timestamp>

Response header semantics:

DTT-2PHP-Server-Correlation-ID:
Server-assigned identifier for this intent registration. The client MUST echo this value in the Phase 2 confirmation.
DTT-2PHP-TTL:
Milliseconds the server will wait for Phase 2 confirmation. Server-defined. The client MUST send Phase 2 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 ISO 8601 format. The client MUST send Phase 2 before this timestamp.
DTT-2PHP-Phase-State:
Current phase state. Value is WAITING_CONFIRM on Phase 1 response.

No DTT-2PHP-Resource-ID is returned in Phase 1. The resource does not yet exist; it is created only after Phase 2 confirmation is received and business logic has successfully executed.

5.2.3. Client Ledger Write

After receiving the Phase 1 response, the client MUST write a ledger entry to its local ledger. The client writes after the Phase 1 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 Phase 1 acknowledgement:

POST /orders/confirm HTTP/1.1
DTT-2PHP-Enabled: true
DTT-2PHP-Client-Correlation-ID: <same-value-as-Phase-1>
DTT-2PHP-Server-Correlation-ID: <value-from-Phase-1-response>

The client MUST send Phase 2 before the DTT-2PHP-PONR-Deadline timestamp received in the Phase 1 response.

5.3.2. Server Response — Synchronous Mode

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: <resource-identifier>

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 Phase 2 response—no polling is required.

5.3.3. Server Response — Asynchronous Mode

In asynchronous mode, the server crosses the PONR and returns 202 Accepted immediately upon receiving Phase 2 confirmation. Business logic executes out-of-band on the original request channel.

HTTP/1.1 202 Accepted
DTT-2PHP-Phase-State: PROCESSING
DTT-2PHP-Resource-ID: <provisional-resource-identifier>

The DTT-2PHP-Resource-ID returned in a 202 Accepted response is provisional—the resource is not yet fully created at the point this response is returned. The client MUST poll the resource endpoint until DTT-2PHP-Phase-State transitions to COMMITTED or FAILED.

The phase state machine is identical to synchronous mode. Only the timing of the COMMITTED transition differs—in asynchronous mode it occurs out-of-band rather than inline on the Phase 2 response channel. 202 Accepted semantics are as defined in [RFC9110].

5.4. TTL Expiry

Any Phase 2 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 (δ) 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 extension to 2PHP that eliminates the explicit Phase 2 client confirmation round trip. When Auto-Confirm is enabled, the server writes the ledger record and crosses the PONR immediately after Phase 1, then executes business logic inline on the original request channel. The final result (200 OK + Resource-ID) is returned synchronously on that same channel—behaviorally identical to a standard HTTP request from the client’s perspective.

Concurrently, immediately after the ledger write and before processing begins, the server dispatches an asynchronous callback to a client-provided endpoint carrying the server_correlation_id and ledger state. This out-of-band delivery gives the client a durable record of the registered intent independent of the original response channel.

Auto-Confirm mode is valuable for:

  • Brownfield adoption—clients with no 2PHP implementation receive full ledger observability with zero behavior change.
  • Low-latency critical paths—the Phase 2 round trip cost is eliminated.
  • Server-side opt-in—platform teams can enable ledger tracking without requiring client participation.

5.5.2. Activation Headers

DTT-2PHP-Auto-Confirm: true
DTT-2PHP-Callback: <client-callback-endpoint-url>
DTT-2PHP-Auto-Confirm:
When true, the server does not wait for a Phase 2 confirmation before crossing the PONR and executing business logic.
DTT-2PHP-Callback:
A client-provided HTTPS endpoint to receive the asynchronous intent acknowledgment payload. This header is OPTIONAL when DTT-2PHP-Auto-Confirm: true is set. If omitted, the server proceeds in Transparent Mode with no client-side ledger participation.

5.5.3. Protocol Flow

Client                            Server            Client Callback
  |                                 |                     |
  |-- POST /orders ------------->   |                     |
  |   DTT-2PHP-Enabled: true        |                     |
  |   DTT-2PHP-Auto-Confirm: true   |                     |
  |   DTT-2PHP-Callback: <url>      |                     |
  |   DTT-2PHP-Client-Corr-ID: C1  |                     |
  |                                 |                     |
  |             Ledger write (WAITING_CONFIRM             |
  |             -> PROCESSING, atomic)                    |
  |                                 |                     |
  |                                 |-- POST callback --> |
  |                                 |   (immediately,     |
  |                                 |   off-thread,       |
  |                                 |   BEFORE processing)|
  |                                 |                     |
  |             Server processes inline...                |
  |                                 |                     |
  | <-- 200 OK + Resource-ID ----   |                     |
  |     DTT-2PHP-Phase-State:       |                     |
  |       COMMITTED                 |                     |
  |     DTT-2PHP-Server-Corr-ID: S1 |                     |
  |                                 |                     |
Figure 2: Auto-Confirm Mode with Callback

The key invariant: the callback MUST be dispatched immediately after the ledger write and MUST fire before processing begins. This maximizes the client detection window. If the original response is never received but the callback was, the client knows the PONR was crossed and MAY query the ledger by server_correlation_id for final state.

5.5.4. Callback Payload

Table 2
Field Description
server_correlation_id Server-assigned intent identifier.
client_correlation_id Echo of the client-provided identifier.
phase_state PROCESSING at time of callback dispatch.
ponr_crossed Always true in Auto-Confirm mode.
callback_timestamp ISO 8601 timestamp of callback dispatch. Fired before processing begins.

5.5.5. Failure Detection via Callback Gap

The callback creates a first-class detectable failure taxonomy:

Table 3
Callback Received Original Response Received Interpretation
Yes Yes Normal success. Reconcile by correlation IDs.
Yes No PONR crossed; response lost in transit. Query ledger by server_correlation_id for final state.
No Yes Callback delivery failed. Ledger entry exists server-side; client has no local record.
No No Network failure before PONR. Safe to retry as a new Phase 1 request.

5.5.6. Transparent Mode (Auto-Confirm without Callback)

When DTT-2PHP-Auto-Confirm: true is set without DTT-2PHP-Callback, the server operates in Transparent Mode. The server records a ledger entry using a server-generated UUID as the client_correlation_id proxy. The client receives a standard synchronous response with no 2PHP headers required. The server MAY return DTT-2PHP-Server-Correlation-ID in the response for optional client-side ledger lookup.

Transparent Mode provides full server-side ledger observability with zero client behavior change. It is the recommended adoption path for brownfield services.

5.5.7. 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] --> (off-thread) Callback dispatched to client
        |         BEFORE processing begins
        |
        +-- 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.

5.5.8. Mode Comparison

Table 4
Mode Phase 2 Required Callback Latency Client 2PHP Support Ledger Participation
Standard 2PHP Yes No 2 round trips Yes Both sides
Auto-Confirm (with callback) No Yes (async) 1 round trip Callback endpoint only Both sides
Transparent Mode (no callback) No No 1 round trip None Server-side only

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] -- [ PONR, PONR+delta-x ) --> [ABANDONED]
Figure 4: 2PHP Phase State Machine

7. Phase States

Table 5
State Description
WAITING_CONFIRM Phase 1 received and persisted. Awaiting client Phase 2 confirmation.
PROCESSING Phase 2 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 + δ grace window. Terminal state.

8. Idempotency and Replay Behavior

8.1. Replay Before TTL

If a client replays Phase 2 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

Two configurable server behaviors are defined, applicable per endpoint or globally:

REJECT (default):
Return 408 TTL_EXPIRED. The client MUST re-submit Phase 1 as a new request with a new DTT-2PHP-Client-Correlation-ID.
REUSE:
The server accepts the late Phase 2 confirmation and uses the persisted intent, provided cleanup has not yet occurred within the δ grace window.

Servers MAY expose the replay policy via the following header:

DTT-2PHP-Replay-Policy: REJECT | REUSE

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. Architectural Contrast: Inline DTT vs. Passive Telemetry

Existing distributed tracing frameworks, such as OpenTelemetry [OTEL], pass trace contexts out-of-band to log execution data after it happens. This post-mortem model suffers from ingestion lag and cannot stop data mismatches when a network drops right at a service boundary.

In contrast, the 2PHP Distributed Transaction Tracker (DTT) Ledger operates inline as an active safety gate. It forces both the client and server to write an atomic record of intent BEFORE data processing starts. This turns passive logging into real-time failure prevention.

9.3. Microservice Autonomy and Compensation Hooks

2PHP is NOT a Distributed Transaction Coordinator (DTC). It requires zero cross-service thread blocking or lock coordination. Each service boundary handles its handshake independently. The 3-Tier Ledger architecture uses a local-first design where writes are synchronous but local, completely removing network hops from the runtime path.

By standardizing states like WAITING_CONFIRM and TTL_EXPIRED across all systems, the platform provides a uniform data layer. Infrastructure tools can read these state transitions to automatically trigger custom application-layer compensation scripts or data-cleanup workflows without human intervention.

9.4. Architecture: 3-Tier Ledger Model

The Intent Ledger uses a local-first, batch-sync architecture to ensure it is never on the critical path of service processing.

Tier 1 — Local Ledger:
Per-service, in-process write. Synchronous but local—no network hop. Authoritative source of truth for that service’s phase states.
Tier 2 — Batch Sync:
Scheduled background job syncing local ledger entries to the Central Ledger. Frequency configurable per service. Not on the critical path.
Tier 3 — Central Ledger:
Read-optimized aggregate view across all services. Used for audit, incident investigation, and SLA reporting. Does not require high availability or low latency guarantees.

9.5. Write Flow

The intent payload and ledger record MUST both be persisted as a single unit of work before 200 OK is returned.

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 5: Ledger Write Flow

For highly critical services, the payload and ledger SHOULD be co-located in the same store to eliminate the need for distributed transaction coordination. For less critical services, a temporary copy of the payload and ledger entry is sufficient for Phase 1 and Phase 2 lifecycle management, with the ledger entry synced to the Central Ledger via event publish, not on the critical path.

9.6. On-Demand Pull

The Central Ledger Management Application MAY trigger an on-demand pull from any service’s local ledger. This mechanism is used during incident investigation when the latest data is needed immediately, without waiting for the next scheduled batch sync.

9.7. Operational Modes

Table 6
Scenario Ledger Used Trigger
Normal operation Local Ledger only Per phase transition
Routine audit Central Ledger Batch sync (scheduled)
Incident investigation Central Ledger On-demand pull from Management App
Compliance reporting Central Ledger Batch sync (scheduled)

9.8. Ledger Schema

Each ledger entry MUST include the following fields:

Table 7
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.
phase Current or terminal phase state.
phase_1_timestamp When Phase 1 was received (ISO 8601).
phase_2_timestamp When Phase 2 confirmation was received, if applicable (ISO 8601).
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 (ISO 8601).
transaction_reference Reference to transaction ID (optional).

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 Phase 1 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.
  • 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 6: 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:

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 δ 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.

Table 8
Scenario TTL δ (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

δ 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.

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 UUID v4 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 Phase 2 confirmation. Implementations MUST authenticate Phase 2 confirmation requests using the same authentication mechanism applied to Phase 1 requests. The server MUST verify that the authenticated identity of the Phase 2 requester matches that of the Phase 1 requester.

13.3. Replay Attacks

The REUSE replay policy (Section 8.2) introduces a window during which a replayed Phase 2 confirmation may be accepted. Implementations using REUSE SHOULD apply additional controls, such as request signing or short-lived tokens, to mitigate replay risk within the δ grace window.

13.4. Intent Payload Confidentiality

The intent payload persisted during Phase 1 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 9.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 Header Field Registrations

This document requests registration of the following HTTP header fields in the "Permanent Message Header Field Names" registry defined in [RFC3864] and updated by [RFC9110]:

Table 9
Header Field Name Applicable Protocol Status Reference
DTT-2PHP-Enabled HTTP Experimental This document
DTT-2PHP-Client-Correlation-ID HTTP Experimental This document
DTT-2PHP-Auto-Confirm HTTP Experimental This document
DTT-2PHP-Callback HTTP Experimental This document
DTT-2PHP-Requested-TTL HTTP Experimental This document
DTT-2PHP-Server-Correlation-ID HTTP Experimental This document
DTT-2PHP-Phase-State HTTP Experimental This document
DTT-2PHP-TTL HTTP Experimental This document
DTT-2PHP-PONR-Deadline HTTP Experimental This document
DTT-2PHP-Resource-ID HTTP Experimental This document
DTT-2PHP-Replay-Policy HTTP Experimental This document
DTT-2PHP-Message HTTP Experimental This document

15. Requirements Language

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.

16. Normative References

[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[RFC9110]
Fielding, R., Nottingham, M., and J. Reschke, "HTTP Semantics", RFC 9110, , <https://www.rfc-editor.org/rfc/rfc9110>.
[RFC9112]
Fielding, R. and J. Reschke, "HTTP/1.1", RFC 9112, , <https://www.rfc-editor.org/rfc/rfc9112>.
[RFC3864]
Klyne, G., Nottingham, M., and J. Mogul, "Registration Procedures for Message Header Fields", BCP 90, RFC 3864, , <https://www.rfc-editor.org/rfc/rfc3864>.

17. Informative References

[OTEL]
OpenTelemetry Authors, "OpenTelemetry Specification", https://opentelemetry.io/docs/specs/otel/ , .
[SAGA]
Garcia-Molina, H. and K. Salem, "Sagas", ACM SIGMOD Record, Vol. 16, Issue 3 , .
[OUTBOX]
Richardson, C., "Pattern: Transactional outbox", .

Authors' Addresses

Barathan Venkateswaran
Salesforce
Aditya Jamwal
Salesforce