DEV Community

Preecha
Preecha

Posted on

How Do You Build Event-Driven APIs with Webhooks and Message Queues?

TL;DR

Event-driven APIs use webhooks for external notifications and message queues for internal processing. Publish events to a queue such as RabbitMQ or Kafka, process them asynchronously, and notify clients with webhooks. Modern PetstoreAPI uses this pattern for order processing, inventory updates, and payment notifications.

Try Apidog today

Introduction

When a customer places an order, your API may need to charge payment, update inventory, send email, notify the warehouse, and trigger webhooks.

Doing all of that synchronously can make the customer wait several seconds. An event-driven API returns a response as soon as the order is accepted, then processes the remaining work in the background.

A typical flow looks like this:

  1. The client sends POST /orders.
  2. The API creates the order.
  3. The API publishes an order.created event.
  4. The API returns 201 Created.
  5. Background workers process payment, inventory, and email tasks.
  6. A webhook worker notifies external clients when processing is complete.

Modern PetstoreAPI uses event-driven architecture for orders, payments, and inventory. Apidog helps you test webhooks, validate event flows, and simulate asynchronous processing.

Event-Driven Architecture

Event-driven APIs publish events when something happens. Other services subscribe to those events and react independently.

Core components

  • Event producer: The API endpoint or service that publishes an event.
  • Event bus or queue: Routes and stores events using systems such as RabbitMQ, Kafka, or Amazon SQS.
  • Event consumer: A background worker that consumes and processes events.
  • Webhook worker: Sends event notifications to external clients over HTTP.

Request and event flow

Client
  │
  ├── POST /orders ───────────────► API
  │                                  │
  │                                  ├── Publish order.created ──► Queue
  │                                  │
  ◄── 201 Created ───────────────────┘

Worker ◄── Consume order.created
  │
  ├── Process payment
  ├── Update inventory
  ├── Send confirmation email
  │
  └── Publish order.completed ─────► Queue

Webhook worker ◄── Consume order.completed
  │
  └── Send webhook ────────────────► Client
Enter fullscreen mode Exit fullscreen mode

Webhooks for External Events

Use webhooks when another application needs to receive notifications from your API.

The order endpoint can publish an event after creating the order:

app.post('/v1/orders', async (req, res) => {
  const order = await createOrder(req.body);

  await eventBus.publish('order.created', {
    orderId: order.id,
    userId: order.userId,
    total: order.total
  });

  res.status(201).json(order);
});
Enter fullscreen mode Exit fullscreen mode

A background worker can send a webhook after the order is completed:

eventBus.subscribe('order.completed', async (event) => {
  const webhooks = await getWebhooks(
    event.userId,
    'order.completed'
  );

  for (const webhook of webhooks) {
    await sendWebhook(webhook.url, {
      event: 'order.completed',
      data: event
    });
  }
});
Enter fullscreen mode Exit fullscreen mode

Keep the initial API response independent from webhook delivery. If a webhook endpoint is temporarily unavailable, the order should still be processed. Add retry logic with exponential backoff for failed webhook deliveries.

Message Queues for Internal Events

Use message queues for communication between internal services and background workers. Queues decouple the order API from payment, inventory, email, and other processing steps.

RabbitMQ-style example

// Publisher
await publishEvent('order.created', {
  orderId: '019b4132'
});

// Consumer
await consumeEvents('order.*', async (event) => {
  await processOrder(event);
});
Enter fullscreen mode Exit fullscreen mode

The producer does not need to know which workers consume the event. Consumers can be scaled independently as processing volume changes.

Queues also provide durability and retry capabilities, which help prevent events from being lost when a worker fails.

How Modern PetstoreAPI Implements Event-Driven APIs

Modern PetstoreAPI uses the following order-processing sequence:

  1. POST /orders returns 201 Created immediately.
  2. The API publishes an order.created event.
  3. A payment worker processes the payment.
  4. An inventory worker updates stock.
  5. An email worker sends the confirmation.
  6. A webhook worker notifies the client.

See Modern PetstoreAPI event architecture.

Testing with Apidog

Use Apidog to test the individual parts of an event-driven API:

  • Send requests that publish events.
  • Test webhook delivery to client endpoints.
  • Validate event names and payloads.
  • Simulate asynchronous processing.
  • Test retry behavior when a webhook fails.
  • Verify the event flow from order creation through completion.

Testing each stage separately makes it easier to identify whether a failure occurs in the API, queue, worker, or webhook integration.

Conclusion

Event-driven APIs improve responsiveness and scalability by separating the initial API request from background processing.

Use:

  • Webhooks for notifications to external clients.
  • Message queues for internal service communication and asynchronous work.
  • Background workers for payment, inventory, email, and other processing tasks.
  • Retry logic to handle temporary webhook failures.

Modern PetstoreAPI demonstrates these patterns for order, payment, and inventory workflows.

FAQ

What’s the difference between webhooks and message queues?

Webhooks notify external clients over HTTP. Message queues handle internal service communication and background processing.

Which message queue should I use?

  • RabbitMQ for a straightforward queue-based architecture.
  • Kafka for high-throughput event streaming.
  • AWS SQS when you prefer a managed queue service.

How do you handle webhook failures?

Implement retry logic with exponential backoff. You can also record failed deliveries so they can be inspected or retried later. See our webhook reliability guide.

Can you use events without message queues?

Yes. However, queues provide durability, retry support, and decoupling between producers and consumers.

How do you test event-driven APIs?

Use Apidog to test webhook delivery, validate event payloads, simulate asynchronous processing, and verify retry behavior.

Top comments (0)