Background image

In Depth: Speakeasy vs APIMatic

Nolan Sullivan

Nolan Sullivan

January 16, 2024

Featured blog post image

At Speakeasy, we create idiomatic SDKs in the most popular languages. Our generators follow principles that ensure we create SDKs that offer the best developer experience so that you can focus on building your API, and your developer-users can focus on delighting their users.

In this post, we'll compare TypeScript SDKs managed by Speakeasy to those generated by APIMatic.

TL;DR? Here's what we found:

  • Ease of Installation: The Speakeasy CLI has a straightforward installation process, especially for macOS users, with a single dependency-free binary. APIMatic, while also straightforward, requires Node.js and is installed using npm, which might add complexity for some users.
  • Code Generation: In our test, the SDK generated by APIMatic via CLI had issues with the src/clientInterface.ts file. Although the APIMatic support team responded, the problem persisted in our Docker environment test. By contrast, Speakeasy generated a complete and error-free SDK on our first attempt.
  • Documentation and Code Structure: The Speakeasy-created SDK included comprehensive documentation, and relies on Zod for runtime data parsing, making it easier for developers to understand and use. The structure and organization of the SDK were clear and intuitive.
  • Developer Experience and Flexibility: Speakeasy seems to place a significant emphasis on the developer experience, offering more customization options and a focus on the API-Developer Experience (DevEx). This could be particularly beneficial for teams looking for greater control over their SDKs.
  • Response to Issues: While the APIMatic support team was responsive, the resolution provided did not address the issue effectively in our case. Since we encountered no issues creating an SDK with Speakeasy, there was no need to similarly test the Speakeasy support team's responsiveness.

Speakeasy and APIMatic each have their strengths, but Speakeasy's ease of installation, reliable code generation, and developer-focused features give it the edge. Of course, individual experiences may vary based on specific needs and use cases, so you might want to follow our process below to test drive both tools.

Getting Started

To compare Speakeasy to APIMatic, we'll generate a new TypeScript SDK for the Swagger Petstore API. This way, we can see how the generators differ in terms of code quality, usability, and automation.

If you're following along, first create accounts on Speakeasy and APIMatic.

Next, download the Swagger Petstore OpenAPI spec. Open the terminal and create a new folder as the root of your workspace for testing SDK generators:

mkdir speakeasy-apimatic && cd speakeasy-apimatic

Now download the Swagger Petstore OpenAPI 3.0 document:


Installing the SDK Generators

To generate SDKs, we'll start by installing each service's CLI.

Installing the Speakeasy CLI

The Speakeasy CLI is distributed as a single, dependency-free binary. If you're on macOS, install the Speakeasy CLI by running the following in the terminal:

brew install speakeasy-api/homebrew-tap/speakeasy

Then, authenticate with the Speakeasy platform to use the Speakeasy CLI:

speakeasy auth login

Speakeasy will open in a browser window, where you may already be logged in. If not, log in to Speakeasy using your email address and password, select your Speakeasy workspace, and follow the prompts to grant the CLI access to the Speakeasy API.

If you're not on macOS, download the latest binary for your system from the Speakeasy releases page (opens in a new tab) on GitHub.

The Speakeasy CLI is developed in Go and is open source (opens in a new tab).

Installing the APIMatic CLI

The APIMatic CLI is built with Node.js, and we'll install it using npm. In the terminal, run:

npm install -g @apimatic/cli

This will install the APIMatic CLI in your global node_modules folder and create the apimatic command.

Authenticate with APIMatic by running:

apimatic auth:login

Then enter your APIMatic email address and password.

The APIMatic CLI is also open source (opens in a new tab).

Generating an SDK Using the APIMatic CLI Tutorial

We'll follow the APIMatic tutorial (opens in a new tab) to generate a TypeScript SDK.

In the terminal, run:

apimatic sdk:generate --platform=typescript --file="petstore.yaml"

This should print the following to the terminal:

Generating SDK... done
Downloading SDK... done
Success! Your SDK is located at ~/speakeasy-apimatic/petstore_sdk_typescript

Inspecting the APIMatic-Generated SDK

To see what was generated, run the tree command from the new SDK directory:

cd petstore_sdk_typescript
tree .

This should print the list of generated files in a hierarchy:

├── doc
│   ├──
│   ├──
│   └──
├── jest.config.js
├── package.json
├── src
│   ├── authentication.ts
│   ├── client.ts
│   ├── clientAdapter.ts
│   └── clientInterface.ts
├── tsconfig.base.json
├── tsconfig.cjs.json
├── tsconfig.esm.json
└── tsconfig.json
3 directories, 15 files

Poking around the source, we found that the generated SDK did not contain any model code or types related to our Petstore example. The src/clientInterface.ts file seems to have been generated incorrectly. Here's what we found:


