Skip to content
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
Cannot retrieve contributors at this time

Aries RFC 0003: Protocols


Defines peer-to-peer application-level protocols in the context of interactions among agent-like things, and shows how they should be designed and documented.


Table of Contents


APIs in the style of Swagger are familiar to nearly all developers, and it's a common assumption that we should use them to solve the problems at hand in the decentralized identity space. However, to truly decentralize, we must think about interactions at a higher level of generalization. Protocols can model all APIs, but not the other way around. This matters. We need to explain why.

We also need to show how a protocol is defined, so the analog to defining a Swagger API is demystified.


What is a Protocol?

A protocol is a recipe for a stateful interaction. Protocols are all around us, and are so ordinary that we take them for granted. Each of the following interactions is stateful, and has conventions that constitute a sort of "recipe":

  • Ordering food at a restaurant
  • Buying a house
  • Playing a game of chess, checkers, tic-tac-toe, etc.
  • Bidding on an item in an online auction.
  • Going through security at the airport when we fly
  • Applying for a loan

In the context of decentralized identity, protocols manifest at many different levels of the stack: at the lowest levels of networking, in cryptographic algorithms like Diffie Hellman, in the management of DIDs, in the conventions of DIDComm, and in higher-level interactions that solve problems for people with only minimal interest in the technology they're using. However, this RFC focuses on the last of these layers, where use cases and personas are transformed into features with obvious social value like:

When "protocol" is used in an Aries context without any qualifying adjective, it is referencing a recipe for a high-level interaction like these. Lower-level protocols are usually described more specifically and possibly with other verbiage: "cryptographic algorithms", "DID management procedures", "DIDComm conventions", "transports", and so forth. This helps us focus "protocol" on the place where application developers that consume Aries do most of the work that creates value.

Relationship to APIs

The familiar world of web APIs is a world of protocols, but it comes with constraints antithetical to decentralized identity:

  • It assumes all interactions are between a client and a server--either two parties, or N parties mediated by a central server. Thus, the server is a natural locus for surveillance and hacking.
  • It assumes security is asymmetric--not using DIDs, but driven by certs on a server and by a session for the client.
  • It assumes the transport is HTTP. This is problematic for pure mobile-to-mobile, or for use cases where the transport is complex or asymmetric.
  • Because the server can never initiate an interaction, it requires at least one party to be continuously online.

Protocols impose none of these constraints. Web APIs can easily be modeled as protocols where the transport is HTTP and the payload is a message, and the Aries community actively does this. We are not opposed to APIs. We just want to describe and standardize the higher level abstraction so we don't have a web solution and a BlueTooth solution that are diverged for no good reason.


As used in the agent/DIDComm world, protocols are decentralized. This means there is not an overseer for the protocol, guaranteeing information flow, enforcing behaviors, and ensuring a coherent view. It is a subtle but important divergence from API-centric approaches, where a server holds state against which all other parties (clients) operate. Instead, all parties are peers, and they interact by mutual consent and with a (hopefully) shared understanding of the rules and goals. Protocols are like a dance—not one that's choreographed or directed, but one where the parties make dynamic decisions and react to them.


Types of Protocols

The simplest protocol style is notification. This style involves two parties, but it is one-way: the notifier emits a message, and the protocol ends when the notified receives it. The basic message protocol uses this style.


Slightly more complex is the request-response protocol style. This style involve two parties, with the requester making the first move, and the responder completing the interaction. The Discover Features Protocol uses this style. Note that with protocols as Aries models them (and unlike an HTTP request), the request-response messages are asynchronous.


However, more complex protocols exist. The Introduce Protocol involves three parties, not two. The issue credential protocol includes up to six message types (including ack and problem_report), two of which (proposal and offer) can be used to interactively negotiate details of the elements of the subsequent messages in the protocol.

See this subsection for definitions of the terms "role", "participant", and "party".

Agent Design

Protocols are the key unit of interoperable extensibility in agents and agent-like things. To add a new interoperable feature to an agent, give it the ability to handle a new protocol.

When agents receive messages, they map the messages to a protocol handler and possibly to an interaction state that was previously persisted. This is the analog to routes, route handlers, and sessions in web APIs, and could actually be implemented as such if the transport for the protocol is HTTP. The protocol handler is code that knows the rules of a particular protocol; the interaction state tracks progress through an interaction. For more information, see the agents explainer—RFC 0004 and the DIDComm explainer—RFC 0005.


