Internet-Draft Event Delivery Semantics June 2026
Panke Expires 30 December 2026 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-mayankpanke-event-delivery-semantics-01
Published:
Intended Status:
Informational
Expires:
Author:
M. Panke
Independent

Event and Webhook Delivery Semantics

Abstract

Event- and webhook-based integrations are a common application-layer mechanism for interoperability across Internet services, yet they lack a shared delivery semantics contract. Existing implementations vary widely in retry behavior, acknowledgment signaling, failure classification, idempotency identifiers, and replay handling, resulting in fragile integrations and ambiguous operational expectations.

This document defines a minimal, application-layer delivery semantics profile for event and webhook delivery over existing transports, and specifies a concrete binding for the Hypertext Transfer Protocol (HTTP). The profile constrains only sender-observable behavior and signaling; it does not impose receiver-side storage or processing requirements and does not redefine existing transport protocols.

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

Table of Contents

1. Introduction

Event- and webhook-based delivery is widely used to notify external systems of state changes or occurrences across administrative boundaries. These integrations are typically implemented over HTTP and are expected to operate in the presence of partial failure, independent failure domains, and variable network conditions.

Despite their ubiquity, there is no common, interoperable delivery semantics model that defines how delivery attempts, retries, acknowledgments, or failures are signaled and interpreted between independently operated producers and consumers. In practice, every producer publishes its own retry policy, its own acknowledgment convention, its own idempotency header, and its own classification of failure; every consumer must adapt to those conventions per producer. The result is fragile integrations, repeated rediscovery of the same edge cases, and operational practices that do not transfer between vendors.

This document addresses that gap by defining a minimal, application-layer semantics profile focused on sender-observable behavior, and by specifying a concrete binding of that profile to HTTP (see Section 9). The profile is intentionally narrow: it does not attempt to define new transport primitives, new cryptographic mechanisms, or new payload formats. Its goal is to give independently developed producers and consumers a shared, interoperable vocabulary for the few signals that determine whether a delivery succeeded, may be retried, or must be abandoned.

2. Conventions and Terminology

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.

The following terms are used throughout this document.

Event:
A self-contained, application-level record of an occurrence or state change generated by an Event Producer and intended for delivery to one or more Event Consumers. This document places no requirement on the payload format of an Event.
Event Producer:
An entity that generates Events and is responsible for initiating Delivery Attempts toward one or more Event Consumers, directly or via an Intermediary.
Event Consumer:
An entity that exposes an endpoint to receive Delivery Attempts for Events and that returns Sender-Observed Outcomes in response to those attempts.
Intermediary:
An entity positioned between an Event Producer and an Event Consumer that relays, transforms, fans out, or buffers Events. An Intermediary takes the Producer role with respect to its downstream Consumer and the Consumer role with respect to its upstream Producer.
Delivery Attempt:
A single, discrete effort by an Event Producer or Intermediary to deliver an Event to a Consumer endpoint. Each Delivery Attempt is independent of all others.
Acknowledgment:
A signal returned by an Event Consumer indicating receipt of a Delivery Attempt. An Acknowledgment does not imply processing success, persistence, or durability beyond the scope of receipt.
Sender-Observed Outcome:
The result of a Delivery Attempt as observable by the sender. Sender-Observed Outcomes are defined in Section 6.2 and form the sole basis for retry decisions.
Accepted:
A Sender-Observed Outcome indicating that the Consumer acknowledged receipt of the Delivery Attempt.
Transient Failure:
A Sender-Observed Outcome indicating a condition that the sender may reasonably expect to resolve such that a future Delivery Attempt could be Accepted.
Terminal Failure:
A Sender-Observed Outcome indicating a condition that the sender cannot reasonably expect to resolve through further Delivery Attempts of the same Event to the same Consumer endpoint.
Idempotency Identifier:
A producer-supplied identifier that correlates multiple Delivery Attempts representing the same logical Event, enabling optional consumer-side deduplication.
Retry:
A subsequent Delivery Attempt for the same logical Event following a non-Accepted Sender-Observed Outcome.

3. Problem Statement

Event- and webhook-based delivery is a widely deployed application-layer integration pattern used to notify external systems of state changes or occurrences. Such delivery is commonly implemented over existing transports, most frequently HTTP, and is typically expected to operate in the presence of partial failure, network interruption, and independent administrative control of endpoints.

Despite widespread deployment, there is no common, interoperable delivery semantics contract governing how Event Producers, Consumers, and Intermediaries signal Delivery Attempts, retries, acknowledgment, or failure. As a result, independently developed implementations rely on implicit assumptions, vendor-specific conventions, or informal documentation, leading to fragile integrations and inconsistent operational behavior.

