Markdown Editor

Event-Driven API Specification Template (AsyncAPI 3)

Async event contract: brokers, channels, operations, CloudEvents envelope, ordering, delivery, DLQ, schema evolution, AsyncAPI YAML

Arsitektur & Desain SistemLengkapAsyncAPI 3.0, CloudEvents 1.0eventapispecificationmath

Cara menggunakan: Use when a service publishes events or messages other teams consume. Decide the delivery contract and schema compatibility rules before the first event ships, then document each message with a field table and a full example. Main pitfall: promising exactly-once or global ordering that the broker cannot give.

Pratinjau

Event API Specification: [Event domain or application name]

Complete specification for an event-driven, asynchronous interface: brokers, channels, operations, messages and schemas, envelope, ordering, delivery guarantees, retries and dead-letter handling, schema evolution, security and consumer onboarding. The structure follows the concepts of the AsyncAPI Specification 3.0 (servers, channels, operations, messages, components) and uses the CloudEvents 1.0 envelope. Replace every [bracketed] value and every row marked Example. Worked examples use an order-fulfilment event stream.

Document control

FieldValue
Document ID[EVT-SPEC-FULFIL-001]
Producing application[Fulfilment service]
Event contract version[1.2.0]
Document version[0.1]
Status[Draft / In review / Approved / Deprecated]
Owner (team)[@team-fulfilment]
Classification[Internal / Partner / Public]
Last updatedYYYY-MM-DD
Related[AsyncAPI file path], [Schema registry subject], [REST API spec]

Approvals

RoleNameDecisionDate
Producer owner[@name][Approved / Changes requested]YYYY-MM-DD
Platform / messaging team[@name][Decision]YYYY-MM-DD
Security[@name][Decision]YYYY-MM-DD
Consumer representative[@name][Decision]YYYY-MM-DD

Revision history

VersionDateAuthorChange summary
0.1YYYY-MM-DD[@name]First draft
0.2YYYY-MM-DD[@name]Example: Changed partition key from customerId to orderId
1.0YYYY-MM-DD[@name]Example: Approved for production

Contents

1. Introduction

1.1 Purpose

[What the events communicate and why an asynchronous interface was chosen. Example: "The Fulfilment service publishes the lifecycle of each shipment so that billing, notifications and analytics can react without calling Fulfilment synchronously."]

1.2 Scope and context

ItemValue
Bounded contextExample: Fulfilment
Producer(s)Example: fulfilment-service (sole writer of every channel in this spec)
Known consumersExample: billing-service, notification-service, analytics lake ingest
Interaction styleExample: Event notification with full state (event-carried state transfer)
Out of scopeExample: Commands to Fulfilment (use the REST API), inventory events

1.3 Event design principles

  • Events describe facts that already happened, named in the past tense.
  • Each event type has exactly one producing application.
  • Payloads carry enough state for typical consumers to act without a call-back; sensitive data is excluded unless listed in section 10.
  • Consumers must tolerate duplicates, gaps in optional fields and unknown fields.

2. Servers and brokers

Server IDEnvironmentHostProtocolVersionNotes
prodProduction[broker-1.prod.example.com:9093]Kafka[3.7]TLS and SASL/OAUTHBEARER
stagingStaging[broker-1.stg.example.com:9093]Kafka[3.7]Masked data
sandboxPartner sandbox[events.sandbox.example.com]AMQP 0-9-1 / MQTT / WebSocket[Version][Bridge for external partners]
[ID][Environment][Host][Protocol][Version][Notes]

3. Channels

Channel IDAddressMessagesPartitionsRetentionCleanup
CH-01fulfilment.shipment.v1ShipmentCreated, ShipmentDispatched, ShipmentDelivered, ShipmentFailed247 daysdelete
CH-02fulfilment.shipment-state.v1ShipmentState (latest snapshot per shipment)24infinitecompact
CH-03fulfilment.shipment.v1.dlqAny message from CH-01 that failed consumer processing630 daysdelete
[CH-nn][Address][Messages][n][Retention][Policy]

Channel naming convention: <domain>.<entity>[-<qualifier>].v<major>, lower case, dot-separated. A new major version means a new channel.

4. Operations

Operation IDActionChannelMessage(s)TriggerExpected rate
OP-01sendCH-01ShipmentCreatedLabel purchased from carrierExample: 40/s average, 300/s peak
OP-02sendCH-01ShipmentDispatchedCarrier scan at depot35/s average
OP-03sendCH-01ShipmentDeliveredCarrier delivery confirmation30/s average
OP-04sendCH-02ShipmentStateEvery change on CH-01Same as CH-01 total
OP-05receiveorders.order.v1OrderPaidStarts picking for a paid order45/s average
[OP-nn][send / receive][Channel][Message][Trigger][Rate]

