Book a consultation

Event-Driven Architecture

AsyncAPI: Documenting Events as Contracts with AsyncAPI 3.0

AsyncAPI explained: the open specification for documenting event-driven APIs, what changed in AsyncAPI 3.0, and how catalogues and governance use it.

Vladimir Romanov


AsyncAPI is an open specification for describing event-driven APIs: a YAML or JSON document that states which broker an application connects to, which channels (topics or queues) it sends and receives on, and exactly what each message contains. It does for events what OpenAPI does for REST. The Linux Foundation has hosted the AsyncAPI Initiative since March 2021, alongside OpenAPI (Linux Foundation), and the current major version, AsyncAPI 3.0, was released in December 2023 (AsyncAPI).

For a plant or an enterprise building an event-driven architecture, AsyncAPI is the difference between “there is a topic called line3/filler/state” and a contract that says what the payload means, which version it is, who publishes it and who depends on it. This page explains the document, what changed in version 3.0, how it relates to CloudEvents and catalogues, and how governance uses it. It is part of our event-driven architecture guide.

Why events need contracts

Events decouple systems in time and identity, and that is also their risk. In a request-driven integration, a broken interface fails loudly: the call returns an error. In an event-driven one, a producer can rename a field or change a unit, and consumers keep running with wrong data until someone notices on a report. In our IT/OT integration experience, that silent breakage is the most common long-term failure of a unified namespace or event backbone, more common than any broker fault.

A contract fixes three things:

  1. Meaning. Is count good parts or total parts? Is temp in Celsius? Is the timestamp from the PLC or the gateway?
  2. Ownership. Who publishes this event, who consumes it, and who approves a change?
  3. Change. Which version is current, what changed, and how long does the old version keep flowing?

AsyncAPI puts those answers in a machine-readable file that can be validated, versioned in Git, rendered as documentation and used to generate code.

The anatomy of an AsyncAPI 3.0 document

ObjectWhat it recordsPlant example
asyncapiThe specification version3.0.0
infoTitle, version and description of this application’s interface“Line 3 filler events”, version 1.2.0
serversBrokers the application connects to: host, protocol, pathname, securityThe site MQTT broker on port 8883 with TLS
channelsAddresses (topics, queues) and the messages that can appear on themsite1/packaging/line3/filler/state
operationsWhat the application does on each channel: send or receive, and request and replyThe gateway sends state changes
componentsReusable messages, schemas, security schemes, traits and bindingsThe StateChanged message and its JSON Schema
Anatomy of an AsyncAPI 3.0 document and what it produces On the left, a document box lists the six top-level sections: asyncapi version, info, servers, channels, operations and components. Arrows show that operations reference channels, channels reference messages in components, and servers describe where channels live. On the right, four outputs come from the same document: human-readable documentation, generated code and client stubs, validation of messages in tests or at runtime, and an entry in an event catalogue. One document, four uses: the contract is written once and read by people and tools asyncapi.yaml (version 3.0.0) info: title, version servers: host, protocol operations action: send | receive channels address, messages components messages, payload schemas, security, traits and protocol bindings (MQTT, Kafka) refers to Readable documentation for each team Generated code and client stubs Message validation in tests and at runtime Entry in the event catalogue In 3.0, operations point at channels, so the same channel can be reused by several applications' documents.
The value is in the right-hand column. A document that only renders as a web page is documentation; one that also drives validation and the catalogue is a contract the organisation can enforce.

A worked plant example

The document below is illustrative. It describes an edge gateway that sends filler state changes to a plant MQTT broker, following the AsyncAPI 3.0 structure (specification).

asyncapi: 3.0.0
info:
  title: Line 3 Filler Events
  version: 1.2.0
  description: State changes published by the line 3 filler edge gateway.
servers:
  plantBroker:
    host: broker.site1.example.local:8883
    protocol: mqtt
channels:
  fillerState:
    address: site1/packaging/line3/filler/state
    messages:
      stateChanged:
        $ref: '#/components/messages/StateChanged'