3.1. Interoperability Failures Observed in Practice

The absence of a shared delivery semantics model results in recurring issues, including:

  • ambiguous retry behavior and unclear signaling of retry exhaustion;
  • inconsistent acknowledgment semantics, with some producers treating any 2xx HTTP response as success and others requiring specific response codes or body content;
  • non-standard idempotency and deduplication signaling, with header field names and value formats varying per producer;
  • unclear classification of delivery failures, in particular conflation of transport-level and application-level failures; and
  • increased exposure to replay and abuse, owing to ad hoc authentication and replay-mitigation conventions.

These issues arise from missing application-layer semantics rather than deficiencies in underlying transport protocols.

3.2. Limitations of Existing Transport Semantics

Transport protocols such as HTTP [RFC9110] provide generic delivery and error signaling mechanisms but intentionally do not define application-specific semantics such as retry interpretation, acknowledgment meaning, or deduplication scope. Correct use of transport semantics alone is therefore insufficient to ensure interoperable event delivery behavior.

3.3. Non-Goals

This document does not attempt to:

  • define or guarantee end-to-end delivery or processing correctness;
  • provide exactly-once, at-most-once, or effectively-once guarantees;
  • impose receiver-side storage or execution requirements;
  • redefine or replace existing transport protocols; or
  • standardize event payload formats or business semantics.

All requirements defined in this document apply to sender-observable behavior and signaling.

4. Goals

The goals of this specification are to:

5. Architecture Overview

This specification considers three primary roles: Event Producer, Event Consumer, and an optional Intermediary. The delivery semantics defined in this document apply to interactions between these roles at the application layer.

+----------------+    Delivery Attempt    +----------------+
|                | ---------------------> |                |
| Event Producer |                        | Event Consumer |
|                | <--------------------- |                |
+----------------+ Sender-Observed Outcome+----------------+

                          (or)

+----------+  Delivery  +--------------+  Delivery  +----------+
| Producer | ---------> | Intermediary | ---------> | Consumer |
+----------+  Outcome   +--------------+  Outcome   +----------+
             <---------                 <---------
Figure 1: Roles and Delivery Direction

An Intermediary takes the Producer role with respect to its downstream Consumer, and the Consumer role with respect to its upstream Producer. The semantics defined in this document therefore apply recursively at each hop.

6. Delivery Semantics Model

This specification defines a sender-observable delivery semantics model for event and webhook delivery. The model applies to each Delivery Attempt independently and does not infer receiver-side processing behavior beyond what is explicitly signaled.

6.1. Delivery Attempt

A Delivery Attempt represents a single, discrete effort by an Event Producer or Intermediary to deliver an Event to a Consumer endpoint. Each Delivery Attempt MUST be treated as best-effort, MUST NOT imply receipt, durability, or processing, and MAY be retried according to sender policy when Sender-Observed Outcomes indicate a non-terminal condition.

6.2. Sender-Observed Outcomes

This specification defines three Sender-Observed Outcomes for a Delivery Attempt:

Accepted:
The Consumer acknowledged receipt of the Delivery Attempt. The sender MUST NOT retry the same Delivery Attempt solely on the basis of an Accepted outcome.
Transient Failure:
A condition was observed that the sender may reasonably expect to resolve. The sender MAY retry the Delivery Attempt subject to sender policy.
Terminal Failure:
A condition was observed that the sender cannot reasonably expect to resolve through further Delivery Attempts of the same Event to the same Consumer endpoint. The sender MUST NOT retry the same Delivery Attempt solely on the basis of a Terminal Failure outcome.

Senders MUST base retry behavior solely on Sender-Observed Outcomes and MUST NOT infer receiver-side state beyond what is explicitly signaled.

6.3. Retry Signaling

Retry behavior is sender-driven and policy-dependent. This specification standardizes only retry signaling, not retry guarantees. Consumers MAY provide retry guidance (for example, by indicating a minimum delay before the next attempt), and senders MAY honor such guidance. When a Consumer provides explicit retry guidance and the sender intends to retry, the sender SHOULD not retry sooner than indicated.

Senders SHOULD apply backoff between retries to avoid amplifying load on Consumers experiencing Transient Failure conditions. An algorithm for the HTTP binding is specified in Section 9.6; interactions with denial-of-service mitigation are discussed in Section 11.8.

6.4. Applicability to Other Transports