5. Messages and schemas

5.1 Envelope: CloudEvents attributes

All messages use the CloudEvents 1.0 envelope in binary content mode: attributes travel as protocol headers (prefixed ce_ on Kafka) and the payload is the message body. Examples in this document use the structured JSON form for readability. partitionkey comes from the CloudEvents partitioning extension.

AttributeRequiredValue ruleExample
specversionYesAlways 1.01.0
idYesUnique per event from this source; UUID or ULID01HV7A0B2C9D8E7F6G5H4J3K2L
sourceYesURI reference of the producing application/fulfilment-service/eu-west-1
typeYesReverse-DNS event type with major versioncom.example.fulfilment.shipment.dispatched.v1
timeYesRFC 3339 UTC time the fact occurred2026-03-15T14:02:11Z
subjectYesID of the entity the event is aboutshp_01HV79ZZ0K
datacontenttypeYesPayload media typeapplication/avro / application/json
dataschemaYesURI of the schema version in the registryhttps://schemas.example.com/fulfilment/shipment-dispatched/3
partitionkeyYesOrdering key (section 6)ord_01HV6Z3K8Q
traceparentYesW3C Trace Context for distributed tracing00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
[extension][Yes / No][Rule][Example]

5.2 Message catalogue

MessageType attributeSchema subjectFormatKey fields
ShipmentCreatedcom.example.fulfilment.shipment.created.v1fulfilment.shipment-createdAvroshipmentId, orderId, carrier, serviceLevel
ShipmentDispatchedcom.example.fulfilment.shipment.dispatched.v1fulfilment.shipment-dispatchedAvroshipmentId, orderId, trackingNumber, dispatchedAt
ShipmentDeliveredcom.example.fulfilment.shipment.delivered.v1fulfilment.shipment-deliveredAvroshipmentId, orderId, deliveredAt, proofOfDelivery
ShipmentFailedcom.example.fulfilment.shipment.failed.v1fulfilment.shipment-failedAvroshipmentId, orderId, reasonCode
[Message][Type][Subject][Format][Fields]

5.3 Example: ShipmentDispatched

Payload fields:

FieldTypeRequiredDescription
shipmentIdstringYesShipment ID, prefix shp_
orderIdstringYesOrder the shipment belongs to
carrierenumYesDHL, UPS, LA_POSTE, OTHER; consumers must accept unknown values
trackingNumberstringYesCarrier tracking number
dispatchedAttimestampYesTime of the first carrier scan
parcelCountintYesNumber of parcels, at least 1
estimatedDeliveryDatedateNoCarrier estimate, if supplied
{
  "specversion": "1.0",
  "id": "01HV7A0B2C9D8E7F6G5H4J3K2L",
  "source": "/fulfilment-service/eu-west-1",
  "type": "com.example.fulfilment.shipment.dispatched.v1",
  "time": "2026-03-15T14:02:11Z",
  "subject": "shp_01HV79ZZ0K",
  "datacontenttype": "application/json",
  "dataschema": "https://schemas.example.com/fulfilment/shipment-dispatched/3",
  "partitionkey": "ord_01HV6Z3K8Q",
  "data": {
    "shipmentId": "shp_01HV79ZZ0K",
    "orderId": "ord_01HV6Z3K8Q",
    "carrier": "LA_POSTE",
    "trackingNumber": "6A12345678901",
    "dispatchedAt": "2026-03-15T14:02:11Z",
    "parcelCount": 1,
    "estimatedDeliveryDate": "2026-03-17"
  }
}

5.4 Example: [Message name]

[Repeat the field table and a complete example for every message in 5.2.]

6. Ordering and partitioning

TopicRule
Partition keyExample: orderId, so all shipment events for one order land in one partition
Order guaranteedEvents for the same orderId are delivered in the order they were produced
Order not guaranteedAcross orders; across channels (CH-01 versus orders.order.v1)
Partition count24; changes only with a migration plan because key-to-partition mapping changes
Hot keysOne order rarely exceeds 10 events; no hot-key mitigation needed
Out-of-order handlingConsumers compare time and a per-entity sequence field and drop older updates

The partition for a key is chosen by hashing:

p=hash(partitionkey) mod Pp = \text{hash}(\text{partitionkey}) \bmod P

