AsyncAPI Conference

DeveloperWeek 2026

18th - 20th of February, 2026 | San Jose, United States

22 days until the end of Call for Speakers

How TransferGo adopted AsyncAPI

Zbigniew Malcherczyk

·8 min read

Introduction

Founded in 2012, TransferGo serves over 8 million customers in more than 160 countries worldwide. We aim to provide more accessible financial services to migrants, making international money transfers cheaper, simpler, and faster.

You can read TransferGo's full story on transfergo.com

TransferGo Architecture

Just like any other fintech, time is crucial to its operation. The customers expect their money to travel instantly. Therefore, the majority of the systems rely on Event Driven Architecture, an asynchronous communication built on top of Amazon Web Services (AWS) and its products, such as Simple Notification Service (SNS) and Simple Queue Service (SQS), with a pinch of Kafka.

Async Communication flow

How it Started?

AsyncAPI Standard Introduction

In 2021, the Backend guild in TransferGo defined a problem. There were too many approaches to documenting REST and async APIs within the guild. That was when the story of TransferGo and AsyncAPI Initiative began. Let me tell you how we leveraged the possibilities of the AsyncAPI specification to improve and drive our engineers' experience.

Code-first Documentation

Given the large codebase, the threat of an outdated API schema was significant. Therefore, the organisation didn't advocate for an API-first approach, as the code is a source of truth for a long-living product. To ease the pain of repeating the same information over and over, the backend guild rolled out a unique internal library that was based on Reflection builds message payload from its Data Transfer Object (DTO).

This combination enables engineers to:

  • Ease the introduction for an engineer
  • Reduce code repetition
  • Ensure company-wide standards
  • Enable seamless upgrades between AsyncAPI versions

The only downside is that the library needs to be maintained.

1#[Message(name: 'PaymentExecuted')]
2#[Channel(name: 'payment_executed')]
3final readonly class PaymentExecuted
4{
5    public function __construct(
6        public float $amount,
7        public string $createdAt,
8    ) {
9    }
10}

Our internal library, with just these two attributes, generates an AsyncAPI schema like this:

1asyncapi: 3.0.0
2info:
3  title: 'Service Example API'
4  version: 1.2.3
5channels:
6  payment_executed:
7    messages:
8      PaymentExecuted:
9        $ref: '#/components/messages/PaymentExecuted'
10components:
11  messages:
12    PaymentExecuted:
13      payload:
14        type: object
15        properties:
16          amount:
17            type: number
18          createdAt:
19            type: string
20        required:
21          - amount
22          - createdAt

Continuous API Validation

The schema catalog grew quite fast; with over 50 services, we started to notice inconsistencies and sometimes even invalid schemas. With teams growing, we had to support more events, more operations and more approaches. For example, some teams preferred writing/generating AsyncAPI yaml schema with the help of AI. Growing technical stacks, validated our ideas in 2021, and we had to take some actions.

Let's not reinvent the wheel. AsyncAPI CLI has a built-in validation command, which comes in handy. It's easy to use and quite fast. This way, with simple asyncapi validate schema.yaml, we managed to ensure our services expose ONLY valid schemas. Some docs were quite heavy, reaching 1 MB. With 100 channels and twice that number of contracts, the schema size could reach that. However, thanks to asyncapi optimize schema.yaml command, we cut the size by about 50%. That's a small win for us, our resources and the planet.

We also noticed that there are teams that like to pimp-up their schema, and teams that fall behind. We were looking for a system that could reward some teams and encourage others. At that time, we also invested time in the Service Catalog. That's why we raised a proposal of adapting an ability to score the schema You can enjoy this feature since the 2.2.0 version

Documentation Showcase

We’ve spent time making sure our services are well-documented and validated. But let’s be honest, reading YAML isn’t enjoyable for most people. So we started looking for tools that could present our schemas in a more visual, developer-friendly way. At first, we used the official React Component to render the documentation. Thanks to our internal tooling, each service could host its own visual docs. While this worked, it wasn't the best experience: engineers had to remember where each service's docs lived or manually navigate to a central document listing them all. To solve this, we decided to adopt a more modern and scalable approach: a Service Catalog and Developer Portal. After weighing our options, we chose Port.io. It offered a lot of functionality, but the key win for us was the ability to generate a UI for our AsyncAPI definitions and provide a unified interface where all service documentation is just a click away. To keep everything up to date, we automated the publishing process using a GitHub Actions workflow. This workflow pulls the latest AsyncAPI specs from S3 bucket and pushes them into Port.io, so the documentation is always current without any manual effort.