operations:
  sendFillerState:
    action: send
    channel:
      $ref: '#/channels/fillerState'
components:
  messages:
    StateChanged:
      contentType: application/json
      payload:
        type: object
        required: [eventId, state, timestamp]
        properties:
          eventId: { type: string, format: uuid }
          state: { type: string, enum: [running, stopped, starved, blocked, faulted] }
          reasonCode: { type: integer }
          timestamp: { type: string, format: date-time }

What this gives the plant. The MES team knows the five allowed states and that eventId exists for de-duplication. The data team knows the timestamp format. A test can reject a message with a misspelt state before it reaches production. When the gateway owner wants to add a shift field, the version moves to 1.3.0 and every consumer listed against the channel can be told.

What changed in AsyncAPI 3.0

Version 3.0 was a breaking release. Teams with 2.x documents should plan a conversion; the AsyncAPI release notes summarise the changes (AsyncAPI).

ChangeIn 2.xIn 3.0Why it matters
Operation keywordspublish and subscribe, which many readers found back to frontsend and receive, from the application’s own point of viewFewer misread documents
Channels and operationsOperations defined inside channelsChannels and messages detached from operationsA shared channel can be described once and reused
Request and replyNot modelled directlyFirst-class request and replyCommands and acknowledgements can be documented
Server addressA single urlSeparate host, pathname and protocolClearer, easier to template per site
Messages on a channelOne message or oneOfA named map of messagesEasier references and reuse
ReuseLimited componentsComponents for channels, operations, replies and moreShared plant conventions live in one place

Bindings, CloudEvents and schema registries

Bindings carry protocol detail. AsyncAPI is protocol-agnostic, so MQTT-specific settings (QoS, retain), Kafka-specific settings (partitions, key schema) and others are expressed as bindings on servers, channels, operations or messages. Vendor protocols have bindings too; Solace, for example, contributed bindings for its own protocol.

CloudEvents is complementary. CloudEvents defines a common envelope inside each event (source, type, id, time and so on), and the CNCF graduated it in January 2024 (CNCF). AsyncAPI describes the interface; CloudEvents standardises the metadata. Using both gives tools a predictable event id and type without reading every schema.

Schema registries hold the payload schemas that AsyncAPI references, with compatibility checks when a schema changes. Kafka estates usually already run one. The AsyncAPI document and the registry should point at the same schema, not hold two copies.

Catalogues and governance

Close-up of colourful source code on a dark monitor with a blurred sidebar in the foreground
Generated code is only trustworthy when the contract it came from is reviewed and versioned like the code itself.

An event catalogue is the searchable collection of every AsyncAPI document and schema in the organisation, with owners, versions and the relationships between producers and consumers. For a manufacturer it becomes the plant data dictionary: a quality engineer can find “which events tell me a batch completed, and who owns them?” without asking around. Commercial catalogues exist, and some import and export AsyncAPI; the Solace Event Portal is one example (Solace docs). Open-source tooling from the AsyncAPI Initiative covers editing, validation and generation.

Governance in practice means a few rules that are actually enforced:

  1. Design first for shared events. The contract is reviewed before the producer is built.
  2. Version with meaning. Additive changes are minor versions; removed or renamed fields are major versions with a migration window.
  3. Validate in the pipeline. Documents are linted, and test messages are checked against the schema before deployment.
  4. Name an owner per event. The owner approves changes and answers questions.
  5. Keep the catalogue in step with runtime. Some tools compare what the broker actually carries with what is documented; without that, the catalogue drifts.

Where to start with AsyncAPI in a plant

Do not try to document everything at once. A practical first pass, in our view, looks like this:

  1. Pick the shared events. Start with the five to ten events more than one team consumes: machine state, counts, batch start and end, quality results, alarms that leave the site.
  2. Write one document per publisher. The edge gateway, the MES and the quality system each own a document for what they send.
  3. Agree the common parts once. Put the envelope fields (event id, timestamp, source, asset path) in shared components, ideally aligned with CloudEvents, and reference them from every document.
  4. Store the documents in Git next to the gateway or integration code, with a review step for changes.
  5. Render and publish them where plant and IT engineers will actually look, then add validation to the deployment pipeline.

