<?xml version="1.0" encoding="utf-8"?>
<?xml-model href="rfc7991bis.rnc"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     docName="draft-hawkins-x402-dns-discovery-01"
     category="info"
     ipr="trust200902"
     submissionType="IETF"
     tocInclude="true"
     sortRefs="true"
     symRefs="true"
     version="3">

  <front>
    <title abbrev="x402 DNS Discovery">Discovering x402 Payment
    Capability via DNS and a Well-Known URI</title>
    <seriesInfo name="Internet-Draft"
                value="draft-hawkins-x402-dns-discovery-01"/>
    <author fullname="Walter D. Hawkins" initials="Walter D."
            surname="Hawkins">
      <organization>Independent</organization>
      <address>
        <email>wdhawkins46@gmail.com</email>
      </address>
    </author>
    <date year="2026" month="August"/>
    <area>Applications</area>
    <keyword>x402</keyword>
    <keyword>DNS</keyword>
    <keyword>well-known</keyword>
    <keyword>payments</keyword>
    <keyword>discovery</keyword>

    <abstract>
      <t>x402 is an application-level protocol for internet-native
      payments built on the HTTP 402 (Payment Required) status code.
      This document defines how a domain publishes its x402 payment
      capability out-of-band, so that clients, autonomous agents, and
      indexers can discover it without prior configuration or a central
      directory. It specifies a JSON capability manifest served at the
      well-known URI "/.well-known/x402" and an optional DNS TXT record
      at the underscored node name "_x402" that points to the manifest.
      A consumer resolves a bare domain name to verified x402
      capability with at most one DNS query and one HTTPS GET.</t>
    </abstract>

    <note removeInRFC="true">
      <name>About This Document</name>
      <t>This document is a successor to the expired individual
      submission draft-jeftovic-x402-dns-discovery-00, whose author is
      credited in the Acknowledgments; an offer of co-authorship
      remains open. Discussion of this document takes place in the
      x402 Foundation community
      (https://github.com/x402-foundation/x402), where a corresponding
      extension specification is under review.</t>
    </note>
  </front>

  <middle>
    <section anchor="intro">
      <name>Introduction</name>
      <t>The x402 protocol <xref target="X402"/> makes payment terms
      self-describing at the moment a client encounters an HTTP 402
      response: the response body enumerates acceptable payment
      schemes, networks, assets, and amounts. What x402 does not
      define is how a client that has never contacted a host learns
      that the host participates in x402 at all, in what role, and
      with what capabilities. In practice this gap has been filled by
      hand-curated lists and directory sites, which rot, do not scale,
      and centralize what is naturally edge-published data.</t>
      <t>Electronic mail solved the same problem with DNS records
      (MX, SPF <xref target="RFC7208"/>, DMARC
      <xref target="RFC7489"/>), and most directly with MTA-STS
      <xref target="RFC8461"/>, in which an unauthenticated DNS TXT
      record points to an authenticated HTTPS policy document. This
      document applies that pattern to x402:</t>
      <ul>
        <li>A JSON capability manifest served over HTTPS at the
        well-known URI <xref target="RFC8615"/> path
        "/.well-known/x402" is the authoritative, machine-readable
        record of a host's x402 capability
        (<xref target="manifest"/>).</li>
        <li>An optional DNS TXT record at the underscored node name
        <xref target="RFC8552"/> "_x402" is a lightweight pointer that
        lets a consumer discover x402 capability from DNS alone,
        before making any HTTP request (<xref target="txt"/>).</li>
      </ul>
      <t>A consumer resolves a bare domain name to verified capability
      with at most one DNS query and one HTTPS GET
      (<xref target="resolution"/>). Curated directories become
      optional caches, regenerable by crawling, rather than
      load-bearing infrastructure.</t>
    </section>

    <section anchor="conventions">
      <name>Conventions and Definitions</name>
      <t>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 <xref target="RFC2119"/>
      <xref target="RFC8174"/> when, and only when, they appear in all
      capitals, as shown here.</t>
      <dl>
        <dt>Facilitator:</dt>
        <dd>A service that verifies and settles x402 payments on
        behalf of resource servers, conventionally exposing
        "supported", "verify", and "settle" endpoints.</dd>
        <dt>Resource server:</dt>
        <dd>An HTTP server that gates resources behind x402
        payments.</dd>
        <dt>Manifest:</dt>
        <dd>The JSON document defined in <xref target="manifest"/>.</dd>
        <dt>Consumer:</dt>
        <dd>Any client, agent, crawler, or indexer that resolves x402
        capability using this mechanism.</dd>
      </dl>
    </section>

    <section anchor="manifest">
      <name>The x402 Well-Known URI</name>
      <t>A host participating in x402 SHOULD serve a JSON
      <xref target="RFC8259"/> manifest at:</t>
      <sourcecode type="text">
https://&lt;host&gt;/.well-known/x402
</sourcecode>
      <t>The manifest MUST be served over HTTPS with media type
      "application/json". Cross-origin GET SHOULD be permitted; the
      manifest is public data. Hosts SHOULD serve the manifest with
      HTTP caching headers.</t>

      <section anchor="manifest-example">
        <name>Example</name>
        <sourcecode type="json">
{
  "x402Version": 2,
  "kind": "facilitator",
  "name": "Example Facilitator",
  "description": "One-line human description.",
  "facilitator": {
    "baseUrl": "https://pay.example.com",
    "endpoints": {
      "supported": "/supported",
      "verify": "/verify",
      "settle": "/settle"
    },
    "kinds": [
      { "x402Version": 2, "scheme": "exact",
        "network": "eip155:114" }
    ],
    "assets": [
      {
        "network": "eip155:114",
        "address": "0x1F930B6A9F68c91aB23db07a9c4A5Dc166eF8011",
        "symbol": "EXUSD",
        "decimals": 6,
        "standard": "EIP-3009"
      }
    ]
  },
  "resources": [
    {
      "url": "https://pay.example.com/demo/card",
      "method": "POST",
      "description": "x402-paywalled demo resource"
    }
  ],
  "attestation": { "type": "none" },
  "docs": "https://pay.example.com/",
  "contact": "ops@example.com",
  "updated": "2026-08-04T00:00:00Z"
}
</sourcecode>
      </section>

      <section anchor="manifest-fields">
        <name>Field Semantics</name>
        <dl>
          <dt>x402Version (REQUIRED):</dt>
          <dd>Highest x402 protocol version the host speaks.</dd>
          <dt>kind (REQUIRED):</dt>
          <dd>One of "facilitator", "resource-server", or "both".</dd>
          <dt>name, description (RECOMMENDED):</dt>
          <dd>Human-readable identification.</dd>
          <dt>facilitator (REQUIRED when kind includes
          facilitator):</dt>
          <dd>Capability block for the facilitator role.</dd>
          <dt>facilitator.baseUrl (REQUIRED):</dt>
          <dd>HTTPS base URL of the facilitator API. It MUST be on
          the same domain as, or a subdomain of, the host serving the
          manifest, and consumers MUST reject manifests that violate
          this. Without this rule a host can name someone else's
          facilitator as its own and turn every conforming crawler
          into a request amplifier aimed at a third party.</dd>
          <dt>facilitator.endpoints (REQUIRED):</dt>
          <dd>Relative paths for the supported/verify/settle
          endpoints. Deployments differ; consumers do not guess.</dd>
          <dt>facilitator.kinds (REQUIRED):</dt>
          <dd>A mirror of the live "supported" endpoint. Divergence
          between the manifest and the live endpoint is a
          misconfiguration; consumers MUST prefer the live endpoint
          (<xref target="resolution"/>).</dd>
          <dt>facilitator.assets (RECOMMENDED):</dt>
          <dd>Settleable assets per network, with the token standard
          each scheme relies on.</dd>
          <dt>resources (OPTIONAL):</dt>
          <dd>x402-gated resources on this host. Each "url" MUST be
          HTTPS and on the manifest's own domain or a subdomain.
          Consumers MUST NOT dereference entries that are not, and
          SHOULD treat their presence as an abuse signal. Because
          this document invites indexers to fetch these URLs, an
          unconstrained field would constitute server-side request
          forgery by specification: a host listing an internal or
          link-local address would have every conforming crawler
          dereference it from inside the crawler's own network.</dd>
          <dt>attestation (OPTIONAL):</dt>
          <dd>Execution-integrity claims, e.g. {"type":"none"} or
          {"type":"tee","scheme":"...","verifier":"&lt;url&gt;"}. See
          <xref target="security"/>.</dd>
          <dt>updated (RECOMMENDED):</dt>
          <dd>Timestamp <xref target="RFC3339"/> of the last manifest
          change, used for cache decisions alongside HTTP caching
          headers.</dd>
        </dl>
        <t>Unknown fields MUST be ignored, for forward
        compatibility.</t>
      </section>
    </section>

    <section anchor="txt">
      <name>The _x402 DNS TXT Record</name>
      <t>A domain MAY additionally publish a TXT record
      <xref target="RFC1035"/> at the underscored node name
      "_x402" <xref target="RFC8552"/>:</t>
      <sourcecode type="dns-rr">
_x402.example.com. IN TXT ( "v=x402-1; "
  "wk=https://pay.example.com/.well-known/x402; "
  "k=facilitator; net=eip155:114; scheme=exact" )
</sourcecode>
      <t>The RDATA is a single character-string sequence interpreted
      as semicolon-separated key=value pairs, order-insensitive:</t>
      <dl>
        <dt>v (REQUIRED):</dt>
        <dd>The record format version. This document defines
        "x402-1".</dd>
        <dt>wk (REQUIRED):</dt>
        <dd>Absolute HTTPS URL of the manifest. It MUST be on the
        publishing domain or a subdomain of it (see
        <xref target="security"/>).</dd>
        <dt>k (RECOMMENDED):</dt>
        <dd>"facilitator", "resource-server", or "both" -- a coarse
        filter so crawlers can skip fetches.</dd>
        <dt>net (OPTIONAL):</dt>
        <dd>Comma-separated network identifiers (coarse filter
        only).</dd>
        <dt>scheme (OPTIONAL):</dt>
        <dd>Comma-separated scheme names (coarse filter only).</dd>
      </dl>
      <t>A domain MUST publish at most one record with "v=x402-1" at
      a given owner name. Consumers that find more than one MUST
      treat the name as unresolvable rather than choosing between
      them: "first record wins" is a race that anyone able to add a
      single TXT record can win by ordering -- a shared DNS control
      panel, a delegated subdomain, a partial compromise. SPF
      <xref target="RFC7208"/> and DMARC <xref target="RFC7489"/>
      both make duplicate records a hard error for precisely this
      reason.</t>
      <t>The TXT record is a pointer, not an authority: all
      capability data comes from the manifest, which is retrieved
      over HTTPS. This split -- unauthenticated DNS pointer to
      authenticated HTTPS policy -- is the MTA-STS
      <xref target="RFC8461"/> pattern, and it keeps the mechanism
      useful even where DNSSEC <xref target="RFC4033"/> is absent.</t>
      <t>Hosts without control of their DNS (for example, hosts on
      platform-assigned subdomains) simply publish the manifest
      alone; resolution step 2 below still finds them.</t>
    </section>

    <section anchor="resolution">
      <name>Resolution Algorithm</name>
      <t>Given a domain name D, a consumer resolves x402 capability
      as follows:</t>
      <ol>
        <li>Query TXT for "_x402.D". If a record with "v=x402-1"
        exists, fetch the manifest from its "wk" URL, rejecting
        non-HTTPS or out-of-domain URLs. Consumers MUST re-apply the
        in-domain constraint to every redirect hop and report the
        final URL as the manifest source. Checking only the requested
        URL validates a location the bytes need not have come from:
        an in-domain "wk" URL that redirects off-domain would
        otherwise pass, defeating the one control the
        (unauthenticated) DNS layer has. Redirect chains SHOULD be
        bounded.</li>
        <li>Otherwise, attempt GET on
        "https://D/.well-known/x402".</li>
        <li>Validate the manifest shape; ignore unknown fields.</li>
        <li>Before using a facilitator, fetch the live "supported"
        endpoint given by baseUrl and endpoints.supported, and treat
        the live response as authoritative over the manifest's
        "kinds" array.</li>
      </ol>
      <t>Steps 1-2 answer "does this domain speak x402, and in what
      role" with at most one DNS query and one HTTP GET. Indexers
      crawl the same way and SHOULD periodically re-verify
      records.</t>

      <section anchor="fetch-bounds">
        <name>Fetch Bounds</name>
        <t>Consumers MUST bound the manifest fetch with a request
        timeout and a maximum response size. An unbounded read is a
        denial of service handed to anyone who can publish a TXT
        record: a hostile host serves an arbitrarily large body, or
        trickles bytes indefinitely, and the crawler exhausts memory
        or hangs. Size limits MUST be applied to the bytes actually
        received, not to the Content-Length header, which is the
        server's claim rather than a measurement. (One deployed
        implementation uses a 256 KiB size cap, a 10-second deadline,
        and at most 3 redirect hops.)</t>
      </section>

      <section anchor="private-dest">
        <name>Refusing Private Destinations</name>
        <t>Before every fetch this document invites -- the manifest,
        each redirect hop, resources[] probes, and the live
        "supported" cross-check -- a consumer MUST refuse a URL whose
        host is, or resolves to, a loopback, link-local, or
        private-range address. The HTTPS and in-domain rules do not
        cover this case: the publisher controls their own DNS, so an
        in-domain hostname can resolve to a link-local metadata
        address or an address inside the crawler's network, and
        DNS-based certificate issuance grants valid certificates to
        names that never point anywhere public. The check MUST be
        re-applied on every redirect hop; a public first hop
        redirecting to an internal name is the classic bypass.
        Resolution-time checks remain subject to DNS rebinding
        between check and connect; consumers needing a stronger
        guarantee SHOULD pin the resolved address for the connection.
        Deployments intentionally operating on private networks MAY
        relax this rule, explicitly.</t>
      </section>
    </section>

    <section anchor="security">
      <name>Security Considerations</name>
      <t>Discovery is not endorsement. A manifest proves that a host
      claims a capability; it transfers no trust. Clients MUST
      validate settlement the way the x402 protocol already requires,
      and SHOULD apply their own reputation or allowlist policy on
      top of discovery.</t>
      <t>DNS spoofing: the TXT record is unauthenticated without
      DNSSEC. That is why it may only point into the same domain, and
      why the manifest -- served under the domain's TLS certificate --
      is the authority. An attacker who can forge the TXT record but
      not the domain's HTTPS gains nothing.</t>
      <t>The same-origin constraint on "wk" prevents a domain from
      claiming another operator's facilitator as its own, and
      prevents the record from being used as an open redirect for
      crawler traffic. This holds only if consumers enforce it on
      every redirect hop and on facilitator.baseUrl, not on the
      requested URL alone.</t>
      <t>Servers MUST NOT derive manifest URLs from
      request-controlled input. A manifest endpoint that builds its
      own baseUrl or resource URLs from the Host or X-Forwarded-Host
      request headers lets any caller make the document -- served
      under the operator's own TLS certificate -- advertise an
      attacker's host, and a cacheable response without a matching
      Vary header can then be replayed to other consumers. The public
      origin MUST be pinned in configuration. This is the same attack
      the "wk" rule addresses, arriving on the side this document
      calls authoritative, and it is easy to introduce precisely
      because deriving the origin from the request looks like good
      hygiene.</t>
      <t>DNSSEC upgrades the TXT record from a hint to an assertion.
      Unsigned, the record is a convenience that the HTTPS manifest
      must backstop. Signed, a validating resolver can prove the
      record was not tampered with. Operators SHOULD sign zones
      carrying "_x402" records and SHOULD monitor RRSIG expiry: an
      expired signature fails validation exactly like a forged one,
      so the record -- and the discovery path -- disappears on a
      timer.</t>
      <t>Manifest/live divergence: consumers MUST prefer live
      "supported" data over the manifest's mirror of it; indexers
      SHOULD flag divergent hosts.</t>
      <t>Attestation claims in the manifest are claims like
      everything else: an execution-integrity attestation is only
      meaningful if the verifier URL lets the client independently
      check an attestation token chain against a published,
      reproducible build. Absent such verification, consumers treat
      the attestation as absent.</t>
      <t>Crawler load: manifests are static JSON; hosts SHOULD serve
      them with cache headers and rate-limit them as any public
      endpoint.</t>
    </section>

    <section anchor="iana">
      <name>IANA Considerations</name>
      <section anchor="iana-wk">
        <name>Well-Known URI Registration</name>
        <t>IANA is requested to register the following entry in the
        "Well-Known URIs" registry defined by
        <xref target="RFC8615"/>:</t>
        <dl>
          <dt>URI Suffix:</dt><dd>x402</dd>
          <dt>Change Controller:</dt><dd>IETF</dd>
          <dt>Reference:</dt><dd>This document</dd>
          <dt>Status:</dt><dd>permanent</dd>
        </dl>
      </section>
      <section anchor="iana-underscore">
        <name>Underscored Node Name Registration</name>
        <t>IANA is requested to register the following entry in the
        "Underscored and Globally Scoped DNS Node Names" registry
        defined by <xref target="RFC8552"/>:</t>
        <dl>
          <dt>RR Type:</dt><dd>TXT</dd>
          <dt>_NODE NAME:</dt><dd>_x402</dd>
          <dt>Reference:</dt><dd>This document</dd>
        </dl>
      </section>
    </section>

    <section anchor="impl-status" removeInRFC="true">
      <name>Implementation Status</name>
      <t>This section records the status of known implementations per
      <xref target="RFC7942"/>.</t>
      <ul>
        <li>A zero-dependency resolver implementing the full
        algorithm of <xref target="resolution"/>, including redirect
        re-validation, fetch bounds, and private-destination refusal,
        is deployed and exercises live "_x402" records published on
        the author's production domains, resolving end-to-end from
        bare domain name to live capability endpoint.</li>
        <li>A corresponding extension specification is under review
        in the x402 Foundation repository
        (x402-foundation/x402, pull request 2979), with a live
        manifest served by a public facilitator deployment.</li>
      </ul>
    </section>

    <section anchor="prior">
      <name>Relationship to Prior Proposals</name>
      <t>DNS-based and well-known-URI-based discovery for x402 has
      been proposed independently several times in the x402
      community, most completely in
      <xref target="JEFTOVIC"/>, which used the same "_x402" TXT
      label and substantially the same resolution approach. That
      document expired without revision in May 2026. This document is
      offered as a successor that consolidates those proposals and
      adds the manifest schema, duplicate-record rule, redirect and
      private-destination constraints, and IANA registrations.
      Co-authorship remains open to the authors of the prior
      proposals.</t>
    </section>
  </middle>

  <back>
    <references>
      <name>References</name>
      <references anchor="normative">
        <name>Normative References</name>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.1035.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8259.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8552.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8615.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3339.xml"/>
      </references>
      <references anchor="informative">
        <name>Informative References</name>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4033.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7208.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7489.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7942.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8461.xml"/>
        <reference anchor="X402" target="https://github.com/x402-foundation/x402">
          <front>
            <title>x402: An Open Standard for Internet-Native
            Payments</title>
            <author><organization>x402 Foundation</organization></author>
            <date year="2026"/>
          </front>
        </reference>
        <reference anchor="JEFTOVIC" target="https://datatracker.ietf.org/doc/draft-jeftovic-x402-dns-discovery/">
          <front>
            <title>Discovering x402 Resources via DNS TXT
            Records</title>
            <author initials="M. E." surname="Jeftovic"
                    fullname="Mark E. Jeftovic"/>
            <date year="2025" month="November"/>
          </front>
          <refcontent>Work in Progress, expired
          Internet-Draft</refcontent>
        </reference>
      </references>
    </references>

    <section anchor="ack" numbered="false">
      <name>Acknowledgments</name>
      <t>Mark E. Jeftovic proposed "_x402" TXT-record discovery for
      x402 first, in <xref target="JEFTOVIC"/> and in x402 community
      discussion; this document deliberately builds on that work, and
      the offer to fold this text into a revision of his draft -- or
      to add him as co-author here -- stands. The authors of the other
      independent discovery proposals in the x402 community
      (repository issues 1348, 2582, and 2831) reached similar
      designs and are acknowledged likewise. Reviewers on x402
      Foundation pull request 2979 materially improved the security
      considerations, in particular the redirect re-validation and
      duplicate-record rules.</t>
    </section>
  </back>
</rfc>
