Dwolla: A Single Solution for Finance Teams

Type-Safe Payments | Dwolla's New TypeScript SDK

Written by Dwolla | Feb 20, 2026 3:28:47 PM

Integrating a payment API shouldn't feel like assembling furniture without instructions.

Yet here's what raw API integration often looks like: you misspell amount as ammount in a transfer request, deploy to production, and discover the bug when a payout fails silently. The API just returned a generic 400 error. For payment APIs, where mistakes have real consequences, this friction is a liability.

We've heard from developers who wanted a more robust, type-safe way to integrate. That’s why we've released the Dwolla TypeScript SDK, built with Speakeasy and generated from our OpenAPI spec to bring type-safe API integration to Node.js and TypeScript developers.

Instead of stitching together raw HTTP requests and hoping you got every field and header right, you work with typed methods like dwolla.customers.create() and dwolla.transfers.create(). TypeScript flags mistakes earlier, and the SDK handles OAuth token management so you authenticate once at initialization.

Here’s what’s inside.

Highlights at a Glance

    • Full TypeScript support — Helps catch mistakes at compile-time, not in production
    • Resource-based API designdwolla.transfers.create() with full IntelliSense
    • 180+ typed error classes — Handle failures precisely with InsufficientFundsError, ValidationError, etc.
    • Generated from OpenAPI — Regularly updated with comprehensive coverage of 80+ operations

Getting Started

Install the SDK with your preferred package manager:

npm install dwolla
# or: yarn add dwolla | pnpm add dwolla | bun add dwolla

Initialize the client and make your first call:

import { Dwolla } from "dwolla";

const dwolla = new Dwolla({
server: "simport { Dwolla } from "dwolla";

const dwolla = new Dwolla({
  server: "sandbox",
  security: {
    clientID: process.env.DWOLLA_CLIENT_ID!,
    clientSecret: process.env.DWOLLA_CLIENT_SECRET!,
  },
});

// List customers
const customers = await dwolla.customers.list({});
console.log(`Found ${customers._embedded?.customers?.length ?? 0}
customers`);

For the complete walkthrough (Sandbox account setup, credentials, environment configuration, and more) see the TypeScript SDK documentation.

What You Get

Type Safety That Catches Mistakes Early

Requests, responses, and errors have comprehensive type definitions. Typos become compile errors instead of production bugs.

Image: TypeScript catching an invalid Dwolla SDK request at compile time in IntelliJ IDEA.

What this means for you:

  • Required fields are enforced at compile-time
  • Response shapes are known. No more ”undefined is not an object” errors
  • Refactoring is safer: Update the SDK, and TypeScript shows affected call sites where types change

Resource-Based API Design for Faster Development

Methods are organized by resources with full IntelliSense. Type ”dwolla.” and explore available operations. No memorizing endpoint paths or tab-switching to docs.

Image: TypeScript autocomplete in IntelliJ IDEA showing available Dwolla SDK resources

What this means for you:

  • Autocomplete shows what's available as you type
  • Hover over any method to see exactly what it expects
  • Onboard new developers faster with discoverable APIs

Automatic OAuth2 Token Management

Provide credentials once at initialization. The SDK acquires and refreshes tokens automatically. No boilerplate token refresh logic cluttering your codebase.

180+ Typed Error Classes for Precise Handling

Catch and handle specific failures instead of parsing error messages with regex.

import * as errors from "dwolla/models/errors";
try {
  await dwolla.transfers.create({ /* ... */ });
} catch (error) {
  if (error instanceof errors.InsufficientFundsError) {
    // Prompt user to add funds
  } else if (error instanceof errors.ValidationError) {
    // Show field-level errors
  } else if (error instanceof errors.DwollaError) {
    console.error(`${error.statusCode}: ${error.message}`);
  }
}

What this means for you:

  • Handle different failure modes with type-safe conditionals
  • Access structured error data (statusCode, message, full response body)

And More

  • Built-in retries — Transient failures are handled automatically with exponential backoff
  • Tree-shakable for serverless — Import only what you need for smaller bundles
  • Multi-runtime support — Works in Node.js, Bun, Deno, and modern browsers
  • File uploads — Upload documents for customer verification using streams or blobs
  • Custom HTTP hooks — Inject headers, log requests, or modify behavior with beforeRequest and requestError hooks
  • Debug logging — Set DWOLLA_DEBUG=true to enable request and response logging

Why Use the TypeScript SDK?

Here's how it compares to the alternatives.

vs. Direct API Calls

You can always call the Dwolla API directly using fetch or any HTTP client. It works, but you're responsible for:

  • Token management — Obtaining tokens, tracking expiration, refreshing before they expire
  • Header construction — Getting Content-Type and Accept headers exactly right
  • Error handling — Parsing error responses and determining what went wrong
  • Retries — Implementing backoff logic for transient failures
  • Type safety — None. Typos in the request body compile just fine.

 

Aspect

Direct API Calls

TypeScript SDK

Type Safety

None

Full compile-time checking

Autocomplete

None

Full IntelliSense

Token Management

Manual

Automatic

Error Handling

Parse JSON, check status codes

Typed error classes

Retries

Build it yourself

Built-in

Documentation

Tab-switch to docs

Inline types + JSDoc

Here's the same operation—creating a customer—with raw fetch vs. the SDK:

// Direct API call (fetch)
const token = await getToken(); // You manage this
const res = await fetch("https://api-sandbox.dwolla.com/customers", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/vnd.dwolla.v1.hal+json",
    Accept: "application/vnd.dwolla.v1.hal+json",
  },
body: JSON.stringify({ firstName: "Jane", lastName: "Doe", email:
"jane@example.com" }),
});