This document defines bindings for HTTP only (Section 9). The model in this section is intentionally transport-independent so that bindings to other transports (for example, AMQP, MQTT, or queue-based protocols) may be specified separately without revisiting the abstract semantics. No such bindings are defined here.

7. Idempotency and Deduplication Signaling

Idempotency and deduplication are addressed through explicit signaling mechanisms only. This specification does not require or assume receiver-side deduplication behavior.

7.1. Idempotency Identifier

An Idempotency Identifier is a producer-supplied identifier intended to correlate multiple Delivery Attempts representing the same logical Event. When present, the identifier MUST remain stable across retries of the same logical Event and MUST be scoped to the producer-consumer context.

Producers SHOULD generate Idempotency Identifiers with sufficient entropy to make collisions across distinct logical Events negligible within the relevant deduplication window.

7.2. Deduplication Expectations

Consumers MAY choose to perform deduplication based on the Idempotency Identifier and local policy. Senders MUST tolerate duplicate delivery in all cases. Deduplication remains an optimization, not a correctness requirement.

A Consumer that performs deduplication SHOULD maintain Idempotency Identifier state for a finite Deduplication Window. When no value is communicated out of band or by prior agreement, a minimum Deduplication Window of 24 hours is RECOMMENDED.

A Producer MUST NOT reuse an Idempotency Identifier for a distinct logical Event within the Consumer's Deduplication Window. When the Window is not known to the Producer, the Producer SHOULD treat it as at least the RECOMMENDED minimum above and SHOULD generate fresh identifiers per distinct logical Event regardless.

8. Failure Classification

Failure classification in this specification is minimal and sender-centric. Two failure classes are defined:

Transport-level failure:
A failure attributable to the transport, such as connection refusal, connection reset, timeout, or name-resolution failure. Transport-level failures SHOULD be treated as Transient Failure unless sender policy specifies otherwise.
Application-level rejection:
A failure signaled by the Consumer at the application layer indicating that the Delivery Attempt was received but not accepted. Application-level rejections MAY be either Transient Failure or Terminal Failure depending on the specific signal (see Section 9.2 for the HTTP mapping).

Failure classifications are used solely to inform sender behavior such as retry decisions, alternate delivery paths, or operator intervention. They carry no semantic guarantees about Consumer-side processing.

9. HTTP Binding

This section defines a binding of the delivery semantics model (Section 6) to HTTP [RFC9110]. Producers and Consumers exchanging Events over HTTP SHOULD implement this binding to enable interoperability. Other transport bindings are out of scope for this document.

9.1. Method and Request Semantics

A Delivery Attempt using the HTTP binding SHOULD use the POST method. PUT MAY be used when Producer and Consumer have prior agreement that the Event payload represents the replacement state of the resource identified by the request URI. Safe methods (GET, HEAD, OPTIONS) are NOT RECOMMENDED for Delivery Attempts because they imply no state change and are subject to intermediary caching behavior that may suppress retries.

The Content-Type of the request MUST accurately identify the Event payload media type. This document does not constrain payload media type; see Section 10 for a discussion of common choices.

9.2. Mapping Sender-Observed Outcomes to HTTP Status Codes

When a Consumer returns an HTTP response to a Delivery Attempt, the sender derives the Sender-Observed Outcome from the response. The mappings in this section represent the default behavior that applies in the absence of out-of-band agreement.

Producers and Consumers MAY agree on alternative interpretations for individual status codes, provided that any such agreement (a) is documented in writing, (b) is discoverable by operators of both parties, and (c) does not weaken the security properties required by Section 11. Absent such an agreement, the defaults below apply.

9.2.1. Accepted

A 2xx (Successful) status code SHOULD be treated as Accepted. The following finer-grained guidance applies:

  • 200 (OK), 201 (Created), 202 (Accepted), and 204 (No Content) MUST be treated as Accepted when received in response to a Delivery Attempt.
  • 207 (Multi-Status) SHOULD NOT be treated as Accepted at the Delivery Attempt level without parsing the body, because per-element status may include failures requiring sender action. Producers and Consumers using 207 MUST have prior agreement on its interpretation.
  • Other 2xx status codes SHOULD be treated as Accepted unless prior agreement specifies otherwise.

The presence or absence of a response body MUST NOT alter the Sender-Observed Outcome derived from a 2xx status code, except as stated above for 207.

9.2.2. Transient Failure

The following status codes SHOULD be treated as Transient Failure:

