<?xml version="1.0" encoding="UTF-8"?>

<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     ipr="trust200902"
     docName="draft-mayankpanke-event-delivery-semantics-01"
     category="info"
     submissionType="IETF"
     consensus="false"
     version="3"
     xml:lang="en"
     tocInclude="true"
     symRefs="true"
     sortRefs="true">

  <front>
    <title abbrev="Event Delivery Semantics">
      Event and Webhook Delivery Semantics
    </title>
    <seriesInfo name="Internet-Draft"
                value="draft-mayankpanke-event-delivery-semantics-01"/>

    <author initials="M." surname="Panke" fullname="Mayank Panke">
      <organization>Independent</organization>
      <address>
        <email>panke.mayank@gmail.com</email>
      </address>
    </author>

    <date year="2026" month="June" day="28"/>

    <area>Applications and Real-Time</area>

    <keyword>webhook</keyword>
    <keyword>event delivery</keyword>
    <keyword>idempotency</keyword>
    <keyword>retry</keyword>
    <keyword>HTTP</keyword>

    <abstract>
      <t>
        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.
      </t>
      <t>
        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.
      </t>
    </abstract>
  </front>

  <middle>

    <!-- =============================================================== -->
    <section anchor="introduction">
      <name>Introduction</name>
      <t>
        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.
      </t>
      <t>
        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.
      </t>
      <t>
        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
        <xref target="http-binding"/>).  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.
      </t>
    </section>

    <!-- =============================================================== -->
    <section anchor="conventions">
      <name>Conventions and Terminology</name>

      <t>
        The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
        "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
        "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
        "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>",
        "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and
        "<bcp14>OPTIONAL</bcp14>" in this document are to be
        interpreted as described in BCP 14
        <xref target="RFC2119"/> <xref target="RFC8174"/> when, and
        only when, they appear in all capitals, as shown here.
      </t>

      <t>
        The following terms are used throughout this document.
      </t>

      <dl newline="false" spacing="normal">
        <dt>Event:</dt>
        <dd>
          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.
        </dd>

        <dt>Event Producer:</dt>
        <dd>
          An entity that generates Events and is responsible for
          initiating Delivery Attempts toward one or more Event
          Consumers, directly or via an Intermediary.
        </dd>

        <dt>Event Consumer:</dt>
        <dd>
          An entity that exposes an endpoint to receive Delivery
          Attempts for Events and that returns Sender-Observed
          Outcomes in response to those attempts.
        </dd>

        <dt>Intermediary:</dt>
        <dd>
          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.
        </dd>

        <dt>Delivery Attempt:</dt>
        <dd>
          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.
        </dd>

        <dt>Acknowledgment:</dt>
        <dd>
          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.
        </dd>

        <dt>Sender-Observed Outcome:</dt>
        <dd>
          The result of a Delivery Attempt as observable by the
          sender.  Sender-Observed Outcomes are defined in
          <xref target="outcomes"/> and form the sole basis for
          retry decisions.
        </dd>

        <dt>Accepted:</dt>
        <dd>
          A Sender-Observed Outcome indicating that the Consumer
          acknowledged receipt of the Delivery Attempt.
        </dd>

        <dt>Transient Failure:</dt>
        <dd>
          A Sender-Observed Outcome indicating a condition that the
          sender may reasonably expect to resolve such that a future
          Delivery Attempt could be Accepted.
        </dd>

        <dt>Terminal Failure:</dt>
        <dd>
          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.
        </dd>

        <dt>Idempotency Identifier:</dt>
        <dd>
          A producer-supplied identifier that correlates multiple
          Delivery Attempts representing the same logical Event,
          enabling optional consumer-side deduplication.
        </dd>

        <dt>Retry:</dt>
        <dd>
          A subsequent Delivery Attempt for the same logical Event
          following a non-Accepted Sender-Observed Outcome.
        </dd>
      </dl>
    </section>

    <!-- =============================================================== -->
    <section anchor="problem">
      <name>Problem Statement</name>

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

      <section anchor="problem-interop">
        <name>Interoperability Failures Observed in Practice</name>
        <t>
          The absence of a shared delivery semantics model results
          in recurring issues, including:
        </t>
        <ul spacing="normal">
          <li>
            ambiguous retry behavior and unclear signaling of retry
            exhaustion;
          </li>
          <li>
            inconsistent acknowledgment semantics, with some
            producers treating any 2xx HTTP response as success and
            others requiring specific response codes or body content;
          </li>
          <li>
            non-standard idempotency and deduplication signaling,
            with header field names and value formats varying per
            producer;
          </li>
          <li>
            unclear classification of delivery failures, in
            particular conflation of transport-level and
            application-level failures; and
          </li>
          <li>
            increased exposure to replay and abuse, owing to ad hoc
            authentication and replay-mitigation conventions.
          </li>
        </ul>
        <t>
          These issues arise from missing application-layer
          semantics rather than deficiencies in underlying transport
          protocols.
        </t>
      </section>

      <section anchor="problem-transport">
        <name>Limitations of Existing Transport Semantics</name>
        <t>
          Transport protocols such as HTTP <xref target="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.
        </t>
      </section>

      <section anchor="non-goals">
        <name>Non-Goals</name>
        <t>
          This document does not attempt to:
        </t>
        <ul spacing="normal">
          <li>
            define or guarantee end-to-end delivery or processing
            correctness;
          </li>
          <li>
            provide exactly-once, at-most-once, or effectively-once
            guarantees;
          </li>
          <li>
            impose receiver-side storage or execution requirements;
          </li>
          <li>
            redefine or replace existing transport protocols; or
          </li>
          <li>
            standardize event payload formats or business semantics.
          </li>
        </ul>
        <t>
          All requirements defined in this document apply to
          sender-observable behavior and signaling.
        </t>
      </section>
    </section>

    <!-- =============================================================== -->
    <section anchor="goals">
      <name>Goals</name>
      <t>
        The goals of this specification are to:
      </t>
      <ul spacing="normal">
        <li>
          define a common vocabulary for event delivery semantics;
        </li>
        <li>
          standardize observable signaling for Delivery Attempts
          and retries;
        </li>
        <li>
          enable interoperable Idempotency Identifier and
          deduplication signaling;
        </li>
        <li>
          improve security posture through consistent guidance
          (see <xref target="security"/>); and
        </li>
        <li>
          reduce ambiguity without constraining implementation
          choices beyond what is required for interoperability.
        </li>
      </ul>
    </section>

    <!-- =============================================================== -->
    <section anchor="architecture">
      <name>Architecture Overview</name>

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

      <figure anchor="fig-arch">
        <name>Roles and Delivery Direction</name>
        <artwork align="left" type="ascii-art"><![CDATA[
+----------------+    Delivery Attempt    +----------------+
|                | ---------------------> |                |
| Event Producer |                        | Event Consumer |
|                | <--------------------- |                |
+----------------+ Sender-Observed Outcome+----------------+

                          (or)

+----------+  Delivery  +--------------+  Delivery  +----------+
| Producer | ---------> | Intermediary | ---------> | Consumer |
+----------+  Outcome   +--------------+  Outcome   +----------+
             <---------                 <---------
]]></artwork>
      </figure>

      <t>
        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.
      </t>
    </section>

    <!-- =============================================================== -->
    <section anchor="model">
      <name>Delivery Semantics Model</name>

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

      <section anchor="attempt">
        <name>Delivery Attempt</name>
        <t>
          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
          <bcp14>MUST</bcp14> be treated as best-effort,
          <bcp14>MUST NOT</bcp14> imply receipt, durability, or
          processing, and <bcp14>MAY</bcp14> be retried according
          to sender policy when Sender-Observed Outcomes indicate a
          non-terminal condition.
        </t>
      </section>

      <section anchor="outcomes">
        <name>Sender-Observed Outcomes</name>
        <t>
          This specification defines three Sender-Observed Outcomes
          for a Delivery Attempt:
        </t>
        <dl newline="false" spacing="normal">
          <dt>Accepted:</dt>
          <dd>
            The Consumer acknowledged receipt of the Delivery
            Attempt.  The sender <bcp14>MUST NOT</bcp14> retry the
            same Delivery Attempt solely on the basis of an
            Accepted outcome.
          </dd>
          <dt>Transient Failure:</dt>
          <dd>
            A condition was observed that the sender may reasonably
            expect to resolve.  The sender <bcp14>MAY</bcp14> retry
            the Delivery Attempt subject to sender policy.
          </dd>
          <dt>Terminal Failure:</dt>
          <dd>
            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 <bcp14>MUST NOT</bcp14> retry the
            same Delivery Attempt solely on the basis of a Terminal
            Failure outcome.
          </dd>
        </dl>
        <t>
          Senders <bcp14>MUST</bcp14> base retry behavior solely on
          Sender-Observed Outcomes and <bcp14>MUST NOT</bcp14> infer
          receiver-side state beyond what is explicitly signaled.
        </t>
      </section>

      <section anchor="retry-signaling">
        <name>Retry Signaling</name>
        <t>
          Retry behavior is sender-driven and policy-dependent.
          This specification standardizes only retry signaling, not
          retry guarantees.  Consumers <bcp14>MAY</bcp14> provide
          retry guidance (for example, by indicating a minimum delay
          before the next attempt), and senders <bcp14>MAY</bcp14>
          honor such guidance.  When a Consumer provides explicit
          retry guidance and the sender intends to retry, the sender
          <bcp14>SHOULD</bcp14> not retry sooner than indicated.
        </t>
        <t>
          Senders <bcp14>SHOULD</bcp14> apply backoff between
          retries to avoid amplifying load on Consumers experiencing
          Transient Failure conditions.  An algorithm for the HTTP
          binding is specified in <xref target="http-backoff"/>;
          interactions with denial-of-service mitigation are
          discussed in <xref target="sec-dos"/>.
        </t>
      </section>

      <section anchor="other-bindings">
        <name>Applicability to Other Transports</name>
        <t>
          This document defines bindings for HTTP only
          (<xref target="http-binding"/>).  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.
        </t>
      </section>
    </section>

    <!-- =============================================================== -->
    <section anchor="idempotency">
      <name>Idempotency and Deduplication Signaling</name>
      <t>
        Idempotency and deduplication are addressed through explicit
        signaling mechanisms only.  This specification does not
        require or assume receiver-side deduplication behavior.
      </t>

      <section anchor="idempotency-identifier">
        <name>Idempotency Identifier</name>
        <t>
          An Idempotency Identifier is a producer-supplied
          identifier intended to correlate multiple Delivery
          Attempts representing the same logical Event.  When
          present, the identifier <bcp14>MUST</bcp14> remain stable
          across retries of the same logical Event and
          <bcp14>MUST</bcp14> be scoped to the producer-consumer
          context.
        </t>
        <t>
          Producers <bcp14>SHOULD</bcp14> generate Idempotency
          Identifiers with sufficient entropy to make collisions
          across distinct logical Events negligible within the
          relevant deduplication window.
        </t>
      </section>

      <section anchor="dedup">
        <name>Deduplication Expectations</name>
        <t>
          Consumers <bcp14>MAY</bcp14> choose to perform
          deduplication based on the Idempotency Identifier and
          local policy.  Senders <bcp14>MUST</bcp14> tolerate
          duplicate delivery in all cases.  Deduplication remains
          an optimization, not a correctness requirement.
        </t>
        <t>
          A Consumer that performs deduplication
          <bcp14>SHOULD</bcp14> 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
          <bcp14>RECOMMENDED</bcp14>.
        </t>
        <t>
          A Producer <bcp14>MUST NOT</bcp14> 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
          <bcp14>SHOULD</bcp14> treat it as at least the
          <bcp14>RECOMMENDED</bcp14> minimum above and
          <bcp14>SHOULD</bcp14> generate fresh identifiers per
          distinct logical Event regardless.
        </t>
      </section>
    </section>

    <!-- =============================================================== -->
    <section anchor="failure-class">
      <name>Failure Classification</name>
      <t>
        Failure classification in this specification is minimal and
        sender-centric.  Two failure classes are defined:
      </t>
      <dl newline="false" spacing="normal">
        <dt>Transport-level failure:</dt>
        <dd>
          A failure attributable to the transport, such as
          connection refusal, connection reset, timeout, or
          name-resolution failure.  Transport-level failures
          <bcp14>SHOULD</bcp14> be treated as Transient Failure
          unless sender policy specifies otherwise.
        </dd>
        <dt>Application-level rejection:</dt>
        <dd>
          A failure signaled by the Consumer at the application
          layer indicating that the Delivery Attempt was received
          but not accepted.  Application-level rejections
          <bcp14>MAY</bcp14> be either Transient Failure or
          Terminal Failure depending on the specific signal
          (see <xref target="http-status-mapping"/> for the HTTP
          mapping).
        </dd>
      </dl>
      <t>
        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.
      </t>
    </section>

    <!-- =============================================================== -->
    <section anchor="http-binding">
      <name>HTTP Binding</name>
      <t>
        This section defines a binding of the delivery semantics
        model (<xref target="model"/>) to HTTP <xref target="RFC9110"/>.
        Producers and Consumers exchanging Events over HTTP
        <bcp14>SHOULD</bcp14> implement this binding to enable
        interoperability.  Other transport bindings are out of scope
        for this document.
      </t>

      <section anchor="http-method">
        <name>Method and Request Semantics</name>
        <t>
          A Delivery Attempt using the HTTP binding
          <bcp14>SHOULD</bcp14> use the POST method.  PUT
          <bcp14>MAY</bcp14> 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
          <bcp14>NOT RECOMMENDED</bcp14> for Delivery Attempts
          because they imply no state change and are subject to
          intermediary caching behavior that may suppress retries.
        </t>
        <t>
          The Content-Type of the request <bcp14>MUST</bcp14>
          accurately identify the Event payload media type.  This
          document does not constrain payload media type; see
          <xref target="related-work"/> for a discussion of
          common choices.
        </t>
      </section>

      <section anchor="http-status-mapping">
        <name>Mapping Sender-Observed Outcomes to HTTP Status Codes</name>
        <t>
          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.
        </t>
        <t>
          Producers and Consumers <bcp14>MAY</bcp14> 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 <xref target="security"/>.
          Absent such an agreement, the defaults below apply.
        </t>

        <section anchor="status-accepted">
          <name>Accepted</name>
          <t>
            A 2xx (Successful) status code <bcp14>SHOULD</bcp14>
            be treated as Accepted.  The following finer-grained
            guidance applies:
          </t>
          <ul spacing="normal">
            <li>
              200 (OK), 201 (Created), 202 (Accepted), and 204 (No
              Content) <bcp14>MUST</bcp14> be treated as Accepted
              when received in response to a Delivery Attempt.
            </li>
            <li>
              207 (Multi-Status) <bcp14>SHOULD NOT</bcp14> 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
              <bcp14>MUST</bcp14> have prior agreement on its
              interpretation.
            </li>
            <li>
              Other 2xx status codes <bcp14>SHOULD</bcp14> be
              treated as Accepted unless prior agreement specifies
              otherwise.
            </li>
          </ul>
          <t>
            The presence or absence of a response body
            <bcp14>MUST NOT</bcp14> alter the Sender-Observed
            Outcome derived from a 2xx status code, except as
            stated above for 207.
          </t>
        </section>

        <section anchor="status-transient">
          <name>Transient Failure</name>
          <t>
            The following status codes <bcp14>SHOULD</bcp14> be
            treated as Transient Failure:
          </t>
          <table anchor="tab-transient">
            <name>Status Codes Mapped to Transient Failure</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Notes</th></tr>
            </thead>
            <tbody>
              <tr><td>408</td><td>Request Timeout</td>
                <td>Ambiguous: the request may or may not have
                been processed.  Safe retry depends on the
                Idempotency-Key field, which is required by
                <xref target="http-idempotency"/>.</td></tr>
              <tr><td>421</td><td>Misdirected Request</td>
                <td>Indicates routing error at the Consumer; retry
                MAY succeed against a re-resolved endpoint.</td></tr>
              <tr><td>425</td><td>Too Early</td>
                <td>Retry after the early-data condition clears.</td></tr>
              <tr><td>429</td><td>Too Many Requests</td>
                <td>Honor Retry-After
                (<xref target="http-retry-after"/>) if present.</td></tr>
              <tr><td>500</td><td>Internal Server Error</td>
                <td>Generic server error; retry with backoff.</td></tr>
              <tr><td>502</td><td>Bad Gateway</td>
                <td>Upstream of Consumer failed; retry.</td></tr>
              <tr><td>503</td><td>Service Unavailable</td>
                <td>Honor Retry-After if present.</td></tr>
              <tr><td>504</td><td>Gateway Timeout</td>
                <td>Same ambiguity as 408; safe retry depends on
                the Idempotency-Key field required by
                <xref target="http-idempotency"/>.</td></tr>
              <tr><td>511</td><td>Network Authentication Required</td>
                <td>Typically injected by an on-path captive portal;
                resolves out of band.</td></tr>
            </tbody>
          </table>
          <t>
            Other 5xx status codes not listed above
            <bcp14>SHOULD</bcp14> be treated as Transient Failure
            unless prior agreement specifies otherwise.
          </t>
        </section>

        <section anchor="status-terminal">
          <name>Terminal Failure</name>
          <t>
            The following status codes <bcp14>SHOULD</bcp14> be
            treated as Terminal Failure:
          </t>
          <table anchor="tab-terminal">
            <name>Status Codes Mapped to Terminal Failure</name>
            <thead>
              <tr><th>Code</th><th>Name</th><th>Notes</th></tr>
            </thead>
            <tbody>
              <tr><td>400</td><td>Bad Request</td>
                <td>Malformed request; retry will produce the same
                outcome.</td></tr>
              <tr><td>401</td><td>Unauthorized</td>
                <td>Producers operating with rotating credentials
                <bcp14>MAY</bcp14> attempt one credential refresh
                and a single subsequent retry before classifying
                as Terminal.</td></tr>
              <tr><td>403</td><td>Forbidden</td>
                <td>Authorization decision; retry not useful absent
                policy change.</td></tr>
              <tr><td>404</td><td>Not Found</td>
                <td>Endpoint missing; reconfiguration required.</td></tr>
              <tr><td>405</td><td>Method Not Allowed</td>
                <td>Producer-Consumer agreement mismatch; see
                <xref target="http-method"/>.</td></tr>
              <tr><td>410</td><td>Gone</td>
                <td>Endpoint permanently removed; Producer
                <bcp14>SHOULD</bcp14> mark the subscription
                inactive.</td></tr>
              <tr><td>413</td><td>Content Too Large</td>
                <td>Event payload exceeds Consumer limit; retry
                without payload reduction will fail.</td></tr>
              <tr><td>414</td><td>URI Too Long</td>
                <td>Typically a Producer configuration error.</td></tr>
              <tr><td>415</td><td>Unsupported Media Type</td>
                <td>Renegotiate media type out of band.</td></tr>
              <tr><td>422</td><td>Unprocessable Content</td>
                <td>Schema or semantic validation failure.</td></tr>
              <tr><td>451</td><td>Unavailable for Legal Reasons</td>
                <td>Producer <bcp14>SHOULD</bcp14> record and
                escalate to operator review.</td></tr>
            </tbody>
          </table>
          <t>
            Other 4xx status codes not listed above
            <bcp14>SHOULD</bcp14> be treated as Terminal Failure
            unless prior agreement specifies otherwise.
          </t>
          <t>
            When a Consumer signals deprecation via the Sunset
            header field <xref target="RFC8594"/>, Producers
            <bcp14>SHOULD</bcp14> treat continued Delivery Attempts
            past the indicated Sunset time as candidates for
            Terminal classification on the next non-Accepted
            outcome.
          </t>
        </section>

        <section anchor="status-other">
          <name>Other Status Code Classes</name>
          <t>
            1xx (Informational) status codes are handled per
            <xref target="RFC9110"/> and do not in themselves
            constitute a Sender-Observed Outcome.
          </t>
          <t>
            3xx (Redirection) status codes are handled per
            <xref target="RFC9110"/>.  In particular, 308
            (Permanent Redirect) <bcp14>SHOULD</bcp14> cause the
            Producer to update its stored endpoint URI for the
            subscription before issuing the next Delivery Attempt.
            307 (Temporary Redirect) <bcp14>MUST NOT</bcp14> cause
            the Producer to update stored configuration.
          </t>
        </section>

        <section anchor="status-problem-details">
          <name>Problem Details in Responses</name>
          <t>
            Consumers <bcp14>MAY</bcp14> return problem details in
            the response body using the format defined in
            <xref target="RFC9457"/> to aid operator diagnosis.
            The Sender-Observed Outcome <bcp14>MUST</bcp14> still
            be derived from the status code; problem details are
            advisory.
          </t>
        </section>
      </section>

      <section anchor="http-network">
        <name>Network-Level Failures</name>
        <t>
          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)
          <bcp14>MUST</bcp14> be treated as a transport-level
          failure as defined in <xref target="failure-class"/>
          and, by default, as Transient Failure.
        </t>
        <t>
          A Delivery Attempt for which the request was transmitted
          but the response was not received in full
          <bcp14>MUST</bcp14> be treated as Transient Failure with
          unknown outcome.  Safe retry in this case depends on the
          Idempotency-Key header field, which is required by
          <xref target="http-idempotency"/> for all Delivery
          Attempts in the HTTP binding.
        </t>
      </section>

      <section anchor="http-idempotency">
        <name>Idempotency-Key Header Field</name>
        <t>
          In the HTTP binding defined by this document, every
          Delivery Attempt <bcp14>MUST</bcp14> include an
          Idempotency-Key header field carrying the Idempotency
          Identifier defined in
          <xref target="idempotency-identifier"/>.  The header
          field's syntax and processing rules
          <bcp14>MUST</bcp14> be those defined by
          <xref target="I-D.ietf-httpapi-idempotency-key"/>.
        </t>
        <t>
          The value of the Idempotency-Key header field
          <bcp14>MUST</bcp14> be identical across all Delivery
          Attempts for the same logical Event from the same
          Producer-Consumer Context (defined below).  The value
          <bcp14>MUST</bcp14> be a string of sufficient entropy
          to make collisions negligible across the Deduplication
          Window (<xref target="dedup"/>); a UUID
          <xref target="RFC9562"/> or a base64url-encoded random
          value of at least 128 bits satisfies this requirement.
        </t>
        <t>
          For the purposes of this document, a Producer-Consumer
          Context is the tuple (Producer identity, Consumer
          endpoint URI), where:
        </t>
        <ul spacing="normal">
          <li>
            Producer identity is the authenticated principal
            presenting the Delivery Attempt.  Authentication is
            <bcp14>REQUIRED</bcp14> in the HTTP binding; see
            <xref target="sec-auth"/>.
          </li>
          <li>
            Consumer endpoint URI is the effective request URI as
            defined in
            <xref target="RFC9110" sectionFormat="of"
                  section="7.1"/>, after any 308 (Permanent
            Redirect) updates per
            <xref target="status-other"/>.
          </li>
        </ul>
        <t>
          Two Delivery Attempts share an Idempotency-Key scope if
          and only if they share a Producer-Consumer Context.
        </t>
      </section>

      <section anchor="http-retry-after">
        <name>Retry-After Header Field</name>
        <t>
          When a Consumer returns a response classified as Transient
          Failure, the Consumer <bcp14>MAY</bcp14> include a
          Retry-After header field as defined in
          <xref target="RFC9110" sectionFormat="of"
                section="10.2.3"/> to indicate a minimum delay
          before the next Delivery Attempt.
        </t>
        <t>
          When a Retry-After header field is present in a response
          classified as Transient Failure and the sender intends to
          retry, the sender <bcp14>SHOULD NOT</bcp14> initiate the
          next Delivery Attempt for the same logical Event sooner
          than indicated by the Retry-After value.  Senders
          <bcp14>MAY</bcp14> apply additional backoff beyond the
          Retry-After value at their discretion.
        </t>
        <t>
          A Retry-After value of 0 indicates that the Consumer has
          no preferred delay; the Producer's local retry policy
          applies (see <xref target="http-backoff"/>).
        </t>
      </section>

      <section anchor="http-backoff">
        <name>Recommended Retry Algorithm</name>
        <t>
          Producers retrying after Transient Failure outcomes
          <bcp14>SHOULD</bcp14> apply an algorithm with the
          following properties:
        </t>
        <ul spacing="normal">
          <li>monotonically non-decreasing expected delay between
          successive retries (backoff);</li>
          <li>independent randomization across Producer instances
          (jitter), to prevent synchronized retry storms; and</li>
          <li>a finite maximum number of retries, a finite total
          retry duration, or both.</li>
        </ul>
        <t>
          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
          <bcp14>MAY</bcp14> use other algorithms that satisfy the
          properties above.
        </t>
        <t>
          When a Retry-After value is supplied
          (<xref target="http-retry-after"/>) and exceeds the
          delay selected by the algorithm above, the Retry-After
          value <bcp14>MUST</bcp14> be honored as the lower bound
          for the next Delivery Attempt.
        </t>
      </section>

      <section anchor="http-intermediary">
        <name>Intermediary Behavior</name>
        <t>
          When an Intermediary (<xref target="architecture"/>)
          relays an Event over the HTTP binding:
        </t>
        <ul spacing="normal">
          <li>
            The Idempotency-Key header field value
            <bcp14>MUST</bcp14> be preserved unchanged on the
            relayed Delivery Attempt sent to the downstream
            Consumer.  Intermediaries
            <bcp14>MUST NOT</bcp14> rewrite the value, even when
            they buffer or fan out Events.
          </li>
          <li>
            The Retry-After header field
            <bcp14>MUST NOT</bcp14> be propagated upstream.  It
            applies only between the immediate sender and receiver
            of a given hop.
          </li>
          <li>
            The Sender-Observed Outcome at each hop is independent.
            An Intermediary <bcp14>MAY</bcp14> return any outcome
            to its upstream Producer that accurately reflects its
            own state.
          </li>
          <li>
            Authentication and integrity protection
            (<xref target="sec-auth"/>,
            <xref target="sec-integrity"/>) apply per hop unless
            an end-to-end mechanism such as HTTP Message
            Signatures <xref target="RFC9421"/> is used to bind
            origin metadata across hops.
          </li>
        </ul>

        <t>
          An Intermediary that buffers Events
          <bcp14>MAY</bcp14> return Accepted upstream prior to
          successful downstream delivery (store-and-forward
          operation) only when both of the following conditions
          hold:
        </t>
        <ol spacing="normal">
          <li>
            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
          </li>
          <li>
            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).
          </li>
        </ol>
        <t>
          Absent both conditions, an Intermediary
          <bcp14>MUST NOT</bcp14> return Accepted upstream before
          the downstream Delivery Attempt has itself yielded an
          Accepted Sender-Observed Outcome.
        </t>
      </section>

      <section anchor="http-examples">
        <name>Examples</name>
        <t>
          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 <xref target="RFC2606"/>.
        </t>

        <t>
          For clarity, the Content-Length header field and other
          framing headers are omitted from the examples; the
          message-body length is determined per
          <xref target="RFC9110"/>.
        </t>

        <section anchor="example-accepted">
          <name>Example: Accepted</name>
          <t>
            A Producer delivers an Event; the Consumer
            acknowledges with 200 OK.
          </t>
          <sourcecode type="http-message"><![CDATA[
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"}
]]></sourcecode>
          <sourcecode type="http-message"><![CDATA[
HTTP/1.1 200 OK
]]></sourcecode>
          <t>
            Sender-Observed Outcome: Accepted.  No retry is
            performed.
          </t>
        </section>

        <section anchor="example-transient">
          <name>Example: Transient Failure with Retry-After</name>
          <t>
            The Consumer is under load and asks the Producer to
            retry after 30 seconds.
          </t>
          <sourcecode type="http-message"><![CDATA[
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"}
]]></sourcecode>
          <sourcecode type="http-message"><![CDATA[
HTTP/1.1 503 Service Unavailable
Retry-After: 30
]]></sourcecode>
          <t>
            Sender-Observed Outcome: Transient Failure.  The
            Producer waits at least 30 seconds, then retries the
            same Delivery Attempt with the same Idempotency-Key.
          </t>
          <sourcecode type="http-message"><![CDATA[
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"}
]]></sourcecode>
          <sourcecode type="http-message"><![CDATA[
HTTP/1.1 200 OK
]]></sourcecode>
          <t>
            The retry is Accepted.  Because the Idempotency-Key is
            preserved, a Consumer that performs deduplication (see
            <xref target="dedup"/>) processes the Event exactly
            once across the two Delivery Attempts.
          </t>
        </section>

        <section anchor="example-terminal">
          <name>Example: Terminal Failure with Problem Details</name>
          <t>
            The Consumer rejects the Event as semantically
            invalid.
          </t>
          <sourcecode type="http-message"><![CDATA[
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":""}
]]></sourcecode>
          <sourcecode type="http-message"><![CDATA[
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."
}
]]></sourcecode>
          <t>
            Sender-Observed Outcome: Terminal Failure.  The
            Producer <bcp14>MUST NOT</bcp14> retry the Delivery
            Attempt; the problem details are recorded for operator
            diagnosis.
          </t>
        </section>

        <section anchor="example-network">
          <name>Example: Network-Level Failure</name>
          <t>
            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.
          </t>
          <t>
            Sender-Observed Outcome: Transient Failure, with
            unknown receiver state per
            <xref target="http-network"/>.  The Producer retries
            using the same Idempotency-Key to permit
            Consumer-side deduplication.  The next retry delay is
            governed by <xref target="http-backoff"/>.
          </t>
        </section>
      </section>

      <section anchor="http-versions">
        <name>HTTP Version Considerations</name>
        <t>
          The Delivery Attempt semantics defined in this section
          are version-independent at the application layer.  The
          following version-specific behaviors apply:
        </t>
        <ul spacing="normal">
          <li>
            Producers using HTTP/2 <xref target="RFC9113"/> or
            HTTP/3 <xref target="RFC9114"/>
            <bcp14>MAY</bcp14> 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
            <bcp14>MUST</bcp14> be treated as a network-level
            failure per <xref target="http-network"/>.
          </li>
          <li>
            Producers <bcp14>MUST NOT</bcp14> send Delivery
            Attempts in TLS 1.3 0-RTT (early) data
            <xref target="RFC8446"/> unless the Producer-Consumer
            Context explicitly permits it through out-of-band
            agreement satisfying the conditions in
            <xref target="http-status-mapping"/>.  TLS 1.3 0-RTT
            data is replay-vulnerable at the transport layer
            regardless of application-layer signing or
            Idempotency-Key-based deduplication; see
            <xref target="sec-replay"/>.
          </li>
          <li>
            HTTP/2 server push and HTTP/3 server push
            <bcp14>MUST NOT</bcp14> be used to deliver Events.
            The Sender-Observed Outcome model presumes
            sender-initiated Delivery Attempts.
          </li>
        </ul>
      </section>
    </section>

    <!-- =============================================================== -->
    <section anchor="related-work">
      <name>Relationship to Existing Work</name>
      <t>
        Several existing specifications and operational conventions
        overlap with the scope of this document.  This section
        positions this profile relative to that work.
      </t>

      <dl newline="true" spacing="normal">
        <dt>CloudEvents <xref target="CLOUDEVENTS"/>:</dt>
        <dd>
          CloudEvents defines a payload format for event data and
          bindings of that format to several transports including
          HTTP.  CloudEvents does not normatively define retry,
          acknowledgment, or deduplication semantics.  This
          document is complementary: a CloudEvents-formatted
          payload may be delivered using this profile.
          <br/>
          The CloudEvents "id" attribute is defined to be unique
          per (source, id) pair within the producer, not
          necessarily globally unique, and CloudEvents does not
          require "id" to be stable across delivery retries.
          Accordingly, a Producer <bcp14>MAY</bcp14> reuse the
          CloudEvents "id" value as the Idempotency Identifier
          (<xref target="idempotency-identifier"/>) only when (a)
          the Producer guarantees the value is stable across all
          retries of the same logical Event, and (b) the
          (source, id) scope falls within a single
          Producer-Consumer Context
          (<xref target="http-idempotency"/>).  When either
          condition does not hold, the Producer
          <bcp14>MUST</bcp14> generate a separate Idempotency
          Identifier and carry it in the Idempotency-Key header
          field independently of the CloudEvents "id".
        </dd>

        <dt>The Idempotency-Key header field
            <xref target="I-D.ietf-httpapi-idempotency-key"/>:</dt>
        <dd>
          This profile reuses the Idempotency-Key header field as
          defined by that work in progress
          (<xref target="http-idempotency"/>) rather than defining
          a new header.  The two documents are intended to remain
          aligned.
        </dd>

        <dt>HTTP Semantics <xref target="RFC9110"/>:</dt>
        <dd>
          This profile builds on but does not modify HTTP
          semantics.  The status-code interpretations in
          <xref target="http-status-mapping"/> are application-layer
          conventions specific to event delivery; they do not
          override the meaning of any status code defined by
          <xref target="RFC9110"/>.
        </dd>

        <dt>WebSub <xref target="WebSub"/>:</dt>
        <dd>
          WebSub is a W3C Recommendation defining a
          publish-subscribe protocol over HTTP, including
          subscription management.  WebSub does not standardize
          the delivery semantics this document addresses; a WebSub
          publisher and subscriber could in principle adopt this
          profile for the notification leg of the protocol.
        </dd>

        <dt>Vendor webhook conventions:</dt>
        <dd>
          Major commercial event and webhook platforms publish
          internally consistent but mutually divergent conventions
          for retry, acknowledgment, idempotency, and signing.
          A non-exhaustive survey of publicly documented behavior
          across such systems is provided in
          <xref target="impl-survey"/>; the mappings in
          <xref target="http-status-mapping"/> and the default
          values in this document fall within the central range
          observed in that survey.
        </dd>
      </dl>
    </section>

    <!-- =============================================================== -->
    <section anchor="security">
      <name>Security Considerations</name>

      <t>
        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
        <xref target="RFC3552"/>.
      </t>

      <section anchor="sec-threats">
        <name>Threat Model</name>
        <t>
          The principal threats to event and webhook delivery
          considered by this document are:
        </t>
        <ul spacing="normal">
          <li>
            spoofing of an Event Producer by a third party in order
            to inject fabricated Events into a Consumer;
          </li>
          <li>
            replay of previously delivered Events by an on-path or
            off-path attacker;
          </li>
          <li>
            modification of Event payloads or metadata in transit;
          </li>
          <li>
            disclosure of Event contents to unauthorized parties;
            and
          </li>
          <li>
            abuse of retry behavior to amplify load against either
            a Consumer or an unrelated third party.
          </li>
        </ul>
      </section>

      <section anchor="sec-transport">
        <name>Transport Security</name>
        <t>
          Producers and Consumers <bcp14>SHOULD</bcp14> use TLS
          <xref target="RFC8446"/> for all Delivery Attempts.
          Producers <bcp14>SHOULD</bcp14> validate Consumer
          endpoint certificates and <bcp14>SHOULD NOT</bcp14>
          deliver Events to endpoints that fail certificate
          validation.
        </t>
      </section>

      <section anchor="sec-auth">
        <name>Authentication of Producers</name>
        <t>
          In the HTTP binding (<xref target="http-binding"/>),
          Consumers <bcp14>MUST</bcp14> authenticate the Producer
          of each Delivery Attempt.  This requirement supports the
          Producer-Consumer Context definition in
          <xref target="http-idempotency"/> and is the basis of
          the replay-mitigation requirement in
          <xref target="sec-replay"/>.
        </t>
        <t>
          Suitable authentication mechanisms include, but are not
          limited to, HTTP Message Signatures
          <xref target="RFC9421"/>, mutual TLS, and bearer tokens
          carried in the Authorization header field as defined in
          <xref target="RFC9110"/>.  Selection of a specific
          mechanism is a deployment decision and is out of scope
          for this document.
        </t>
        <t>
          Whatever mechanism is chosen, Consumers
          <bcp14>MUST NOT</bcp14> treat a Delivery Attempt as
          Accepted on the basis of its payload alone when
          authentication has not been verified.
        </t>
      </section>

      <section anchor="sec-integrity">
        <name>Integrity Protection</name>
        <t>
          Producers <bcp14>SHOULD</bcp14> protect the integrity of
          Event payloads and security-relevant metadata in transit.
          Use of TLS (<xref target="sec-transport"/>) provides
          integrity for the transport channel.  Use of HTTP Message
          Signatures <xref target="RFC9421"/> additionally provides
          integrity over selected message components that survives
          intermediary processing.
        </t>
      </section>

      <section anchor="sec-replay">
        <name>Replay Mitigation</name>
        <t>
          Consumers that act on Events <bcp14>MUST</bcp14> mitigate
          replay attacks.  At least one of the following
          mechanisms <bcp14>MUST</bcp14> be in effect for any
          Consumer for which replay would have security
          consequences:
        </t>
        <ol spacing="normal">
          <li>
            Deduplication based on the Idempotency Identifier
            (<xref target="dedup"/>) 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.
          </li>
          <li>
            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.
          </li>
        </ol>
        <t>
          The Idempotency Identifier alone is
          <bcp14>NOT RECOMMENDED</bcp14> 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
          <bcp14>MUST</bcp14> implement mechanism (2) above to
          satisfy the requirement in this section.
        </t>
        <t>
          When Delivery Attempts traverse TLS 1.3
          <xref target="RFC8446"/>, neither mechanism above
          mitigates replay of TLS 1.3 0-RTT (early) data, which
          is replayable at the transport layer.  Producers
          <bcp14>MUST NOT</bcp14> transmit Delivery Attempts as
          0-RTT data except under the conditions stated in
          <xref target="http-versions"/>.  When Delivery Attempts
          are transmitted as 0-RTT data under those conditions,
          Consumers <bcp14>MUST</bcp14> 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.
        </t>
      </section>

      <section anchor="sec-confidentiality">
        <name>Confidentiality</name>
        <t>
          Event payloads may contain confidential data.  Producers
          and Consumers <bcp14>SHOULD</bcp14> use TLS to provide
          confidentiality on the transport channel and
          <bcp14>SHOULD</bcp14> avoid logging full Event payloads
          at intermediary points where such logs are not subject to
          equivalent protection.
        </t>
      </section>

      <section anchor="sec-authz">
        <name>Endpoint Authorization</name>
        <t>
          Producers <bcp14>SHOULD</bcp14> 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)
          <bcp14>SHOULD</bcp14> validate those URLs and
          <bcp14>SHOULD NOT</bcp14> permit delivery to addresses
          inside their own trust boundary unless explicitly
          intended, to mitigate server-side request forgery.
        </t>
      </section>

      <section anchor="sec-dos">
        <name>Retry Amplification and Denial-of-Service Considerations</name>
        <t>
          Retry behavior interacts directly with availability.
          The bounding and jitter requirements in
          <xref target="http-backoff"/> are motivated in part by
          the need to prevent senders from amplifying load against
          a Consumer recovering from a Transient Failure
          condition.  Senders <bcp14>MUST NOT</bcp14> retry
          without bound; the finite-retry requirement in
          <xref target="http-backoff"/> is normative for that
          reason.
        </t>
        <t>
          When a Consumer returns a Retry-After value
          (<xref target="http-retry-after"/>), honoring that
          value contributes directly to mitigating retry
          amplification.
        </t>
        <t>
          Producers <bcp14>SHOULD</bcp14> 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.
        </t>
      </section>
    </section>

    <!-- =============================================================== -->
    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>
        This document makes no request of IANA.
      </t>
      <t>
        The HTTP header field name "Idempotency-Key" referenced in
        <xref target="http-idempotency"/> is registered by
        <xref target="I-D.ietf-httpapi-idempotency-key"/>; this
        document defers to that registration.
      </t>
    </section>

  </middle>

  <!-- =============================================================== -->
  <back>

    <references>
      <name>References</name>

      <references>
        <name>Normative References</name>

        <reference anchor="RFC2119"
                   target="https://www.rfc-editor.org/info/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement
                   Levels</title>
            <author initials="S." surname="Bradner" fullname="S. Bradner">
              <organization/>
            </author>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>

        <reference anchor="RFC8174"
                   target="https://www.rfc-editor.org/info/rfc8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119
                   Key Words</title>
            <author initials="B." surname="Leiba" fullname="B. Leiba">
              <organization/>
            </author>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>

        <reference anchor="RFC9110"
                   target="https://www.rfc-editor.org/info/rfc9110">
          <front>
            <title>HTTP Semantics</title>
            <author initials="R." surname="Fielding"
                    fullname="R. Fielding" role="editor">
              <organization/>
            </author>
            <author initials="M." surname="Nottingham"
                    fullname="M. Nottingham" role="editor">
              <organization/>
            </author>
            <author initials="J." surname="Reschke"
                    fullname="J. Reschke" role="editor">
              <organization/>
            </author>
            <date year="2022" month="June"/>
          </front>
          <seriesInfo name="STD" value="97"/>
          <seriesInfo name="RFC" value="9110"/>
          <seriesInfo name="DOI" value="10.17487/RFC9110"/>
        </reference>
      </references>

      <references>
        <name>Informative References</name>

        <reference anchor="RFC3552"
                   target="https://www.rfc-editor.org/info/rfc3552">
          <front>
            <title>Guidelines for Writing RFC Text on Security
                   Considerations</title>
            <author initials="E." surname="Rescorla"
                    fullname="E. Rescorla">
              <organization/>
            </author>
            <author initials="B." surname="Korver"
                    fullname="B. Korver">
              <organization/>
            </author>
            <date year="2003" month="July"/>
          </front>
          <seriesInfo name="BCP" value="72"/>
          <seriesInfo name="RFC" value="3552"/>
          <seriesInfo name="DOI" value="10.17487/RFC3552"/>
        </reference>

        <reference anchor="RFC7322"
                   target="https://www.rfc-editor.org/info/rfc7322">
          <front>
            <title>RFC Style Guide</title>
            <author initials="H." surname="Flanagan"
                    fullname="H. Flanagan">
              <organization/>
            </author>
            <author initials="S." surname="Ginoza"
                    fullname="S. Ginoza">
              <organization/>
            </author>
            <date year="2014" month="September"/>
          </front>
          <seriesInfo name="RFC" value="7322"/>
          <seriesInfo name="DOI" value="10.17487/RFC7322"/>
        </reference>

        <reference anchor="RFC8446"
                   target="https://www.rfc-editor.org/info/rfc8446">
          <front>
            <title>The Transport Layer Security (TLS) Protocol
                   Version 1.3</title>
            <author initials="E." surname="Rescorla"
                    fullname="E. Rescorla">
              <organization/>
            </author>
            <date year="2018" month="August"/>
          </front>
          <seriesInfo name="RFC" value="8446"/>
          <seriesInfo name="DOI" value="10.17487/RFC8446"/>
        </reference>

        <reference anchor="RFC9113"
                   target="https://www.rfc-editor.org/info/rfc9113">
          <front>
            <title>HTTP/2</title>
            <author initials="M." surname="Thomson"
                    fullname="M. Thomson" role="editor">
              <organization/>
            </author>
            <author initials="C." surname="Benfield"
                    fullname="C. Benfield" role="editor">
              <organization/>
            </author>
            <date year="2022" month="June"/>
          </front>
          <seriesInfo name="RFC" value="9113"/>
          <seriesInfo name="DOI" value="10.17487/RFC9113"/>
        </reference>

        <reference anchor="RFC9114"
                   target="https://www.rfc-editor.org/info/rfc9114">
          <front>
            <title>HTTP/3</title>
            <author initials="M." surname="Bishop"
                    fullname="M. Bishop" role="editor">
              <organization/>
            </author>
            <date year="2022" month="June"/>
          </front>
          <seriesInfo name="RFC" value="9114"/>
          <seriesInfo name="DOI" value="10.17487/RFC9114"/>
        </reference>

        <reference anchor="RFC9421"
                   target="https://www.rfc-editor.org/info/rfc9421">
          <front>
            <title>HTTP Message Signatures</title>
            <author initials="A." surname="Backman"
                    fullname="A. Backman" role="editor">
              <organization/>
            </author>
            <author initials="J." surname="Richer"
                    fullname="J. Richer" role="editor">
              <organization/>
            </author>
            <author initials="M." surname="Sporny"
                    fullname="M. Sporny">
              <organization/>
            </author>
            <date year="2024" month="February"/>
          </front>
          <seriesInfo name="RFC" value="9421"/>
          <seriesInfo name="DOI" value="10.17487/RFC9421"/>
        </reference>

        <reference anchor="RFC9457"
                   target="https://www.rfc-editor.org/info/rfc9457">
          <front>
            <title>Problem Details for HTTP APIs</title>
            <author initials="M." surname="Nottingham"
                    fullname="M. Nottingham">
              <organization/>
            </author>
            <author initials="E." surname="Wilde"
                    fullname="E. Wilde">
              <organization/>
            </author>
            <author initials="S." surname="Dalal"
                    fullname="S. Dalal">
              <organization/>
            </author>
            <date year="2023" month="July"/>
          </front>
          <seriesInfo name="RFC" value="9457"/>
          <seriesInfo name="DOI" value="10.17487/RFC9457"/>
        </reference>

        <reference anchor="RFC9562"
                   target="https://www.rfc-editor.org/info/rfc9562">
          <front>
            <title>Universally Unique IDentifiers (UUIDs)</title>
            <author initials="K." surname="Davis"
                    fullname="K. Davis" role="editor">
              <organization/>
            </author>
            <author initials="B." surname="Peabody"
                    fullname="B. Peabody" role="editor">
              <organization/>
            </author>
            <author initials="P." surname="Leach"
                    fullname="P. Leach">
              <organization/>
            </author>
            <date year="2024" month="May"/>
          </front>
          <seriesInfo name="RFC" value="9562"/>
          <seriesInfo name="DOI" value="10.17487/RFC9562"/>
        </reference>

        <reference anchor="I-D.ietf-httpapi-idempotency-key"
                   target="https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-idempotency-key">
          <front>
            <title>The Idempotency-Key HTTP Header Field</title>
            <author initials="J." surname="Yasskin"
                    fullname="J. Yasskin">
              <organization/>
            </author>
            <author initials="S." surname="Dalal"
                    fullname="S. Dalal">
              <organization/>
            </author>
            <date year="2025"/>
          </front>
          <seriesInfo name="Internet-Draft"
                      value="draft-ietf-httpapi-idempotency-key"/>
          <refcontent>Work in Progress</refcontent>
        </reference>

        <reference anchor="CLOUDEVENTS"
                   target="https://github.com/cloudevents/spec">
          <front>
            <title>CloudEvents - A specification for describing
                   event data in a common way</title>
            <author>
              <organization>Cloud Native Computing Foundation</organization>
            </author>
            <date year="2024"/>
          </front>
        </reference>

        <reference anchor="RFC2606"
                   target="https://www.rfc-editor.org/info/rfc2606">
          <front>
            <title>Reserved Top Level DNS Names</title>
            <author initials="D." surname="Eastlake 3rd"
                    fullname="D. Eastlake 3rd">
              <organization/>
            </author>
            <author initials="A." surname="Panitz"
                    fullname="A. Panitz">
              <organization/>
            </author>
            <date year="1999" month="June"/>
          </front>
          <seriesInfo name="BCP" value="32"/>
          <seriesInfo name="RFC" value="2606"/>
          <seriesInfo name="DOI" value="10.17487/RFC2606"/>
        </reference>

        <reference anchor="RFC8594"
                   target="https://www.rfc-editor.org/info/rfc8594">
          <front>
            <title>The Sunset HTTP Header Field</title>
            <author initials="E." surname="Wilde"
                    fullname="E. Wilde">
              <organization/>
            </author>
            <date year="2019" month="May"/>
          </front>
          <seriesInfo name="RFC" value="8594"/>
          <seriesInfo name="DOI" value="10.17487/RFC8594"/>
        </reference>

        <reference anchor="WebSub"
                   target="https://www.w3.org/TR/websub/">
          <front>
            <title>WebSub</title>
            <author initials="J." surname="Genestoux"
                    fullname="J. Genestoux" role="editor">
              <organization/>
            </author>
            <author initials="A." surname="Parecki"
                    fullname="A. Parecki" role="editor">
              <organization/>
            </author>
            <date year="2018" month="January"/>
          </front>
          <refcontent>W3C Recommendation</refcontent>
        </reference>
      </references>
    </references>

    <!-- =============================================================== -->
    <section anchor="changes-from-00">
      <name>Changes from -00</name>
      <t>
        This section will be removed prior to publication.
      </t>

      <t>Structural and editorial changes:</t>
      <ul spacing="normal">
        <li>
          Renamed the combined "Terminology" section to "Conventions
          and Terminology" and incorporated the full BCP 14
          boilerplate citing both <xref target="RFC2119"/> and
          <xref target="RFC8174"/>.
        </li>
        <li>
          Expanded the terminology list to include Event, Event
          Producer, Event Consumer, Intermediary, Sender-Observed
          Outcome, Accepted, Transient Failure, Terminal Failure,
          and Retry, in addition to the three terms defined in -00.
        </li>
        <li>
          Added a figure illustrating the
          Producer/Consumer/Intermediary roles and recursive
          application of the model at each hop.
        </li>
        <li>
          Reworded Non-Goals and Goals as bulleted lists for
          clarity.
        </li>
        <li>
          Split References into Normative and Informative
          subsections per <xref target="RFC7322"/> structure.
        </li>
        <li>
          Corrected the expiry date inconsistency present in -00
          ("Expires: 28 June 2026" in the header versus "4 June
          2026" in the Status of This Memo section).
        </li>
        <li>
          Editorial: tightened the Introduction and Problem
          Statement for consistency of terminology and
          cross-references; aligned capitalization of defined
          terms throughout.
        </li>
      </ul>

      <t>Model and normative content:</t>
      <ul spacing="normal">
        <li>
          Promoted "Accepted", "Transient Failure", and "Terminal
          Failure" from informal names to normatively defined
          Sender-Observed Outcomes with explicit retry semantics
          (<xref target="outcomes"/>).
        </li>
        <li>
          Defined a Deduplication Window with a recommended minimum
          of 24 hours, and constrained Producer reuse of Idempotency
          Identifiers accordingly (<xref target="dedup"/>).
        </li>
        <li>
          Added a normative HTTP Binding section
          (<xref target="http-binding"/>) covering method semantics,
          status-code mapping to Sender-Observed Outcomes, treatment
          of network-level failures, use of the Idempotency-Key
          header field aligned with
          <xref target="I-D.ietf-httpapi-idempotency-key"/>, use of
          the Retry-After header field per <xref target="RFC9110"/>,
          a recommended retry algorithm with full-jitter exponential
          backoff, and explicit Intermediary behavior across hops.
        </li>
        <li>
          Replaced the single status-code mapping list with three
          tables (<xref target="tab-transient"/>,
          <xref target="tab-terminal"/>, and the prose handling of
          2xx, 3xx, and 1xx) covering 408, 421, 425, 429, 500, 502,
          503, 504, 511 as Transient and 400, 401, 403, 404, 405,
          410, 413, 414, 415, 422, 451 as Terminal, with per-code
          rationale.  MUST/SHOULD distribution adjusted to reflect
          operational reality (for example, 401 demoted from MUST
          Terminal to SHOULD Terminal with explicit rotating-credential
          allowance; 408 and 504 demoted from MUST Transient to
          SHOULD Transient with explicit ambiguity warning).
        </li>
        <li>
          Defined the Producer-Consumer Context as the tuple
          (Producer identity, Consumer endpoint URI) to make the
          scope of Idempotency-Key precise
          (<xref target="http-idempotency"/>).
        </li>
        <li>
          Added handling guidance for the Sunset header field
          <xref target="RFC8594"/> and for 308 vs 307 redirects.
        </li>
        <li>
          Added four worked HTTP examples
          (<xref target="http-examples"/>): Accepted, Transient
          Failure with Retry-After followed by retry, Terminal
          Failure with Problem Details, and a network-level failure.
        </li>
        <li>
          Added a Relationship to Existing Work section
          (<xref target="related-work"/>) positioning the profile
          against CloudEvents,
          <xref target="I-D.ietf-httpapi-idempotency-key"/>,
          <xref target="RFC9110"/>, WebSub, and vendor webhook
          conventions.
        </li>
      </ul>

      <t>Security:</t>
      <ul spacing="normal">
        <li>
          Expanded the Security Considerations section per
          <xref target="RFC3552"/> to include a threat model and
          guidance on transport security, producer authentication,
          integrity protection, replay mitigation, confidentiality,
          endpoint authorization, and denial-of-service
          considerations.
        </li>
        <li>
          Reconciled the optional-deduplication position in
          <xref target="dedup"/> with the replay-mitigation
          requirement in <xref target="sec-replay"/>: Consumers
          that do not perform deduplication
          <bcp14>MUST</bcp14> implement an alternative
          freshness mechanism (signed timestamp or nonce).
        </li>
      </ul>

      <t>References added:</t>
      <ul spacing="normal">
        <li>
          Normative: <xref target="RFC8174"/>,
          <xref target="RFC9110"/>.
        </li>
        <li>
          Informative: <xref target="RFC2606"/>,
          <xref target="RFC3552"/>, <xref target="RFC7322"/>,
          <xref target="RFC8446"/>, <xref target="RFC8594"/>,
          <xref target="RFC9113"/>, <xref target="RFC9114"/>,
          <xref target="RFC9421"/>, <xref target="RFC9457"/>,
          <xref target="RFC9562"/>,
          <xref target="I-D.ietf-httpapi-idempotency-key"/>,
          CloudEvents, WebSub.
        </li>
      </ul>

      <t>Internal-consistency and second-pass review changes:</t>
      <ul spacing="normal">
        <li>
          Promoted the Idempotency-Key header field requirement
          in the HTTP binding from SHOULD to MUST
          (<xref target="http-idempotency"/>); this removes the
          MUST-on-SHOULD construction in the 408, 504, and
          network-level-failure handling and makes the
          Producer-Consumer Context definition well-formed in
          all cases.
        </li>
        <li>
          Promoted Producer authentication in the HTTP binding
          from SHOULD to MUST (<xref target="sec-auth"/>) so the
          Producer-Consumer Context is always defined and the
          replay-mitigation requirement is satisfiable.
        </li>
        <li>
          Constrained the buffered-Intermediary
          store-and-forward acceptance rule
          (<xref target="http-intermediary"/>): an Intermediary
          may return Accepted upstream prior to downstream
          delivery only when its store-and-forward behavior is
          documented in an operator-accessible service
          description and the upstream Producer has acknowledged
          that description out of band.
        </li>
        <li>
          Tightened the "prior agreement" escape hatch in
          <xref target="http-status-mapping"/>: alternative
          interpretations must be documented in writing,
          operator-discoverable, and must not weaken the
          security properties in <xref target="security"/>.
        </li>
        <li>
          Corrected the CloudEvents alignment claim
          (<xref target="related-work"/>): the CloudEvents "id"
          attribute may be reused as the Idempotency Identifier
          only when stability across retries and
          Producer-Consumer Context containment are both
          guaranteed; otherwise a separate Idempotency-Key value
          is required.
        </li>
        <li>
          Added <xref target="http-versions"/> covering HTTP/2
          and HTTP/3 stream-reset handling, TLS 1.3 0-RTT replay
          considerations, and the prohibition on using HTTP/2 or
          HTTP/3 server push for Delivery Attempts.
        </li>
        <li>
          Added a TLS 1.3 0-RTT paragraph to
          <xref target="sec-replay"/> requiring the alternative
          freshness mechanism when Delivery Attempts traverse
          0-RTT data.
        </li>
        <li>
          Consolidated retry-bound and backoff guidance in
          <xref target="sec-dos"/> to cross-reference
          <xref target="http-backoff"/> rather than duplicate it,
          and added a normative SHOULD for disabling endpoints
          after repeated Terminal Failure outcomes.
        </li>
        <li>
          Removed Content-Length values from the worked HTTP
          examples (<xref target="http-examples"/>) so the
          examples are textually self-consistent without
          maintaining a redundant length field.
        </li>
        <li>
          Added a non-normative
          <xref target="other-bindings"/> noting that bindings
          to transports other than HTTP are out of scope but
          intended to be supported by the abstract model.
        </li>
        <li>
          Added <xref target="impl-survey"/> documenting the
          empirical basis for the recommended default values
          (deduplication window, backoff parameters) and for the
          status-code mappings.
        </li>
      </ul>
    </section>

    <section anchor="impl-survey">
      <name>Implementation Survey</name>
      <t>
        This appendix is non-normative.  It documents the
        empirical basis for the default values recommended in
        <xref target="dedup"/> and <xref target="http-backoff"/>
        and for the status-code mappings in
        <xref target="http-status-mapping"/>.  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 <bcp14>SHOULD</bcp14> consult current
        vendor documentation for the specific systems they
        integrate with.
      </t>

      <section anchor="survey-systems">
        <name>Surveyed Systems</name>
        <t>
          The following event and webhook platforms publish
          delivery-semantics documentation and were considered
          in framing this document:
        </t>
        <ul spacing="normal">
          <li>Stripe Webhooks</li>
          <li>GitHub Webhooks</li>
          <li>Amazon Web Services EventBridge and Amazon SNS
              HTTP/HTTPS subscriptions</li>
          <li>Microsoft Azure Event Grid</li>
          <li>Google Cloud Eventarc</li>
          <li>Twilio Event Streams and Webhooks</li>
          <li>Shopify Webhooks</li>
          <li>Slack Events API</li>
          <li>PayPal Webhooks</li>
          <li>The Svix open-source webhook service</li>
        </ul>
      </section>

      <section anchor="survey-retry">
        <name>Retry Strategies</name>
        <t>
          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.
        </t>
        <t>
          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 <xref target="http-backoff"/> (base of
          1 second, cap between 60 and 600 seconds) fall within
          this central range.
        </t>
      </section>

      <section anchor="survey-idempotency">
        <name>Idempotency and Deduplication</name>
        <t>
          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.
        </t>
        <t>
          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
          <bcp14>RECOMMENDED</bcp14> minimum of 24 hours in
          <xref target="dedup"/> reflects this observation.
        </t>
      </section>

      <section anchor="survey-status">
        <name>Status Code Treatment</name>
        <t>
          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
          <xref target="http-status-mapping"/>.  Specific
          divergences observed include:
        </t>
        <ul spacing="normal">
          <li>
            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.
          </li>
          <li>
            Treatment of 429 Too Many Requests is consistently
            retriable, with most systems honoring the
            Retry-After header field when present.
          </li>
          <li>
            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.
          </li>
        </ul>
      </section>

      <section anchor="survey-conclusions">
        <name>Synthesis</name>
        <t>
          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 <xref target="goals"/>.
        </t>
      </section>
    </section>

    <section anchor="acknowledgements" numbered="false">
      <name>Acknowledgements</name>
      <t>
        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.
      </t>
    </section>

  </back>
</rfc>