The measure of success is simple: when someone asks what an event means, the answer is a link, not a meeting.

Limits and open questions

  • Adoption in OT is early. Most plant MQTT namespaces are undocumented or documented in spreadsheets. AsyncAPI’s tooling grew up in software teams, and few OT products export it today.
  • 3.0 tooling support varies. Version 3.0 is a breaking change, and not every generator, catalogue or vendor tool supported it equally at release. Check the version your tools read and write.
  • Sparkplug payloads are a poor fit. Sparkplug’s Protobuf payload carries many metrics with their own names and types, so describing it as a fixed schema says little. Contextualised UNS payloads in JSON document far better.
  • Documents drift. A contract that is not checked against what is actually published becomes fiction within months.
  • It does not replace a topic convention. AsyncAPI documents channels; it does not decide how your namespace should be organised.

How to evaluate AsyncAPI for your architecture

  • How many teams or vendors publish and consume shared events today?
  • Where would the documents live, and how are they reviewed and versioned?
  • Do your brokers, catalogue and generators support AsyncAPI 3.0?
  • Will you use CloudEvents metadata, and is it in the schemas?
  • Is there a schema registry, and do documents reference it rather than copy it?
  • Who owns each shared event, and is that recorded in the document?
  • Can you detect events on the broker that no document describes?

If the starting point is a namespace nobody has written down, documenting the current events is usually the first deliverable of an IT/OT integration engagement.

Deeper

There are no child pages under this guide yet. These go further:

Back to the event-driven architecture hub.

Frequently asked questions

What is AsyncAPI?

AsyncAPI is an open specification for describing event-driven, asynchronous APIs in a machine-readable YAML or JSON document. It records which servers and protocols an application uses, which channels or topics it sends and receives on, and the structure of each message. It plays the role for events that OpenAPI plays for REST, and it is hosted by the Linux Foundation.

What changed in AsyncAPI 3.0?

AsyncAPI 3.0, released in December 2023, separates channels and messages from the operations performed on them, so channels can be reused across documents. It replaces the confusing publish and subscribe keywords with send and receive from the application's point of view, adds request and reply, splits the server URL into host, pathname and protocol, and widens what can be reused through components.

Is AsyncAPI the same as CloudEvents?

No, and they work together. AsyncAPI describes an application's event interface: channels, operations and message schemas. CloudEvents, a CNCF specification, defines a common envelope of metadata inside each event, such as its source, type, id and time. An AsyncAPI document can describe messages that follow the CloudEvents format.

Does AsyncAPI work with MQTT and Kafka?

Yes. AsyncAPI is protocol-agnostic and uses bindings to capture protocol-specific details. There are bindings for MQTT, Kafka, AMQP, JMS and several vendor protocols, so one document can state an MQTT topic's QoS and retain flag, or a Kafka topic's partitions and key schema, alongside the payload definition.

Do plants need AsyncAPI if they already have a UNS topic convention?

A topic convention says where events live; it does not say what is inside them, who publishes them, which version applies or who to call when they change. AsyncAPI documents that contract. For a single line it may be overkill, but once several teams or vendors publish and consume plant events, an AsyncAPI description per publisher prevents silent breakage.

References and further reading

  1. AsyncAPI Specification 3.0.0 · AsyncAPI Initiative
  2. AsyncAPI 3.0.0 Release Notes · AsyncAPI Initiative
  3. Linux Foundation Will Host AsyncAPI to Support Growth and Collaboration for Industry's Fastest-Growing API Spec · Linux Foundation
  4. CloudEvents · Cloud Native Computing Foundation
  5. Cloud Native Computing Foundation Announces the Graduation of CloudEvents · CNCF
  6. Solace Event Portal · SolaceOne commercial catalogue that imports and exports AsyncAPI.

← Event-Driven Architecture

Have a project that needs technical ownership?

Send us the situation. If it is not something we should take on, we will say so.