Table 1: Status Codes Mapped to Transient Failure
Code Name Notes
408 Request Timeout Ambiguous: the request may or may not have been processed. Safe retry depends on the Idempotency-Key field, which is required by Section 9.4.
421 Misdirected Request Indicates routing error at the Consumer; retry MAY succeed against a re-resolved endpoint.
425 Too Early Retry after the early-data condition clears.
429 Too Many Requests Honor Retry-After (Section 9.5) if present.
500 Internal Server Error Generic server error; retry with backoff.
502 Bad Gateway Upstream of Consumer failed; retry.
503 Service Unavailable Honor Retry-After if present.
504 Gateway Timeout Same ambiguity as 408; safe retry depends on the Idempotency-Key field required by Section 9.4.
511 Network Authentication Required Typically injected by an on-path captive portal; resolves out of band.

Other 5xx status codes not listed above SHOULD be treated as Transient Failure unless prior agreement specifies otherwise.

9.2.3. Terminal Failure

The following status codes SHOULD be treated as Terminal Failure:

Table 2: Status Codes Mapped to Terminal Failure
Code Name Notes
400 Bad Request Malformed request; retry will produce the same outcome.
401 Unauthorized Producers operating with rotating credentials MAY attempt one credential refresh and a single subsequent retry before classifying as Terminal.
403 Forbidden Authorization decision; retry not useful absent policy change.
404 Not Found Endpoint missing; reconfiguration required.
405 Method Not Allowed Producer-Consumer agreement mismatch; see Section 9.1.
410 Gone Endpoint permanently removed; Producer SHOULD mark the subscription inactive.
413 Content Too Large Event payload exceeds Consumer limit; retry without payload reduction will fail.
414 URI Too Long Typically a Producer configuration error.
415 Unsupported Media Type Renegotiate media type out of band.
422 Unprocessable Content Schema or semantic validation failure.
451 Unavailable for Legal Reasons Producer SHOULD record and escalate to operator review.

Other 4xx status codes not listed above SHOULD be treated as Terminal Failure unless prior agreement specifies otherwise.

When a Consumer signals deprecation via the Sunset header field [RFC8594], Producers SHOULD treat continued Delivery Attempts past the indicated Sunset time as candidates for Terminal classification on the next non-Accepted outcome.

9.2.4. Other Status Code Classes

1xx (Informational) status codes are handled per [RFC9110] and do not in themselves constitute a Sender-Observed Outcome.

3xx (Redirection) status codes are handled per [RFC9110]. In particular, 308 (Permanent Redirect) SHOULD cause the Producer to update its stored endpoint URI for the subscription before issuing the next Delivery Attempt. 307 (Temporary Redirect) MUST NOT cause the Producer to update stored configuration.

9.2.5. Problem Details in Responses

Consumers MAY return problem details in the response body using the format defined in [RFC9457] to aid operator diagnosis. The Sender-Observed Outcome MUST still be derived from the status code; problem details are advisory.

9.3. Network-Level Failures

A Delivery Attempt that fails before a complete HTTP response status line is received (for example, due to connection refusal, connection reset, TLS handshake failure, request timeout, or name-resolution failure) MUST be treated as a transport-level failure as defined in Section 8 and, by default, as Transient Failure.

A Delivery Attempt for which the request was transmitted but the response was not received in full MUST be treated as Transient Failure with unknown outcome. Safe retry in this case depends on the Idempotency-Key header field, which is required by Section 9.4 for all Delivery Attempts in the HTTP binding.

9.4. Idempotency-Key Header Field

In the HTTP binding defined by this document, every Delivery Attempt MUST include an Idempotency-Key header field carrying the Idempotency Identifier defined in Section 7.1. The header field's syntax and processing rules MUST be those defined by [I-D.ietf-httpapi-idempotency-key].

The value of the Idempotency-Key header field MUST be identical across all Delivery Attempts for the same logical Event from the same Producer-Consumer Context (defined below). The value MUST be a string of sufficient entropy to make collisions negligible across the Deduplication Window (Section 7.2); a UUID [RFC9562] or a base64url-encoded random value of at least 128 bits satisfies this requirement.

For the purposes of this document, a Producer-Consumer Context is the tuple (Producer identity, Consumer endpoint URI), where:

  • Producer identity is the authenticated principal presenting the Delivery Attempt. Authentication is REQUIRED in the HTTP binding; see Section 11.3.
  • Consumer endpoint URI is the effective request URI as defined in Section 7.1 of [RFC9110], after any 308 (Permanent Redirect) updates per Section 9.2.4.

Two Delivery Attempts share an Idempotency-Key scope if and only if they share a Producer-Consumer Context.

9.5. Retry-After Header Field