Now, instead of chasing URLs or digging through repos, developers can browse all available services, see their contracts visually, and quickly understand how to integrate with them — all in one place.

How's it Going?

Event Catalog

With over 300 channels, learning what's published, where, and when is quite a challenge. Thankfully, there are solutions for this pain. The Event Catalog project, done by David helped us show the big picture and significantly showcased scenarios that required our attention. Below, you can find our process of gathering schemas and building an event catalog from AsyncAPI files.

Service documentation generation pipeline

Event Catalog Building pipeline

Contract Testing

Recently, our attention has been focused on contract testing. It would be ideal to build such an extra layer of tests based on well-known specs like OpenAPI and AsyncAPI. Multiple solutions were tested, but the Microcks project seemed to suite us the best.

We’ve recently been focusing more on contract testing as a way to ensure our services interact reliably as they grow and change. By validating service communication against defined contracts, we catch issues early and avoid surprises when integrating new features.

To do this, we rely on well-known specifications like OpenAPI for REST and AsyncAPI for asynchronous messaging. These specs define the expected request/response structure or message formats, and serve as the source of truth for what services send and receive.

After trying out several tools, we found Microcks to be the best fit for our needs. It supports both OpenAPI and AsyncAPI, making it easy to import our specs, simulate endpoints, and run conformance checks automatically.

Our message-driven architecture includes Symfony-based workers that consume real messages — often from AWS SQS. To test these components properly without relying on cloud infrastructure, we use LocalStack to emulate AWS services locally. This lets us run realistic, end-to-end contract tests as part of our pipeline.

We’ve integrated this setup into our Jenkins CI pipeline. During test runs, we bootstrap Microcks with our AsyncAPI definitions, which describe the expected message structure and communication channels. Once the services and workers are up, Microcks sends test messages through LocalStack, and we validate that our Symfony workers process them as expected.

This approach has helped us detect contract issues early, maintain clear communication boundaries between services, and keep our integration tests fast and reliable.

Chart presenting how TransferGo adopts Microcks

API Coverage

One of the problems within distributed systems and organisations is ensuring trust. Engineers must trust your Event Catalog and your API. To do so, you need to ensure it's up to date. Many systems provide Schema Registry, but not all of them. When dealing with mature systems, it's not so easy to migrate to new and fancy systems.

That's how the concept of API Guardian came up. This internal tool compares and checks Service CloudFormation files and AsyncAPI schemas for forgotten channels. It's nothing more than a simple CLI app based on Oclif Framework that compares two or multiple files. It's a more complicated topic as you need to understand which parts of the infrastructure are the contracts. Some elements must be ignored, like Dead Letter Queues or Internal Queues. Because of that, we can develop a nice config file that lets you ignore specific SQS, SNS, and channels as necessary.

1node asyncapi-coverage
2    --async-api-schema async-api-docs.yaml
3    --cloudformation sns-sqs.yaml
4    --service service-name
5    --environment production
6    --coverage 100
1{
2  "ignore": {
3    "sqs": [
4      "${AppEnvironment}-${Service}-commands.fifo",
5      "${AppEnvironment}-${Service}-events"
6    ],
7    "sns": [],
8    "channels": []
9  }
10}

The Big Picture

TransferGo Big Picture Architecture

Summary

At TransferGo, reliable communication between services is critical, especially in a fast-paced, event-driven fintech environment. To support this, we adopted the AsyncAPI specification to bring clarity, consistency, and automation to how we document, validate, and test asynchronous APIs. Starting with a code-first approach, we built internal tooling that automatically generates AsyncAPI schemas from DTOs, ensuring that documentation stays in sync with actual behavior. As the number of services and channels grew, we introduced validation pipelines, schema scoring, and optimization practices to maintain quality at scale. We then tackled accessibility by moving from isolated, YAML-based docs to a centralized Developer Portal powered by Port.io. For testing, we use Microcks with LocalStack in Jenkins CI to run end-to-end contract tests against real message consumers. To further increase trust and visibility, we integrated our schemas into an Event Catalog and built a custom CLI tool, API Guardian, to measure schema coverage against deployed infrastructure. AsyncAPI has become a foundational part of how we scale service development at TransferGo - helping us move fast, stay aligned, and keep our system reliable and well-documented from day one.