so increasing the partition count PP remaps keys and can break ordering during the change.

7. Delivery semantics

7.1 Producer guarantees

  • Delivery: at least once. Duplicates are possible after producer retries or failover.
  • No silent loss: events are written to a transactional outbox table in the same database transaction as the state change, and a relay publishes them with broker acknowledgement from all in-sync replicas (acks=all).
  • Producer idempotence is enabled to reduce, not eliminate, duplicates.
  • Maximum publish delay from state change to broker: [5 s at p99].

7.2 Consumer obligations

ObligationHow
Be idempotentStore processed id values (or the entity version) and skip repeats for at least the retention period
Commit after processingCommit offsets only after side effects are durable
Tolerate unknown fields and enum valuesUse the reader schema; map unknown enums to a default branch
Handle out-of-order eventsApply only if the event is newer than the stored state
Bound processing timeKeep each message under [30 s] or move work to a job queue

7.3 Exactly-once statements

[State whether any end-to-end exactly-once processing is offered. Example: "Not offered. Consumers achieve effectively-once results through idempotent processing as described in 7.2."]

8. Retries and dead-letter handling

Failure typeExampleConsumer behaviour
TransientDownstream timeout, database deadlockRetry in place up to 3 times with backoff 1 s, 5 s, 25 s
Persistent but recoverableReferenced customer not yet replicatedPublish to retry channel with delay 5 min, maximum 6 attempts
PoisonSchema-valid but semantically invalid payloadPublish to CH-03 dead-letter channel immediately
Deserialisation errorUnknown schema IDPublish raw bytes to CH-03 with error header

Dead-letter messages carry the original headers plus dlq_reason, dlq_consumer, dlq_attempts and dlq_first_failure_time.

DLQ process stepRule
AlertAny message in CH-03 pages the owning consumer team during business hours; more than [100] in 10 min pages on call
TriageWithin [1 business day]
ReplayFix, then replay with the platform replay tool, preserving id so idempotency still applies
DiscardOnly with a ticket recording the reason and approver

9. Schema evolution and compatibility

9.1 Compatibility mode

The schema registry enforces [BACKWARD_TRANSITIVE / FULL_TRANSITIVE] compatibility for every subject in this specification: a consumer using any newer schema can read all data written with older schemas.

ChangeAllowed in the same major version?
Add an optional field with a defaultYes
Remove an optional field that has a defaultYes, after deprecation notice
Add a value to an enumYes, consumers must handle unknown values
Add a required field without a defaultNo
Rename a field or change its typeNo
Change the meaning or unit of a fieldNo
Change the partition keyNo; new channel version

9.2 Breaking changes

A breaking change creates a new major event type (for example com.example.fulfilment.shipment.dispatched.v2) on a new channel. The producer dual-publishes v1 and v2 for at least [6 months]; v1 is then sunset after every registered consumer confirms migration.

9.3 Deprecation of fields

Mark deprecated fields with "deprecated": true in the schema doc string, announce in the changelog, keep populating them for [3 months], then remove only if the compatibility mode allows it.

10. Security

ControlRule
TransportTLS 1.2 or later between clients and brokers and between brokers
AuthenticationExample: SASL/OAUTHBEARER with workload identity; no shared passwords
AuthorisationACLs per principal: producer has WRITE on CH-01 and CH-02 only; each consumer group has READ on named channels
Personal dataExample: No names, addresses or phone numbers in payloads; consumers fetch them from the Customer API when authorised
Encryption at restBroker disks encrypted with provider-managed keys; [field-level encryption for proofOfDelivery image URL]
IntegritySchemas validated at produce time; unknown producers rejected by ACL
AuditBroker audit log of ACL changes and authentication failures retained [1 year]

11. AsyncAPI document

The authoritative machine-readable contract is [asyncapi/fulfilment.yaml]. The skeleton shows the AsyncAPI 3.0 structure used here.

asyncapi: 3.0.0
info:
  title: Fulfilment Events
  version: 1.2.0
  description: Shipment lifecycle events published by fulfilment-service.
defaultContentType: application/json
servers:
  prod:
    host: broker-1.prod.example.com:9093
    protocol: kafka
    security:
      - $ref: '#/components/securitySchemes/oauth'
channels:
  shipment:
    address: fulfilment.shipment.v1
    messages:
      shipmentDispatched:
        $ref: '#/components/messages/ShipmentDispatched'