When a Consumer returns a response classified as Transient Failure, the Consumer MAY include a Retry-After header field as defined in Section 10.2.3 of [RFC9110] to indicate a minimum delay before the next Delivery Attempt.

When a Retry-After header field is present in a response classified as Transient Failure and the sender intends to retry, the sender SHOULD NOT initiate the next Delivery Attempt for the same logical Event sooner than indicated by the Retry-After value. Senders MAY apply additional backoff beyond the Retry-After value at their discretion.

A Retry-After value of 0 indicates that the Consumer has no preferred delay; the Producer's local retry policy applies (see Section 9.6).

Producers retrying after Transient Failure outcomes SHOULD apply an algorithm with the following properties:

  • monotonically non-decreasing expected delay between successive retries (backoff);
  • independent randomization across Producer instances (jitter), to prevent synchronized retry storms; and
  • a finite maximum number of retries, a finite total retry duration, or both.

A widely deployed default that satisfies these requirements is full-jitter exponential backoff. For retry attempt n (with n = 0 denoting the first retry), the sender selects a delay uniformly at random from the interval [0, min(cap, base * 2^n)], where base is a baseline delay (a value of 1 second is commonly used) and cap is an upper bound on a single delay (commonly between 60 and 600 seconds). Producers MAY use other algorithms that satisfy the properties above.

When a Retry-After value is supplied (Section 9.5) and exceeds the delay selected by the algorithm above, the Retry-After value MUST be honored as the lower bound for the next Delivery Attempt.

9.7. Intermediary Behavior

When an Intermediary (Section 5) relays an Event over the HTTP binding:

  • The Idempotency-Key header field value MUST be preserved unchanged on the relayed Delivery Attempt sent to the downstream Consumer. Intermediaries MUST NOT rewrite the value, even when they buffer or fan out Events.
  • The Retry-After header field MUST NOT be propagated upstream. It applies only between the immediate sender and receiver of a given hop.
  • The Sender-Observed Outcome at each hop is independent. An Intermediary MAY return any outcome to its upstream Producer that accurately reflects its own state.
  • Authentication and integrity protection (Section 11.3, Section 11.4) apply per hop unless an end-to-end mechanism such as HTTP Message Signatures [RFC9421] is used to bind origin metadata across hops.

An Intermediary that buffers Events MAY return Accepted upstream prior to successful downstream delivery (store-and-forward operation) only when both of the following conditions hold:

  1. The Intermediary's store-and-forward behavior, including its durability guarantees and its retry policy toward the downstream Consumer, is documented in a service description that is accessible to operators of the upstream Producer; and
  2. The upstream Producer has acknowledged that service description out of band (for example, by accepting terms of service, by configuring the Intermediary as a delivery target, or by equivalent administrative action).

Absent both conditions, an Intermediary MUST NOT return Accepted upstream before the downstream Delivery Attempt has itself yielded an Accepted Sender-Observed Outcome.

9.8. Examples

The examples in this section are illustrative and non-normative. Line breaks within header fields are inserted for readability only. All hostnames use example.com per [RFC2606].

For clarity, the Content-Length header field and other framing headers are omitted from the examples; the message-body length is determined per [RFC9110].

9.8.1. Example: Accepted

A Producer delivers an Event; the Consumer acknowledges with 200 OK.

POST /webhooks/orders HTTP/1.1
Host: consumer.example.com
Content-Type: application/json
Idempotency-Key: 0190a4d5-1c9e-7c5e-9b9a-3f8e3b3f1a2e

{"event_type":"order.created","order_id":"ord_12345"}
HTTP/1.1 200 OK

Sender-Observed Outcome: Accepted. No retry is performed.

9.8.2. Example: Transient Failure with Retry-After

The Consumer is under load and asks the Producer to retry after 30 seconds.

POST /webhooks/orders HTTP/1.1
Host: consumer.example.com
Content-Type: application/json
Idempotency-Key: 0190a4d5-1c9e-7c5e-9b9a-3f8e3b3f1a2e

{"event_type":"order.created","order_id":"ord_12345"}
HTTP/1.1 503 Service Unavailable
Retry-After: 30

Sender-Observed Outcome: Transient Failure. The Producer waits at least 30 seconds, then retries the same Delivery Attempt with the same Idempotency-Key.

POST /webhooks/orders HTTP/1.1
Host: consumer.example.com
Content-Type: application/json
Idempotency-Key: 0190a4d5-1c9e-7c5e-9b9a-3f8e3b3f1a2e

{"event_type":"order.created","order_id":"ord_12345"}
HTTP/1.1 200 OK

