Swagger Webhooks and Callbacks let your API signal events to other services asynchronously, enabling event-driven architectures.

Imagine you’re building an e-commerce platform. When a customer places an order, you don’t want to hold their browser open waiting for every single downstream system (inventory, shipping, payment) to confirm. That would be a terrible user experience. Instead, you want to tell the customer "Your order is processing!" and then use webhooks to notify other services that an order has been placed.

Let’s see this in action with a simplified OpenAPI (Swagger) definition.

openapi: 3.0.0
info:
  title: E-commerce API
  version: 1.0.0
servers:
  - url: https://api.example.com/v1
paths:
  /orders:
    post:
      summary: Create a new order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderRequest'
      responses:
        '201':
          description: Order created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
      # This is where the webhook magic happens!
      callbacks:
        OrderCreated:
          'https://my-event-listener.example.com/webhooks/order/{orderId}': # The callback URL, can be dynamic
            post:
              summary: Notification of order creation
              requestBody:
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/OrderEvent'
              responses:
                '200':
                  description: Acknowledged receipt of the webhook
components:
  schemas:
    OrderRequest:
      type: object
      properties:
        customerId:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'
    Order:
      type: object
      properties:
        orderId:
          type: string
        customerId:
          type: string
        status:
          type: string
          enum: [PENDING, PROCESSING, SHIPPED, DELIVERED, CANCELLED]
        createdAt:
          type: string
          format: date-time
    OrderItem:
      type: object
      properties:
        productId:
          type: string
        quantity:
          type: integer
    OrderEvent:
      type: object
      properties:
        eventType:
          type: string
          enum: [ORDER_CREATED, ORDER_STATUS_UPDATED]
        orderId:
          type: string
        timestamp:
          type: string
          format: date-time
        payload:
          $ref: '#/components/schemas/Order' # The actual order details

In this example, when a POST /orders request is successfully processed (returning a 201), the API also defines a webhook OrderCreated. The callbacks object specifies the URL to which the event notification will be sent. Notice the {orderId} in the URL – this is a variable that can be populated with data from the response of the original request, making the callback URL dynamic. The post operation within the callback defines the structure of the event payload (OrderEvent) that will be sent to the listening service.

This system solves the problem of tightly coupled, synchronous communication. Instead of the order service directly calling inventory, shipping, and payment services and waiting for responses, it simply creates the order and then fires off an event. Any service interested in order creation can subscribe to this event by providing a webhook URL. The API then acts as a central dispatcher, sending the OrderEvent to all registered webhook endpoints. This decouples services, making them more resilient and easier to scale. If the shipping service is temporarily down, the order creation can still succeed, and the webhook for shipping can be retried later.

The core idea is that the API definition itself describes how to communicate asynchronously. The callbacks object in OpenAPI 3.0 is the specific mechanism for this. It allows the API provider to declare the available event notifications and the expected structure of those notifications, along with the URLs where subscribers should listen. This makes it self-documenting and discoverable.

A key detail often missed is how the callback URL is determined. While the example shows a static URL with a dynamic path parameter ({orderId}), the actual URL can be entirely dynamic, constructed from data in the initial request or response. For instance, a user might provide their preferred webhook endpoint in a user profile, and the API would then use that specific URL for their events. The callbacks definition acts as a template or a default, but the actual destination can be more flexible.

The next step in building robust event-driven systems is understanding how to handle webhook delivery reliability, including acknowledgment mechanisms and retry strategies.

Want structured learning?

Take the full Swagger course →