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 design — dwolla.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:
- 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.
- Type checking. In dwolla-v2-node, nothing stops you from passing { fristName: "Jane" }. In the TypeScript SDK, that's a compile error.
- 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.
- 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.
- NPM Package - Download the SDK via NPM
- SDK Documentation - Full API reference and examples
- Developer Docs - Guides, concepts, and API reference
- Sandbox Dashboard - Manage test data and view transfers
Happy building!