The retry is Accepted. Because the Idempotency-Key is preserved, a Consumer that performs deduplication (see Section 7.2) processes the Event exactly once across the two Delivery Attempts.

9.8.3. Example: Terminal Failure with Problem Details

The Consumer rejects the Event as semantically invalid.

POST /webhooks/orders HTTP/1.1
Host: consumer.example.com
Content-Type: application/json
Idempotency-Key: 0190a4d5-1c9e-7c5e-9b9a-3f8e3b3f1a2f

{"event_type":"order.created","order_id":""}
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json

{
  "type": "https://consumer.example.com/probs/invalid-payload",
  "title": "Invalid event payload",
  "status": 422,
  "detail": "Field 'order_id' must be non-empty."
}

Sender-Observed Outcome: Terminal Failure. The Producer MUST NOT retry the Delivery Attempt; the problem details are recorded for operator diagnosis.

9.8.4. Example: Network-Level Failure

The Producer establishes a TCP connection to consumer.example.com on port 443. TLS negotiation completes. The Producer transmits the request in full and waits for a response. After 60 seconds with no response bytes received, the Producer's local timeout fires and the connection is closed.

Sender-Observed Outcome: Transient Failure, with unknown receiver state per Section 9.3. The Producer retries using the same Idempotency-Key to permit Consumer-side deduplication. The next retry delay is governed by Section 9.6.

9.9. HTTP Version Considerations

The Delivery Attempt semantics defined in this section are version-independent at the application layer. The following version-specific behaviors apply:

  • Producers using HTTP/2 [RFC9113] or HTTP/3 [RFC9114] MAY multiplex multiple Delivery Attempts on a single connection. Stream reset (RST_STREAM in HTTP/2; STOP_SENDING or RESET_STREAM in HTTP/3) after the request has been transmitted but before a complete response is received MUST be treated as a network-level failure per Section 9.3.
  • Producers MUST NOT send Delivery Attempts in TLS 1.3 0-RTT (early) data [RFC8446] unless the Producer-Consumer Context explicitly permits it through out-of-band agreement satisfying the conditions in Section 9.2. TLS 1.3 0-RTT data is replay-vulnerable at the transport layer regardless of application-layer signing or Idempotency-Key-based deduplication; see Section 11.5.
  • HTTP/2 server push and HTTP/3 server push MUST NOT be used to deliver Events. The Sender-Observed Outcome model presumes sender-initiated Delivery Attempts.

11. Security Considerations

Event delivery mechanisms are commonly used to convey security-sensitive notifications across administrative boundaries. This section profiles existing security mechanisms and provides guidance on their application to the delivery semantics defined in this document. No new cryptographic mechanisms are defined. The guidance below follows the structure recommended by [RFC3552].

11.1. Threat Model

The principal threats to event and webhook delivery considered by this document are:

  • spoofing of an Event Producer by a third party in order to inject fabricated Events into a Consumer;
  • replay of previously delivered Events by an on-path or off-path attacker;
  • modification of Event payloads or metadata in transit;
  • disclosure of Event contents to unauthorized parties; and
  • abuse of retry behavior to amplify load against either a Consumer or an unrelated third party.

11.2. Transport Security

Producers and Consumers SHOULD use TLS [RFC8446] for all Delivery Attempts. Producers SHOULD validate Consumer endpoint certificates and SHOULD NOT deliver Events to endpoints that fail certificate validation.

11.3. Authentication of Producers

In the HTTP binding (Section 9), Consumers MUST authenticate the Producer of each Delivery Attempt. This requirement supports the Producer-Consumer Context definition in Section 9.4 and is the basis of the replay-mitigation requirement in Section 11.5.

Suitable authentication mechanisms include, but are not limited to, HTTP Message Signatures [RFC9421], mutual TLS, and bearer tokens carried in the Authorization header field as defined in [RFC9110]. Selection of a specific mechanism is a deployment decision and is out of scope for this document.

Whatever mechanism is chosen, Consumers MUST NOT treat a Delivery Attempt as Accepted on the basis of its payload alone when authentication has not been verified.

11.4. Integrity Protection

Producers SHOULD protect the integrity of Event payloads and security-relevant metadata in transit. Use of TLS (Section 11.2) provides integrity for the transport channel. Use of HTTP Message Signatures [RFC9421] additionally provides integrity over selected message components that survives intermediary processing.

11.5. Replay Mitigation