// TypeScript SDK
import { Dwolla } from "dwolla";

const dwolla = new Dwolla({
  security: {
    clientID: process.env.DWOLLA_CLIENT_ID!,
    clientSecret: process.env.DWOLLA_CLIENT_SECRET!,
  },
});

await dwolla.customers.create({
requestBody: { firstName: "Jane", lastName: "Doe", email:
"jane@example.com" },
});

When to use direct calls: If you're making a single API call in a script or have very specific HTTP requirements the SDK doesn't support, direct calls might be simpler.

When to use the SDK: For any integration beyond a one-off script, especially in production applications where reliability and maintainability matter.

vs. dwolla-v2-node

The dwolla-v2-node package has been the official Node.js SDK for years. It's stable and works well. If you have an existing integration with it, there's no urgent need to migrate.
That said, the new TypeScript SDK offers significant improvements for TypeScript users.
The difference is visible even in a single call:

// dwolla-v2-node
const res = await client.post("customers", { firstName: "Jane", lastName:
"Doe", email: "jane@example.com" });
const location = res.headers.get("location"); // Untyped

// TypeScript SDK
const res = await dwolla.customers.create({
  requestBody: { firstName: "Jane", lastName: "Doe", email:
"jane@example.com" },
});
const location = res.location; // Typed string

As your integration grows, the benefits compound:

Aspect

dwolla-v2-node

TypeScript SDK

API Style

Generic HTTP methods (client.post("customers"))

Resource methods (dwolla.customers.create())

Type Safety

Basic (added via DefinitelyTyped)

First-class, generated from OpenAPI

Request Bodies

Untyped object

Typed interfaces per operation

Responses

Generic wrapper

Typed models per operation

Errors

Generic error object

180+ specific error classes

Bundle Size

Full SDK

Tree-shakable standalone functions

Maintenance

Hand-maintained

Auto-generated from OpenAPI spec

Key differences in practice:

  1. Discoverability. With dwolla-v2-node, you need to know the endpoint path ("customers", "transfers", etc.). With the TypeScript SDK, autocomplete shows available methods like dwolla.customers and dwolla.transfers.
  2. Type checking. In dwolla-v2-node, nothing stops you from passing { fristName: "Jane" }. In the TypeScript SDK, that's a compile error.
  3. Error handling. dwolla-v2-node throws a generic error. The TypeScript SDK throws InsufficientFundsError, ValidationError, or one of 180+ specific types you can catch individually.
  4. Staying current. The TypeScript SDK is generated from Dwolla's OpenAPI spec, so new endpoints appear automatically. dwolla-v2-node requires manual updates.

Migration Path

If you're using dwolla-v2-node today:

  • No rush. Your existing integration will continue to work.
  • Incremental migration. Both SDKs can coexist. You can adopt the TypeScript SDK for new features while keeping existing code on dwolla-v2-node.
  • Same credentials. Both SDKs use the same API keys and OAuth flow. No credential changes needed.

For new projects, we recommend starting with the TypeScript SDK to take advantage of the improved developer experience.

In Practice

We invited developers to test the TypeScript SDK during beta. Here's what they said:

"The developer experience feels great—the type safety and auto-completion are exactly what we were hoping for. The SDK structure, type definitions, and overall API feel very intuitive. This will be a huge improvement for TypeScript developers working with Dwolla." — Davidson Nascimento, Co-Founder/CTO at Cleo Pay

Get Started Today

The Dwolla TypeScript SDK is designed to make payment integration faster, safer, and less frustrating. With full type safety, automatic token management, and typed error handling, you can focus on building your product instead of wrestling with API mechanics.

Try it in 5 minutes:

Install with npm install dwolla, copy the Getting Started example, and run your first type-safe API call. Then tell us what you think on the developer forum or open an issue on Github if you run into any problems.

Resources

Everything you need to get started and go deeper.

Happy building!