SdkRequestBuilderFactory = RequestBuilderFactory<
export type SdkRequestBuilder = ReturnType<SdkRequestBuilderFactory>;
export type Server = 'default';
export type AuthParams = boolean;
* Swagger PetstoreLib
* This file was automatically generated by APIMATIC v3.0 ( ).
import { RequestBuilderFactory } from './core';
export interface ClientInterface {
getRequestBuilderFactory(): SdkRequestBuilderFactory;
export type

The file seems to start in the middle, then wrap around.

This error gave us an opportunity to engage with the APIMatic support team, so we'll take a brief detour and share our experience: After seven days of filing the bug report, we received a curt, "We've tested out the SDKs via the CLI method and they're being generated as expected." To be fair, the support agent did offer to provide further assistance if we still had a problem.

As any responsible tester would do, we decided to isolate the test environment from our system to be sure the issue doesn't stem from an error on our side. We're using nvm on macOS after all, and issues can crop up when switching between Node versions.

We created a Dockerfile to install the requirements and generate an SDK:

FROM node:latest
ARG apimatic_auth_key=APIMATIC_KEY
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY petstore.yaml /usr/src/app
RUN npm install -g @apimatic/cli
RUN apimatic auth:login --auth-key=$apimatic_auth_key
RUN apimatic sdk:generate --platform=typescript --file="petstore.yaml"
RUN cat petstore_sdk_typescript/src/clientInterface.ts

Replace $APIMATIC_KEY with your APIMatic API key, then run:

docker build -t apimatic-petstore --build-arg apimatic_auth_key=$APIMATIC_KEY --progress plain .

On a second run with Docker, the bug appeared to fix itself, only to fail again later.

Sure enough, the result was the same - the src/clientInterface.ts file starts in the middle and wraps around. This might be caused by a race condition in the code that downloads and unzips the SDK from APIMatic. Tempting as it is to track this error down, we have SDKs to generate, so we'll move on.

If you're following along, remember to delete your Docker image, as it contains your API key. The key also appears in your Docker history.

In the terminal, run:

docker image rm apimatic-petstore

We need to find another way to generate an SDK using APIMatic - let's try the web app.

Generating an SDK Using the APIMatic UI

Log in to the APIMatic web application and follow the prompts to import the Petstore spec as a new API.

Click on Generate and select TypeScript. This generates a TypeScript SDK, which downloads to your computer as a zip file.

Here's what's inside:

├── doc
│   ├──
│   ├──
│   ├──
│   ├── controllers
│   │   └──
│   └── models
│       ├──
│       └──
├── jest.config.js
├── package.json
├── src
│   ├── authentication.ts
│   ├── client.ts
│   ├── clientAdapter.ts
│   ├── clientInterface.ts
│   ├── configuration.ts
│   ├── controllers
│   │   ├── baseController.ts
│   │   └── petsController.ts
│   ├── core.ts
│   ├── defaultConfiguration.ts
│   ├── errors
│   │   └── customError.ts
│   ├── index.ts
│   ├── models
│   │   └── pet.ts
│   └── schema.ts
├── tsconfig.base.json
├── tsconfig.cjs.json
├── tsconfig.esm.json
└── tsconfig.json
8 directories, 27 files

This looks more complete, and none of the files are corrupted, so we'll move on to trying the Speakeasy generator.

Creating an SDK Using the Speakeasy CLI

Back in your local workspace, create a TypeScript SDK with Speakeasy by running:

speakeasy generate sdk \
--schema petstore.yaml \
--lang typescript \
--out ./petstore-sdk-speakeasy

Speakeasy creates an SDK and returns the following output:

Authenticated with workspace successfully -
Generating SDK for typescript...
INFO    operation valid	{"operation":"listPets","type":"paths"}
INFO    operation valid	{"operation":"createPets","type":"paths"}
INFO    operation valid	{"operation":"showPetById","type":"paths"}
INFO    versioning: feature version changed detected, bumping patch version	{"current":"3.4.6","feature":"core","previous":"3.4.5"}
INFO    versioning: fix level change detected, bumping patch version
SDK for typescript generated successfully ✓
For docs on customising the SDK check out:

We'll take a look at what Speakeasy created:

cd petstore-sdk-speakeasy
tree .

Here's what's inside:

├── docs
│   ├── models
│   │   ├── components
│   │   │   ├──
│   │   │   └──
│   │   └── operations
│   │       ├──
│   │       ├──
│   │       ├──
│   │       ├──
│   │       └──
│   └── sdks
│       ├── pets
│       │   └──
│       └── sdk
│           └──
├── package-lock.json
├── package.json
├── src
│   ├── index.ts
│   ├── lib
│   │   ├── base64.ts
│   │   ├── config.ts
│   │   ├── encodings.ts
│   │   ├── http.ts
│   │   ├── retries.ts
│   │   ├── sdks.ts
│   │   ├── security.ts
│   │   └── url.ts
│   ├── models
│   │   ├── components
│   │   │   ├── error.ts
│   │   │   ├── index.ts
│   │   │   └── pet.ts
│   │   ├── errors
│   │   │   ├── index.ts
│   │   │   └── sdkerror.ts
│   │   └── operations
│   │       ├── createpets.ts
│   │       ├── index.ts
│   │       ├── listpets.ts
│   │       └── showpetbyid.ts
│   ├── sdk
│   │   ├── index.ts
│   │   ├── pets.ts
│   │   └── sdk.ts
│   └── types
│       ├── blobs.ts
│       ├── decimal.ts
│       ├── index.ts
│       ├── operations.ts
│       └── rfcdate.ts
└── tsconfig.json
16 directories, 41 files

Creating an SDK Using the Speakeasy Web App

You can also create an SDK using the Speakeasy web app (opens in a new tab).

SDKs compared

Now that we have two SDKs, let's see how they differ.


For each SDK, in the root of the generated code, install the package's dependencies:

npm install

We found that the SDK managed by Speakeasy has a dependency tree of 232 packages, while the SDK generated by APIMatic depends on 411 packages. npm audit warns about three vulnerabilities of moderate severity in the APIMatic SDK, but on closer inspection, the vulnerability should not affect users, as it's an Axios cross-site request forgery vulnerability.

The SDK generated by APIMatic depends on four packages from APIMatic at runtime:

"dependencies": {
"@apimatic/authentication-adapters": "^0.5.0",
"@apimatic/axios-client-adapter": "^0.2.0",
"@apimatic/core": "^0.10.0",
"@apimatic/schema": "^0.7.0"

Speakeasy, on the other hand, bundles all runtime dependencies apart from Zod (opens in a new tab), JSONPath (opens in a new tab), and decimal.js (opens in a new tab). The dependencies bundled by Speakeasy are popular and widely used, making them well-vetted and familiar to developers.

Serialization and Validation

TypeScript SDKs managed by Speakeasy use Zod for runtime data parsing and serialization, while code generated by APIMatic uses the @apimatic/schema package. The documentation available for Zod (opens in a new tab) is approachable and clear, which makes it easier for developer users to understand runtime type errors.

Usage Examples

To illustrate usage, we added a discriminated union response type to the createPets operation in our schema, with two new components, Cat and Dog:

description: A pet to be returned
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
propertyName: petType
Cat: '#/components/schemas/Cat'
Dog: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Pet'
- type: object
type: string
example: Dog
type: string
name: dog
- $ref: '#/components/schemas/Pet'
- type: object
type: string
example: Cat
type: boolean
type: integer
format: int32
name: cat

After regenerating the two SDKs, we can use each to create a new pet.

Using the SDK managed by Speakeasy, we create a new SDK instance, then call sdk.pets.createPets():

Info Icon


Here we use imports that reference the default package names set by each generator.

import { SDK } from "openapi";
import { Pet, Status } from "openapi/models/components";
import { CreatePetsResponse } from "openapi/models/operations";
async function run() {
const sdk = new SDK();
const pet: Pet = {
id: 596804,
name: "string",
status: Status.Available,
const result: CreatePetsResponse = await sdk.pets.createPets(pet);
if (result.error) {
const petResponse = result.oneOf;
if (petResponse?.petType === "Dog") {
console.log(petResponse.bark); // Unique to dogs
} else if (petResponse?.petType === "Cat") {
console.log(petResponse.age); // Unique to cats
} else {
console.error("Unexpected pet type");

Using the SDK generated by APIMatic, we import Client and PetsController, create a new client and pass it to PetsController, then call petsController.createPets():


import {
} from "swagger-petstorelib";
async function run() {
const client = new Client({
timeout: 0,
const petsController = new PetsController(client);
const body: Pet = {
id: BigInt(120),
name: "name6",
try {
const { result, ...httpResponse } = await petsController.createPets(body);
if (CreatePetsResponse.isCat(result)) {
// Use the result narrowed down to Cat type.
} else if (CreatePetsResponse.isDog(result)) {
// Use the result narrowed down to Dog type.
} else {
// result is narrowed down to type 'never'.
} catch (error) {
if (error instanceof ApiError) {
const errors = error.result;

The convenience methods CreatePetsResponse.isCat and CreatePetsResponse.isDog are useful, but in both SDKs, the response is typed, and TypeScript intellisense works as expected.

Now that we know how to use our TypeScript SDKs, let's get a broader overview of Speakeasy and APIMatic.

SDK language support

Both Speakeasy and APIMatic generate SDKs in various languages. A notable difference is that Speakeasy can manage SDKs in Swift and Unity (both in alpha).

C# .NET✔️✔️

Additionally, Speakeasy can manage Terraform providers based on OpenAPI specifications.

SDK Customization

Speakeasy's customization focuses on enhancing the API-developer experience (DevEx) through its x-speakeasy extensions and gen.yaml file configurations. These customizations allow detailed control over SDK components, including method naming, grouping into namespaces, retries, pagination, and more.

Both Speakeasy and APIMatic offer a broad range of customizable settings across various aspects of SDK generation.


Both Speakeasy and APIMatic can run as GitHub actions to autogenerate new SDK branches when your API definition changes. This ensures that managed SDKs are always up to date.


Speakeasy stands out for its user-friendly installation, error-free code generation, and a strong focus on enhancing developer experience. The platform's emphasis on customization, clear documentation, and intuitive SDK structure are significant advantages for developers seeking a seamless integration process and detailed control over SDK components.

CTA background illustrations

Speakeasy Changelog

Subscribe to stay up-to-date on Speakeasy news and feature releases.