Protocols are composable--meaning that you can build complex ones from simple ones. The protocol for asking someone to repeat their last sentence can be part of the protocol for ordering food at a restaurant. It's common to ask a potential driver's license holder to prove their street address before issuing the license. In protocol terms, this is nicely modeled as the present proof being invoked in the middle of an issue credential protocol.

When we run one protocol inside another, we call the inner protocol a subprotocol, and the outer protocol a superprotocol. A given protocol may be a subprotocol in some contexts, and a standalone protocol in others. In some contexts, a protocol may be a subprotocol from one perspective, and a superprotocol from another (as when protocols are nested at least 3 deep).

super- and subprotocols

Commonly, protocols wait for subprotocols to complete, and then they continue. A good example of this is mentioned above—starting an issue credential flow, but requiring the potential issuer and/or the potential holder to prove something to one another before completing the process.

In other cases, a protocol B is not "contained" inside protocol A. Rather, A triggers B, then continues in parallel, without waiting for B to complete. This coprotocol relationship is analogous to relationship between coroutines in computer science. In the Introduce Protocol, the final step is to begin a connection protocol between the two introducees-- but the introduction coprotocol completes when the connect coprotocol starts, not when it completes.


Message Types

A protocol includes a number of message types that enable the execution of an instance of a protocol. Collectively, the message types of a protocol become the skeleton of its interface. Most of the message types are defined with the protocol, but several key message types, notably acks and problem reports are defined in separate RFCs and adopted into a protocol. This ensures that the structure of such messages is standardized, but used in the context of the protocol adopting the message types.

Handling Unrecognized Items in Messages

In the semver section of this document there is discussion of the handling of mismatches in minor versions supported and received. Notably, a recipient that supports a given minor version of a protocol less than that of a received protocol message should ignore any unrecognized fields in the message. Such handling of unrecognized data items applies more generally than just minor version mismatches. A recipient of a message from a supported major version of a protocol should ignore any unrecognized items in a received message, even if the supported and minor versions are the same. When items from the message are ignored, the recipient may want to send a warning problem-report message with code fields-ignored.


A protocol has the following ingredients:

How to Define a Protocol

To define a protocol, write an RFC. Specific instructions for protocol RFCs, and a discussion about the theory behind detailed protocol concepts, are given in the instructions for protocol RFCs and in the protocol RFC template.

The tictactoe protocol is attached to this RFC as an example.

tictactoe protocol

Security Considerations

Replay Attacks

It should be noted that when defining a protocol that has domain specific requirements around preventing replay attacks, an @id property SHOULD be required. Given an @id field is most commonly set to be a UUID, it should provide randomness comparable to that of a nonce in preventing replay attacks. However, this means that care will be needed in processing of the @id field to make sure its value has not been used before. In some cases, nonces require being unpredictable as well. In this case, greater review should be taken as to how the @id field should be used in the domain specific protocol. In the event where the @id field is not adequate for preventing replay attacks, it's recommended that an additional nonce field be required by the domain specific protocol specification.


Message Type and Protocol Identifier URIs

Message types and protocols are identified with URIs that match certain conventions.


A message type URI (MTURI) identifies message types unambiguously. Standardizing its format is important because it is parsed by agents that will map messages to handlers--basically, code will look at this string and say, "Do I have something that can handle this message type inside protocol X version Y?"

When this analysis happens, strings should be compared for byte-wise equality in all segments except version. This means that case, unicode normalization, and punctuation differences all matter. It is thus best practice to avoid protocol and message names that differ only in subtle, easy-to-mistake ways.

Comparison of the version segment of an MTURI or PIURI should follow semver rules and is discussed in the semver section of this document.

The URI MUST be composed as follows:

MTURI structure

message-type-uri  = doc-uri delim protocol-name
    "/" protocol-version "/" message-type-name
delim             = "?" / "/" / "&" / ":" / ";" / "="
protocol-name     = identifier
protocol-version  = semver
message-type-name = identifier
identifier        = alpha *(*(alphanum / "_" / "-" / ".") alphanum)

It can be loosely matched and parsed with the following regex:


A match will have captures groups of (1) = doc-uri, (2) = protocol-name, (3) = protocol-version, and (4) = message-type-name.

The goals of this URI are, in descending priority:

  • Code can use the URI to route messages to protocol handlers using semver rules.

  • The definition of a protocol should be tied to the URI such that it is semantically stable. This means that once version 1.0 of a protocol is defined, its definition should not change in ways that would break implementations.

  • Developers can discover information about novel protocols, using the URI to browse or search the web.

The doc-uri portion is any URI that exposes documentation about protocols. A developer should be able to browse to that URI and use human intelligence to look up the named and versioned protocol. Optionally and preferably, the full URI may produce a page of documentation about the specific message type, with no human mediation involved.


A shorter URI that follows the same conventions but lacks the message-type-name portion is called a protocol identifier URI (PIURI).

PIURI structure

protocol-identifier-uri  = doc-uri delim protocol-name
    "/" semver

Its loose matcher regex is:


The following are examples of valid MTURIs and PIURIs:

  • (PIURI with fully automated lookup of protocol docs)
  • (MTURI)
  • (MTURI). Note that this URI returns a 404 error if followed directly--but per rules described above, the developer should browse to the doc root ( and look for documentation on the trust_ping/1.0 protocol.
  • (MTURI) This uses an https reference that could serve information about protocols.

Semver Rules for Protocols

Semver rules apply to protocols, with the version of a protocol is expressed in the semver portion of its identifying URI. The "ingredients" of a protocol combine to form a public API in the semver sense. Core Aries protocols specify only major and minor elements in a version; the patch component is not used. Non-core protocols may choose to use the patch element.

The major and minor versions of protocols match semver semantics:

  • Clarification updates that do not change the "public API" of the protocol can be made with community support without changing the minor version of the protocol.
  • An individual message type can add new optional fields, or deprecate existing fields, with only a change to its protocol's minor version. Similarly, a protocol can add new or deprecate message types with only a change to the minor version.
  • Changes that remove fields or message types, that make formerly optional things required, or that alter the state machine in incompatible ways, must result in an increase of the major version of the protocol/primary message family.

Within a given major version of a protocol, an agent should:

  • Respond to a minimum supported minor version, defaulting to "0".
    • An agent SHOULD keep minimum supported minor version at "0" unless it is unsecure or extremely complicated to do so.
  • Respond with or initiate a protocol instance the current fully supported minor version.

This leads to the following received message handling rules:

  • Message types received with minor versions below the minimum MAY be ignored, or preferably, MAY be answered only with a problem-report message with code version-not-supported.
  • Message types received with a minor version at or higher than the minimum supported and less than the current minor version are processed as follows:
    • The processing MAY be with the same minor version of the received message.
      • To support this, an implementation must implement each minor version from minimum to current within the major version.
    • The processing MAY be with the current minor version (higher than received).
      • This approach is used when maintaining each minor version from minimum to current within the major version is impractical.
      • Recipients of the response message SHOULD detect from the response PIURI that a higher minor version was used in the response, and to compensate if needed and as necessary.
      • Prior wording of this protocol included the following suggestion that is now considered deprecated. See note below about deprecating the "warning" problem reports.
        • In addition to responding with the protocol message (if necessary), the agent MAY also want to send a warning problem-report message with code version-with-degraded-features.
  • Message types received with a minor version higher than the current minor version MUST be processed with any unrecognized fields ignored.
    • The response MUST use the current minor version.
    • Recipients of the response message SHOULD detect from the response PIURI that a lower minor version was used in the response, and to compensate if needed and as necessary.
    • Prior wording of this protocol included the following that is now considered deprecated. See note below about deprecating the "warning" problem reports.
      • In addition to responding with the protocol message, an agent MAY send a warning problem-report message with code fields-ignored-due-to-version-mismatch

Note: The deprecation of the "warning" problem-reports in cases of minor version mismatches is because the recipient of the response can detect the mismatch by looking at the PIURI, making the "warning" unnecessary, and because the problem-report message may be received after (and definitely at a different time than) the response message, and so the warning is of very little value to the recipient. Recipients should still be aware that minor version mismatch warning problem-report messages may be received and handle them appropriately, likely by quietly ignoring them.

As documented in the semver documentation, these requirements are not applied when major version 0 is used. In that case, minor version increments are considered breaking.

Agents may support multiple major versions and select which major version to use when initiating an instance of the protocol.

An agent should reject messages from protocols or unsupported protocol major versions with a problem-report message with code version-not-supported. Agents that receive such a problem-report message may use the discover features protocol to resolve the mismatch.

Semver Examples


Unless Alice's agent (the initiator of a protocol) knows from prior history that it should do something different, it should begin a protocol using the highest version number that it supports. For example, if A.1 supports versions 2.0 through 2.2 of protocol X, it should use 2.2 as the version in the message type of its first message.

Recipient Rules

Agents for Bob (the recipient) should reject messages from protocols with major versions different from those they support. For major version 0, they should also reject protocols with minor versions they don't support, since semver stipulates that features are not stable before 1.0. For example, if B.1 supports only versions 2.0 and 2.1 of protocol X, it should reject any messages from version 3 or version 1 or 0. In most cases, rejecting a message means sending a problem-report that the message is unsupported. The code field in such messages should be version-not-supported. Agents that receive such a problem-report can then use the Discover Features Protocol to resolve version problems.

Recipient agents should accept messages that differ from their own supported version of a protocol only in the patch, prerelease, and/or build fields, whether these differences make the message earlier or later than the version the recipient prefers. These messages will be robustly compatible.

For major version >= 1, recipients should also accept messages that differ only in that the message's minor version is earlier than their own preference. In such a case, the recipient should degrade gracefully to use the earlier version of the protocol. If the earlier version lacks important features, the recipient may optionally choose to send, in addition to a response, a problem-report with code version-with-degraded-features.

If a recipient supports protocol X version 1.0, it should tentatively accept messages with later minor versions (e.g., 1.2). Message types that differ in only in minor version are guaranteed to be compatible for the feature set of the earlier version. That is, a 1.0-capable agent can support 1.0 features using a 1.2 message, though of course it will lose any features that 1.2 added. Thus, accepting such a message could have two possible outcomes:

  1. The message at version 1.2 might look and behave exactly like it did at version 1.0, in which case the message will process without any trouble.

  2. The message might contain some fields that are unrecognized and need to be ignored.

In case 2, it is best practice for the recipient to send a problem-report that is a warning, not an error, announcing that some fields could not be processed (code = fields-ignored-due-to-version-mismatch). Such a message is in addition to any response that the protocol demands of the recipient.

If the recipient of a protocol's initial message generates a response, the response should use the latest major.minor protocol version that both parties support and know about. Generally, all messages after the first use only major.minor

version negotiation matrix

State Details and State Machines

While some protocols have only one sequence of states to manage, in most different roles perceive the interaction differently. The sequence of states for each role needs to be described with care in the RFC.

State Machines

By convention, protocol state and sequence rules are described using the concept of state machines, and we encourage developers who implement protocols to build them that way.

Among other benefits, this helps with error handling: when one agent sends a problem-report message to another, the message can make it crystal clear which state it has fallen back to as a result of the error.

Many developers will have encountered a formal of definition of state machines as they wrote parsers or worked on other highly demanding tasks, and may worry that state machines are heavy and intimidating. But as they are used in Aries protocols, state machines are straightforward and elegant. They cleanly encapsulate logic that would otherwise be a bunch of conditionals scattered throughout agent code. The tictactoe example protocol example includes a complete state machine in less than 50 lines of python code, with tests.

For an extended discussion of how state machines can be used, including in nested protocols, and with hooks that let custom processing happen at each point in a flow, see

Processing Points

A protocol definition describes key points in the flow where business logic can attach. Some of these processing points are obvious, because the protocol makes calls for decisions to be made. Others are implicit. Some examples include:

  • The beginning and end.
  • The launch of a subprotocol.
  • The completion of a subprotocol, or the subprotocol changing state.
  • Sending a message. (For each send, the sender could choose to go silent and abandon the interaction instead, though many protocols would ask for notification to be emitted as best practice.)
  • (Receiving a message_. (Requires validation, then integration with policy and processes internal to the agent and its sovereign domain, to move the interaction forward.)

Roles, Participants, Parties, and Controllers


The roles in a protocol are the perspectives (responsibilities, privileges) that parties take in an interaction.

This perspective is manifested in three general ways:

  • by the expectations that a party takes on in a protocol (ex. a role may be expected to do something to start a protocol).
  • by the messages that a party can and does use in the course of the protocol (some messages may be reserved for a single role, while other may used by some if not all roles).
  • by the state and the transition rules

Like parties, roles are normally known at the start of the protocol but this is not a requirement.

In an auction protocol, there are only two roles—auctioneer and bidder—even though there may be many parties involved.


The participants in a protocol are the agents that send and/or receive plaintext application-level messages that embody the protocol's interaction. Alice, Bob, and Carol may each have a cloud agent, a laptop, and a phone; if they engage in an introduction protocol using phones, then the agents on their phones are the participants. If the phones talk directly over Bluetooth, this is particularly clear--but even if the phones leverage push notifications and HTTP such that cloud agents help with routing, only the phone agents are participants, because only they maintain state for the interaction underway. (The cloud agents would be facilitators, and the laptops would be bystanders). When a protocol is complete, the participant agents know about the outcome; they may need to synchronize or replicate their state before other agents of the parties are aware.


The parties to a protocol are the entities directly responsible for achieving the protocol's goals. When a protocol is high-level, parties are typically people or organizations; as protocols become lower-level, parties may be specific agents tasked with detail work through delegation.

Imagine a situation where Alice wants a vacation. She engages with a travel agent named Bob. Together, they begin an "arrange a vacation" protocol. Alice is responsible for expressing her parameters and proving her willingness to pay; Bob is responsible for running a bunch of subprotocols to work out the details. Alice and Bob--not software agents they use--are parties to this high-level protocol, since they share responsibility for its goals.

As soon as Alice has provided enough direction and hangs up the phone, Bob begins a sub-protocol with a hotel to book a room for Alice. This sub-protocol has related but different goals--it is about booking a particular hotel room, not about the vacation as a whole. We can see the difference when we consider that Bob could abandon the booking and choose a different hotel entirely, without affecting the overarching "arrange a vacation" protocol.

With the change in goal, the parties have now changed, too. Bob and a hotel concierge are the ones responsible for making the "book a hotel room" protocol progress. Alice is an approver and indirect stakeholder, but she is not doing the work. (In RACI terms, Alice is an "accountable" or "approving" entity, but only Bob and the concierge are "responsible" parties.)

Now, as part of the hotel reservation, Bob tells the concierge that the guest would like access to a waverunner to play in the ocean on day 2. The concierge engages in a sub-sub-protocol to reserve the waverunner. The goal of this sub-sub-protocol is to reserve the equipment, not to book a hotel or arrange a vacation. The parties to this sub-sub-protocol are the concierge and the person or automated system that manages waverunners.

Often, parties are known at the start of a protocol; however, that is not a requirement. Some protocols might commence with some parties not yet known or assigned.

For many protocols, there are only two parties, and they are in a pairwise relationship. Other protocols are more complex. Introductions involves three; an auction may involve many.

Normally, the parties that are involved in a protocol also participate in the interaction but this is not always the case. Consider a gossip protocol, two parties may be talking about a third party. In this case, the third party would not even know that the protocol was happening and would definitely not participate.


The controllers in a protocol are entities that make decisions. They may or may not be direct parties.

Imagine a remote chess game between Bob and Carol, conducted with software agents. The chess protocol isn't technically about how to select a wise chess move; it's about communicating the moves so parties achieve the shared goal of running a game to completion. Yet choices about moves are clearly made as the protocol unfolds. These choices are made by controllers--Bob and Carol--while the agents responsible for the work of moving the game forward wait with the protocol suspended.

In this case, Bob and Carol could be analyzed as parties to the protocol, as well as controllers. But in other cases, the concepts are distinct. For example, in a protocol to issue credentials, the issuing institution might use an AI and/or business automation as a controller.

Instructions for Protocol RFCs

A protocol RFC conforms to general RFC patterns, but includes some specific substructure.

template sections

Please see the special protocol RFC template for details.


This RFC creates some formalism around defining protocols. It doesn't go nearly as far as SOAP or CORBA/COM did, but it is slightly more demanding of a protocol author than the familiar world of RESTful Swagger/OpenAPI.

The extra complexity is justified by the greater demands that agent-to-agent communications place on the protocol definition. See notes in Prior Art section for details.

Rationale and alternatives

Some of the simplest DIDComm protocols could be specified in a Swagger/OpenAPI style. This would give some nice tooling. However, not all fit into that mold. It may be desirable to create conversion tools that allow Swagger interop.

Prior art


BPMN (Business Process Model and Notation) is a graphical language for modeling flows of all types (plus things less like our protocols as well). BPMN is a mature standard sponsored by OMG(Object Management Group). It has a nice tool ecosystem (such as this). It also has an XML file format, so the visual diagrams have a two-way transformation to and from formal written language. And it has a code generation mode, where BPMN can be used to drive executable behavior if diagrams are sufficiently detailed and sufficiently standard. (Since BPMN supports various extensions and is often used at various levels of formality, execution is not its most common application.)

BPMN began with a focus on centralized processes (those driven by a business entity), with diagrams organized around the goal of the point-of-view entity and what they experience in the interaction. This is somewhat different from a DIDComm protocol where any given entity may experience the goal and the scope of interaction differently; the state machine for a home inspector in the "buy a home" protocol is quite different, and somewhat separable, from the state machine of the buyer, and that of the title insurance company.

BPMN 2.0 introduced the notion of a choreography, which is much closer to the concept of an A2A protocol, and which has quite an elegant and intuitive visual representation. However, even a BPMN choreography doesn't have a way to discuss interactions with decorators, adoption of generic messages, and other A2A-specific concerns. Thus, we may lean on BPMN for some diagramming tasks, but it is not a substitute for the RFC definition procedure described here.


WSDL (Web Services Description Language) is a web-centric evolution of earlier, RPC-style interface definition languages like IDL in all its varieties and CORBA. These technologies describe a called interface, but they don't describe the caller, and they lack a formalism for capturing state changes, especiall by the caller. They are also out of favor in the programmer community at present, as being too heavy, too fragile, or poorly supported by current tools.

Swagger / OpenAPI

Swagger / OpenAPI overlaps with some of the concerns of protocol definition in agent-to-agent interactions. We like the tools and the convenience of the paradigm offered by OpenAPI, but where these two do not overlap, we have impedance.

Agent-to-agent protocols must support more than 2 roles, or two roles that are peers, whereas RESTful web services assume just client and server--and only the server has a documented API.

Agent-to-agent protocols are fundamentally asynchronous, whereas RESTful web services mostly assume synchronous request~response.

Agent-to-agent protocols have complex considerations for diffuse trust, whereas RESTful web services centralize trust in the web server.

Agent-to-agent protocols need to support transports beyond HTTP, whereas RESTful web services do not.

Agent-to-agent protocols are nestable, while RESTful web services don't provide any special support for that construct.


  • Pdef (Protocol Definition Language): An alternative to Swagger.
  • JSON RPC: Defines how invocation of remote methods can be accomplished by passing JSON messages. However, the RPC paradigm assumes request/response pairs, and does not provide a way to describe state and roles carefully.
  • IPC Protocol Definition Language (IPDL): This is much closer to agent protocols in terms of its scope of concerns than OpenAPI. However, it is C++ only, and intended for use within browser plugins.

Unresolved questions

  • Should we write a Swagger translator?
  • If not swagger, what formal definition format should we use in the future?


The following lists the implementations (if any) of this RFC. Please do a pull request to add your implementation. If the implementation is open source, include a link to the repo or to the implementation within the repo. Please be consistent in the "Name" field so that a mechanical processing of the RFCs can generate a list of all RFCs supported by an Aries implementation.

Name / Link Implementation Notes
Indy Cloud Agent - Python several protocols, circa Feb 2019
Aries Framework - .NET several protocols, circa Feb 2019 several protocols, circa Feb 2019
Aries Cloud Agent - Python numerous protocols plus extension mechanism for pluggable protocols
Aries Static Agent - Python 2 or 3 protocols
Aries Framework - Go DID Exchange
Connect.Me mature but proprietary protocols; community protocols in process
Verity mature but proprietary protocols; community protocols in process
Aries Protocol Test Suite 2 or 3 core protocols; active work to implement all that are ACCEPTED, since this tests conformance of other agents
Pico Labs implemented protocols: connections, trust_ping, basicmessage, routing