operations:
  publishShipmentDispatched:
    action: send
    channel:
      $ref: '#/channels/shipment'
    messages:
      - $ref: '#/channels/shipment/messages/shipmentDispatched'
components:
  securitySchemes:
    oauth:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://auth.example.com/oauth2/token
          availableScopes:
            events:fulfilment:read: Read fulfilment events
  messages:
    ShipmentDispatched:
      name: ShipmentDispatched
      contentType: application/json
      headers:
        type: object
        properties:
          ce_id: {type: string}
          ce_type: {type: string, const: com.example.fulfilment.shipment.dispatched.v1}
          ce_time: {type: string, format: date-time}
      payload:
        $ref: '#/components/schemas/ShipmentDispatchedPayload'
      bindings:
        kafka:
          key:
            type: string
            description: orderId
  schemas:
    ShipmentDispatchedPayload:
      type: object
      required: [shipmentId, orderId, carrier, trackingNumber, dispatchedAt, parcelCount]
      properties:
        shipmentId: {type: string}
        orderId: {type: string}
        carrier: {type: string}
        trackingNumber: {type: string}
        dispatchedAt: {type: string, format: date-time}
        parcelCount: {type: integer, minimum: 1}
        estimatedDeliveryDate: {type: string, format: date}

12. Interaction flows

The main flow from a carrier scan to downstream reactions, including the outbox relay and a consumer failure routed to the dead-letter channel:

ScenarioProducer eventsExpected consumer reaction
Example: Normal deliveryCreated, Dispatched, DeliveredBilling invoices on Dispatched; Notification emails on each
Example: Failed deliveryCreated, Dispatched, FailedNotification emails customer; Support case opened
[Scenario][Events][Reaction]

13. Operations and service levels

IndicatorObjectiveMeasured as
Publish latencyp99 at or below 5 s from state change to brokerOutbox row timestamp to broker timestamp
Producer availability99.9% of events published within 60 s, monthlyOutbox backlog age
Broker availability[99.95%] monthlyPlatform SLO
Consumer lag (per consumer, owned by consumer)Below [60 s] p95Lag exporter
[Indicator][Objective][Method]

Replay: consumers may reset offsets within the retention window. Requests to re-publish older history go to [@team-fulfilment] with [5 business days] notice.

14. Consumer onboarding

StepActionOwnerDone when
1Read this specification and the AsyncAPI fileConsumer teamQuestions raised in [channel]
2Register as a consumer: name, contact, channels, purpose, data needsConsumer teamEntry in consumer registry
3Request ACLs and a consumer group ID (<team>.<app>.<purpose>)Platform teamACL applied in staging
4Implement idempotency, DLQ and unknown-field handling per section 7 and 8Consumer teamCode review checklist passed
5Run contract tests against registry schemasConsumer teamCI green
6Load test at [2x] expected peak in stagingConsumer teamLag stays below objective
7Add lag and DLQ alerts to the team dashboardConsumer teamAlerts fire in a test
8Production ACL approvalProducer owner and SecurityACL applied in production

Registered consumers:

ConsumerTeamChannelsContactSince
Example: billing-serviceBillingCH-01[@billing-oncall]YYYY-MM-DD
[Consumer][Team][Channels][@contact]YYYY-MM-DD

15. Glossary and references

15.1 Glossary

TermMeaning
ChannelAddressable destination for messages, such as a topic or queue
OperationWhat an application does on a channel: send or receive
EnvelopeMetadata wrapped around a payload (here CloudEvents attributes)
Partition keyValue that decides which partition receives a message and therefore its ordering scope
OutboxTable written in the same transaction as business state, later relayed to the broker
Dead-letter queue (DLQ)Channel holding messages that could not be processed
Compatibility modeRegistry rule deciding which schema changes are accepted
[Term][Meaning]

15.2 References

ReferenceUsed for
AsyncAPI Specification 3.0Structure of sections 2 to 5 and 11
CloudEvents Specification 1.0 (CNCF)Envelope attributes in 5.1
W3C Trace Contexttraceparent propagation
RFC 3339Timestamps
[Schema registry documentation]Compatibility modes
[Internal messaging standard][Use]

Standard and licence note

Structure aligned with the AsyncAPI Specification 3.0 (Apache License 2.0): servers, channels, operations, messages and reusable components, with the CloudEvents 1.0 envelope (CNCF, Apache License 2.0). Based on common industry practice for event-driven integration, including the transactional outbox and dead-letter channels. This template is original text written for this collection and reproduces no text from those specifications; read them for their normative requirements. Template licence: MIT.

Templat terkait