Consumers that act on Events MUST mitigate replay attacks. At least one of the following mechanisms MUST be in effect for any Consumer for which replay would have security consequences:

  1. Deduplication based on the Idempotency Identifier (Section 7.2) within an active Deduplication Window. This mechanism is sufficient against replay only for the duration of the Window and only when the Window is enforced.
  2. Verification of a Producer-supplied freshness indicator (such as a signed timestamp or nonce) carried in authenticated metadata, where Delivery Attempts with timestamps outside an acceptance window or with previously seen nonces are rejected.

The Idempotency Identifier alone is NOT RECOMMENDED as a sole replay countermeasure outside the bounded Deduplication Window, because Producers may legitimately reuse identifiers beyond that window per local policy. Consumers that do not perform deduplication MUST implement mechanism (2) above to satisfy the requirement in this section.

When Delivery Attempts traverse TLS 1.3 [RFC8446], neither mechanism above mitigates replay of TLS 1.3 0-RTT (early) data, which is replayable at the transport layer. Producers MUST NOT transmit Delivery Attempts as 0-RTT data except under the conditions stated in Section 9.9. When Delivery Attempts are transmitted as 0-RTT data under those conditions, Consumers MUST rely on mechanism (2) above for replay protection; the Deduplication Window alone is insufficient because a 0-RTT replay may deliver an Event with an Idempotency Identifier that the Consumer has not yet seen.

11.6. Confidentiality

Event payloads may contain confidential data. Producers and Consumers SHOULD use TLS to provide confidentiality on the transport channel and SHOULD avoid logging full Event payloads at intermediary points where such logs are not subject to equivalent protection.

11.7. Endpoint Authorization

Producers SHOULD deliver Events only to Consumer endpoints that have been explicitly registered or otherwise authorized to receive them. Producers that accept user-supplied delivery URLs (for example, customer-configurable webhook endpoints) SHOULD validate those URLs and SHOULD NOT permit delivery to addresses inside their own trust boundary unless explicitly intended, to mitigate server-side request forgery.

11.8. Retry Amplification and Denial-of-Service Considerations

Retry behavior interacts directly with availability. The bounding and jitter requirements in Section 9.6 are motivated in part by the need to prevent senders from amplifying load against a Consumer recovering from a Transient Failure condition. Senders MUST NOT retry without bound; the finite-retry requirement in Section 9.6 is normative for that reason.

When a Consumer returns a Retry-After value (Section 9.5), honoring that value contributes directly to mitigating retry amplification.

Producers SHOULD additionally treat repeated Terminal Failure outcomes from a single Consumer endpoint as a signal to disable further Delivery Attempts to that endpoint until operator intervention, so as not to amplify load against endpoints that have been removed, misconfigured, or unsubscribed.

12. IANA Considerations

This document makes no request of IANA.

The HTTP header field name "Idempotency-Key" referenced in Section 9.4 is registered by [I-D.ietf-httpapi-idempotency-key]; this document defers to that registration.

13. References

13.1. Normative References

[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC9110]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, , <https://www.rfc-editor.org/info/rfc9110>.

13.2. Informative References

[CLOUDEVENTS]
Cloud Native Computing Foundation, "CloudEvents - A specification for describing event data in a common way", , <https://github.com/cloudevents/spec>.
[I-D.ietf-httpapi-idempotency-key]
Yasskin, J. and S. Dalal, "The Idempotency-Key HTTP Header Field", Work in Progress, Internet-Draft, draft-ietf-httpapi-idempotency-key, , <https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-idempotency-key>.
[RFC2606]
Eastlake 3rd, D. and A. Panitz, "Reserved Top Level DNS Names", BCP 32, RFC 2606, DOI 10.17487/RFC2606, , <https://www.rfc-editor.org/info/rfc2606>.
[RFC3552]
Rescorla, E. and B. Korver, "Guidelines for Writing RFC Text on Security Considerations", BCP 72, RFC 3552, DOI 10.17487/RFC3552, , <https://www.rfc-editor.org/info/rfc3552>.
[RFC7322]
Flanagan, H. and S. Ginoza, "RFC Style Guide", RFC 7322, DOI 10.17487/RFC7322, , <https://www.rfc-editor.org/info/rfc7322>.
[RFC8446]
Rescorla, E., "The Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, , <https://www.rfc-editor.org/info/rfc8446>.
[RFC8594]
Wilde, E., "The Sunset HTTP Header Field", RFC 8594, DOI 10.17487/RFC8594, , <https://www.rfc-editor.org/info/rfc8594>.
[RFC9113]
Thomson, M., Ed. and C. Benfield, Ed., "HTTP/2", RFC 9113, DOI 10.17487/RFC9113, , <https://www.rfc-editor.org/info/rfc9113>.
[RFC9114]
Bishop, M., Ed., "HTTP/3", RFC 9114, DOI 10.17487/RFC9114, , <https://www.rfc-editor.org/info/rfc9114>.
[RFC9421]
Backman, A., Ed., Richer, J., Ed., and M. Sporny, "HTTP Message Signatures", RFC 9421, DOI 10.17487/RFC9421, , <https://www.rfc-editor.org/info/rfc9421>.
[RFC9457]
Nottingham, M., Wilde, E., and S. Dalal, "Problem Details for HTTP APIs", RFC 9457, DOI 10.17487/RFC9457, , <https://www.rfc-editor.org/info/rfc9457>.
[RFC9562]
Davis, K., Ed., Peabody, B., Ed., and P. Leach, "Universally Unique IDentifiers (UUIDs)", RFC 9562, DOI 10.17487/RFC9562, , <https://www.rfc-editor.org/info/rfc9562>.
[WebSub]
Genestoux, J., Ed. and A. Parecki, Ed., "WebSub", W3C Recommendation, , <https://www.w3.org/TR/websub/>.

