<?xml version="1.0" encoding="utf-8"?>
<rfc version="3" ipr="trust200902" docName="draft-koenig-idmandat-credential-00" category="info" xml:lang="en" sortRefs="true" symRefs="true" tocInclude="true">
  <front>
    <title abbrev="ID MANDAT Credential">A Machine-Readable Credential for the Agents of a Company (ID MANDAT)</title>
    <seriesInfo name="Internet-Draft" value="draft-koenig-idmandat-credential-00"/>
    <author fullname="Manja König" initials="M." surname="König">
      <organization>ID MANDAT</organization>
      <address>
        <postal>
          <city>Osnabrück</city>
          <country>DE</country>
        </postal>
        <email>kontakt@idmandat.com</email>
        <uri>https://idmandat.com</uri>
      </address>
    </author>
    <date year="2026" month="October" day="16"/>
    <keyword>AI agents</keyword>
    <keyword>identity</keyword>
    <keyword>mandate</keyword>
    <keyword>well-known URI</keyword>
    <abstract>
      <t>Automated software agents increasingly act for companies: they ask for quotes, book appointments and place orders. A recipient can verify, for example with Web Bot Auth, that a request was signed by the holder of a key. That does not tell the recipient which company stands behind the agent or what the agent is allowed to do on its behalf. This document describes a small credential file that a company publishes on its own domain under /.well-known/idmandat.json, a DNS TXT record that links the file to the domain, and the answer format of a public registry that checks both and reports the result in a digitally signed response. The credential states, by declaration of the company, which agents act for it and what each agent may and may not do. It does not make claims about creditworthiness, trustworthiness or quality.</t>
    </abstract>
  </front>
  <middle>
    <section anchor="intro">
      <name>Introduction</name>
      <t>A website visitor can look at an imprint and judge whether a company looks serious. An automated agent cannot. Work on authenticating automated traffic, such as <xref target="WEBBOTAUTH"/>, lets a recipient check that a request was signed by the holder of a key and, through the Signature-Agent header field, where that key can be found. That work explicitly does not say who operates the agent or what it is authorised to do.</t>
      <t>This document specifies a complementary, voluntary and declarative layer:</t>
      <ul>
        <li>a credential file under the company's own domain, naming the company, its agents, and for each agent what it may and may not do (<xref target="credential"/>);</li>
        <li>a DNS TXT record that ties the file to the domain (<xref target="dns"/>);</li>
        <li>the lookup answer of a registry that checks both, including the possibility of revoking an entry (<xref target="lookup"/>).</li>
      </ul>
      <t>The credential belongs to the company, not to the registry. It stays valid and readable without any registry.</t>
      <section anchor="reqs">
        <name>Requirements Language</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>
      </section>
      <section anchor="status">
        <name>Status of this Document</name>
        <t>This is an individual submission describing a deployed beta (version 0.3). It is not the product of an IETF working group. The lookup interface described in <xref target="lookup"/> is operated at https://idmandat.com and is described here so that others can implement clients and compatible registries.</t>
      </section>
    </section>

    <section anchor="credential">
      <name>The Credential File</name>
      <t>A company that wants to declare its agents publishes a JSON document <xref target="RFC8259"/> at:</t>
      <sourcecode>
https://example.com/.well-known/idmandat.json
</sourcecode>
      <t>The document is served with media type application/json over HTTPS. Its top-level members are:</t>
      <dl>
        <dt>idmandat</dt><dd>Version of this specification, as a string (for example "0.1").</dd>
        <dt>domain</dt><dd>The domain that publishes the file. It MUST equal the host from which the file was fetched.</dd>
        <dt>organization</dt><dd>An object with at least "name" (the legal name of the company as in its imprint or commercial register) and "country" (ISO 3166-1 alpha-2). It MAY contain "legalForm", "address", "industry", "register" (court and number), "vatId" and "imprint" (a URL).</dd>
        <dt>agents</dt><dd>An array of agent objects (see below).</dd>
        <dt>verification</dt><dd>An object naming the registry and the DNS name of the proof record.</dd>
        <dt>updated</dt><dd>Date of the last change, as an ISO 8601 date.</dd>
      </dl>
      <t>Each agent object has the following members:</t>
      <dl>
        <dt>id, name, role</dt><dd>Identifier, display name and short description of the task of the agent.</dd>
        <dt>isHuman</dt><dd>MUST be false. An agent declared under this document does not present itself as a human being.</dd>
        <dt>endpoint, protocols</dt><dd>OPTIONAL. Where the agent can be reached and which protocols it speaks (for example "a2a", "mcp").</dd>
        <dt>mandate</dt><dd>An object with "may" and "mayNot", arrays of capability names, and OPTIONAL "bindingOnlyAfter", a short text saying from when an action becomes binding (for example after confirmation by a human). A mandate SHOULD state what the agent may not do as well as what it may do.</dd>
        <dt>humanContact</dt><dd>OPTIONAL. Where a human can be reached.</dd>
        <dt>signatureAgent</dt><dd>OPTIONAL. One https URL, or an array of at most three, naming the key directory with which the agent signs its requests (the value that appears in the Signature-Agent header field of <xref target="WEBBOTAUTH"/>). A recipient can use it to find the company from the key (<xref target="lookup"/>).</dd>
      </dl>
      <t>For "may" and "mayNot" the following capability names are RECOMMENDED so that different implementations read them the same way: answer_product_questions, answer_service_questions, explain_prices, check_availability, prepare_appointment, reserve_appointment, book_appointment, create_quote, take_order, qualify_lead, forward_request, conclude_contract, trigger_payment, share_personal_data, give_legal_advice, give_medical_advice. Other names are allowed.</t>
      <t>The following is a non-normative example.</t>
      <sourcecode type="json"><![CDATA[
{
  "idmandat": "0.1",
  "domain": "example.com",
  "organization": {
    "name": "Example GmbH",
    "country": "DE",
    "vatId": "DE123456789",
    "imprint": "https://example.com/impressum"
  },
  "agents": [
    {
      "id": "captain",
      "name": "Captain",
      "role": "Appointments and product questions",
      "isHuman": false,
      "protocols": ["a2a", "mcp"],
      "mandate": {
        "may": ["answer_product_questions", "reserve_appointment"],
        "mayNot": ["conclude_contract", "trigger_payment"],
        "bindingOnlyAfter": "confirmation by a human"
      },
      "signatureAgent": "https://bot.example.com"
    }
  ],
  "verification": {
    "registry": "https://idmandat.com",
    "dns": "_idmandat.example.com"
  },
  "updated": "2026-10-16"
}
]]></sourcecode>
    </section>

    <section anchor="dns">
      <name>The DNS Proof Record</name>
      <t>The file alone shows only that whoever controls the web server published it. To tie it to the domain holder as well, the company publishes a TXT record at the name "_idmandat" below the domain:</t>
      <sourcecode>
_idmandat.example.com.  IN TXT  "v=idmandat1; file=/.well-known/idmandat.json"
</sourcecode>
      <t>A checker accepts an entry at the level "registered" only if the domain in the file, the DNS record and the fetched file agree.</t>
    </section>

    <section anchor="levels">
      <name>Check Levels</name>
      <t>A registry reports how far it has checked an entry. The levels used by the registry described here are:</t>
      <dl>
        <dt>listed_unverified</dt><dd>The company listed itself; nothing was checked.</dd>
        <dt>registered</dt><dd>File and DNS proof record agree with the domain.</dd>
        <dt>verified</dt><dd>In addition, name and address match the imprint of the domain, and the commercial register entry (or, for companies without one, a valid VAT identification number) exists and matches. Checks are repeated regularly.</dd>
      </dl>
      <t>Where no level applies the answer says so explicitly. The text "no entry" MUST NOT be read as a sign of wrongdoing.</t>
    </section>

    <section anchor="lookup">
      <name>Registry Lookup and Signed Answers</name>
      <t>A registry offers a read-only HTTP interface that needs no account. The reference registry answers GET requests on https://idmandat.com/api/v1/verify with a JSON object. A query names either a domain ("domain", optionally with an agent name) or a key directory ("signature_agent", the address from the Signature-Agent header field or the whole header value).</t>
      <t>An answer for an entry contains at least: "domain", "registered", "level", and, where applicable, "organization", "agents" (with "may" and "mayNot"), and "mandate_source" with the value "declared_by_operator". The answer states that the agent details are declarations of the operator and not checked by the registry.</t>
      <section anchor="states">
        <name>Entry States</name>
        <t>An entry that is no longer valid is reported explicitly: "registered" is false, "level" is "none", "entry_state" is one of "revoked", "suspended" or "expired", "state_since" gives the date, and for a revocation "revoked" is true. A recipient MUST NOT rely on earlier answers for such an entry.</t>
      </section>
      <section anchor="sigagent">
        <name>Lookup by Key Directory</name>
        <t>For a query by "signature_agent" the registry normalises the address (https only, lower-case host, default port removed, trailing slash removed, query kept; a well-known key directory path is shortened to the origin) and compares it with the declarations in the entries. The "resolution" is one of: none (no entry declares it), ambiguous (more than one entry declares it; the answer lists them and MUST NOT name one as responsible), or a match. A match carries "key_directory_link", with the value "same_domain" if the directory is on the same registrable domain as the entry (a hint) or "declared_only" (the company merely declares it).</t>
        <t>The registry does not fetch the key directory and does not verify that the company controls it. The link rests on the declaration of the company.</t>
      </section>
      <section anchor="signing">
        <name>Digital Signature</name>
        <t>Answers are signed with Ed25519 <xref target="RFC8032"/>. The answer carries "signed" (true or false), "key_id", "issued_at" and "expires_at" (valid for 15 minutes) and a "signature" object with "alg" and "value". The signed bytes are the UTF-8 encoding of the answer without the "signature" member, with all object members sorted recursively by key, written compactly (no insignificant white space), without escaping non-ASCII characters or the solidus. The value is base64url without padding. Public keys are published at https://idmandat.com/api/v1/keys. An answer with "signed" false MUST NOT be treated as evidence.</t>
      </section>
    </section>

    <section anchor="security">
      <name>Security Considerations</name>
      <t>The statements about agents and their permissions come from the company itself. The registry confirms identity of the company and that the declaration is published on its domain. It does not confirm that the agent exists, that a power of attorney was actually granted, or that the agent respects its "mayNot" list. A recipient decides what to do with the answer and MUST enforce its own limits.</t>
      <t>The link between a key directory and a company (<xref target="sigagent"/>) is a declaration. A company may declare a key directory it does not control. Recipients SHOULD treat "declared_only" as weak and "ambiguous" as no result.</t>
      <t>Answers are valid for a short time and are signed so that they can be cached and replayed only within that time. A client MUST check "expires_at", the domain in the answer and the signature against the published keys, and SHOULD pin the "alg".</t>
      <t>A valid signature on a request (for example as in <xref target="WEBBOTAUTH"/>) shows that the request came from the key holder. It is not evidence of an entry in a registry, and the absence of an entry is not evidence against the agent.</t>
      <t>This document does not define authorisation of single transactions (amount, purpose, time window) or delegation between agents. Those belong to other layers.</t>
    </section>

    <section anchor="privacy">
      <name>Privacy Considerations</name>
      <t>The credential is public by design and SHOULD contain business contact points rather than personal data. The reference registry stores no record of which domains were queried, no addresses of clients and no persons. It keeps only a count of queries per day. Other registries SHOULD be equally restrictive.</t>
    </section>

    <section anchor="iana">
      <name>IANA Considerations</name>
      <section anchor="iana-wk">
        <name>Well-Known URI</name>
        <t>This document requests registration of the following in the "Well-Known URIs" registry <xref target="RFC8615"/>:</t>
        <dl>
          <dt>URI suffix:</dt><dd>idmandat.json</dd>
          <dt>Change controller:</dt><dd>ID MANDAT, kontakt@idmandat.com</dd>
          <dt>Specification document(s):</dt><dd>This document</dd>
          <dt>Status:</dt><dd>provisional</dd>
        </dl>
      </section>
      <section anchor="iana-dns">
        <name>Underscored DNS Node Name</name>
        <t>This document requests registration of the following in the "Underscored and Globally Scoped DNS Node Names" registry <xref target="RFC8552"/>:</t>
        <dl>
          <dt>RR Type:</dt><dd>TXT</dd>
          <dt>_NODE NAME:</dt><dd>_idmandat</dd>
          <dt>Reference:</dt><dd>This document</dd>
        </dl>
      </section>
    </section>
  </middle>
  <back>
    <references>
      <name>References</name>
      <references anchor="normative">
        <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="Scott Bradner"/><date month="March" year="1997"/></front>
          <seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="2119"/>
        </reference>
        <reference anchor="RFC8032" target="https://www.rfc-editor.org/info/rfc8032">
          <front><title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title><author initials="S." surname="Josefsson" fullname="Simon Josefsson"/><author initials="I." surname="Liusvaara" fullname="Ilari Liusvaara"/><date month="January" year="2017"/></front>
          <seriesInfo name="RFC" value="8032"/>
        </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="Barry Leiba"/><date month="May" year="2017"/></front>
          <seriesInfo name="BCP" value="14"/><seriesInfo name="RFC" value="8174"/>
        </reference>
        <reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259">
          <front><title>The JavaScript Object Notation (JSON) Data Interchange Format</title><author initials="T." surname="Bray" fullname="Tim Bray" role="editor"/><date month="December" year="2017"/></front>
          <seriesInfo name="RFC" value="8259"/>
        </reference>
        <reference anchor="RFC8552" target="https://www.rfc-editor.org/info/rfc8552">
          <front><title>Scoped Interpretation of DNS Resource Records through "Underscored" Naming of Attribute Leaves</title><author initials="D." surname="Crocker" fullname="Dave Crocker"/><date month="March" year="2019"/></front>
          <seriesInfo name="BCP" value="222"/><seriesInfo name="RFC" value="8552"/>
        </reference>
        <reference anchor="RFC8615" target="https://www.rfc-editor.org/info/rfc8615">
          <front><title>Well-Known Uniform Resource Identifiers (URIs)</title><author initials="M." surname="Nottingham" fullname="Mark Nottingham"/><date month="May" year="2019"/></front>
          <seriesInfo name="RFC" value="8615"/>
        </reference>
      </references>
      <references anchor="informative">
        <name>Informative References</name>
        <reference anchor="WEBBOTAUTH" target="https://datatracker.ietf.org/doc/draft-ietf-webbotauth-httpsig-protocol/">
          <front>
            <title>HTTP Message Signatures for automated traffic</title>
            <author>
              <organization>IETF Web Bot Auth Working Group</organization>
            </author>
            <date year="2026" month="September"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-ietf-webbotauth-httpsig-protocol-00"/>
        </reference>
      </references>
    </references>
    <section anchor="appendix-a" numbered="false">
      <name>Acknowledgments</name>
      <t>The author thanks the people who commented on the early versions of the format.</t>
    </section>
  </back>
</rfc>