Appendix A. Changes from -00

This section will be removed prior to publication.

Structural and editorial changes:

Model and normative content:

Security:

References added:

Internal-consistency and second-pass review changes:

Appendix B. Implementation Survey

This appendix is non-normative. It documents the empirical basis for the default values recommended in Section 7.2 and Section 9.6 and for the status-code mappings in Section 9.2. Values reported here are taken from publicly available vendor documentation as of the date of this revision and are intended to illustrate the design space rather than to assert the current state of any individual system. Implementers SHOULD consult current vendor documentation for the specific systems they integrate with.

B.1. Surveyed Systems

The following event and webhook platforms publish delivery-semantics documentation and were considered in framing this document:

  • Stripe Webhooks
  • GitHub Webhooks
  • Amazon Web Services EventBridge and Amazon SNS HTTP/HTTPS subscriptions
  • Microsoft Azure Event Grid
  • Google Cloud Eventarc
  • Twilio Event Streams and Webhooks
  • Shopify Webhooks
  • Slack Events API
  • PayPal Webhooks
  • The Svix open-source webhook service

B.2. Retry Strategies

Surveyed systems report total retry windows ranging from approximately ten minutes (for low-tolerance notification systems) to several days (for billing- and account-state systems), with the central tendency falling between four and seventy-two hours. Retry counts within those windows range from a single-digit fixed-count strategy (e.g., a small number of attempts at fixed offsets) to exponential strategies extending to one or two hundred attempts.

The dominant backoff shape is exponential with random jitter. Base delays in the range of a few seconds and per-attempt caps in the range of several minutes to ten minutes are common. The default algorithm and parameters in Section 9.6 (base of 1 second, cap between 60 and 600 seconds) fall within this central range.

B.3. Idempotency and Deduplication

Surveyed systems are uniform in providing a producer-supplied identifier intended to support consumer-side deduplication, though they vary in naming (Idempotency-Key, delivery GUID, event id, and others) and in whether the identifier is carried in an HTTP header field or in the payload body.

Reported deduplication windows, where stated, range from approximately one hour to seven days. Twenty-four hours is the most commonly reported value among systems that publish a specific window. The RECOMMENDED minimum of 24 hours in Section 7.2 reflects this observation.

B.4. Status Code Treatment

Surveyed systems are broadly consistent in treating 2xx responses as Accepted, 5xx responses as retriable, and 4xx responses as non-retriable, with the exceptions and special cases captured in Section 9.2. Specific divergences observed include:

  • Treatment of 408 Request Timeout and 504 Gateway Timeout varies; some systems retry, others do not. This document treats them as Transient but flags the ambiguity.
  • Treatment of 429 Too Many Requests is consistently retriable, with most systems honoring the Retry-After header field when present.
  • Treatment of 410 Gone varies, with some systems automatically disabling the affected subscription and others requiring operator action. This document classifies 410 as Terminal and recommends marking the subscription inactive.

B.5. Synthesis

The default values and mappings recommended in this document are positioned to interoperate with the central range of observed practice rather than with any single system's specific behavior. Where this document adopts a tighter or stronger position than current practice (for example, requiring authentication and Idempotency-Key in the HTTP binding), that position is motivated by the security and interoperability goals stated in Section 4.

Acknowledgements

The author thanks early reviewers of -00 for their feedback and discussion. Specific acknowledgements will be added in future revisions as the document attracts community review.

Author's Address

Mayank Panke
Independent