Official Ruby Wrapper for Dwolla's API v2
Ruby Shell
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.


Build Status

Dwolla V2 Ruby client.

API Documentation


Add this line to your application's Gemfile:

gem 'dwolla_v2', '~> 2.0'

And then execute:

$ bundle

Or install it yourself as:

$ gem install dwolla_v2


Basic usage

Create a client using your application's consumer key and secret found on the applications page (Sandbox, Production).

# config/initializers/dwolla.rb
$dwolla = ENV["DWOLLA_APP_KEY"], secret: ENV["DWOLLA_APP_SECRET"])

Using the sandbox environment (optional)

# config/initializers/dwolla.rb
$dwolla = ENV["DWOLLA_APP_KEY"], secret: ENV["DWOLLA_APP_SECRET"]) do |config|
  config.environment = :sandbox

environment= defaults to :production and accepts either a String or a Symbol.

Configure an on_grant callback (optional)

An on_grant callback is useful for storing new tokens when they are granted. For example, you may have a YourTokenData ActiveRecord model that you use to store your tokens. The on_grant callback is called with the DwollaV2::Token that was just granted by the server. You can pass this to the create! method of an ActiveRecord model to create a record using the token's data.

# config/initializers/dwolla.rb
$dwolla = ENV["DWOLLA_APP_KEY"], secret: ENV["DWOLLA_APP_SECRET"]) do |config|
  config.on_grant {|t| YourTokenData.create!(t) }

It is highly recommended that you encrypt any token data you store using attr_encrypted or vault-rails (if you use Vault). These are both configured in your ActiveRecord models.

Configure Faraday (optional)

DwollaV2 uses Faraday to make HTTP requests. You can configure your own Faraday middleware and adapter when configuring your client. Remember to always include an adapter last, even if you want to use the default adapter.

# config/initializers/dwolla.rb
$dwolla = ENV["DWOLLA_APP_KEY"], secret: ENV["DWOLLA_APP_SECRET"]) do |config|
  config.faraday do |faraday|
    faraday.response :logger
    faraday.adapter Faraday.default_adapter


Tokens can be used to make requests to the Dwolla V2 API.

Application tokens

Application access tokens are used to authenticate against the API on behalf of a consumer application. Application tokens can be used to access resources in the API that either belong to the application itself (webhooks, events, webhook-subscriptions) or the partner Account that owns the consumer application (accounts, customers, funding-sources, etc.). Application tokens are obtained by using the client_credentials OAuth grant type:

application_token = $dwolla.auths.client
# => #<DwollaV2::Token client=#<DwollaV2::Client key="..." secret="..." environment=:sandbox> access_token="..." expires_in=3600 scope="...">

Application tokens do not include a refresh_token. When an application token expires, generate a new one using $dwolla.auths.client.

Initializing a pre-existing access token:

DwollaV2::Tokens can be initialized with the following attributes:

$ access_token: "...",
                   expires_in: 123
#<DwollaV2::Token client=#<DwollaV2::Client key="..." secret="..." environment=:sandbox> access_token="..." expires_in=123>
token_data = YourTokenData.first


DwollaV2::Tokens can make requests using the #get, #post, #put, and #delete methods.

token.get "resource", foo: "bar"

# POST {"foo":"bar"} "resource", foo: "bar"

# POST multipart/form-data foo=... "resource", foo:"/path/to/bar.png", "image/png")

# PUT {"foo":"bar"}
token.put "resource", foo: "bar"

token.delete "resource"

Requests can also be made in parallel:

foo, bar = nil
token.in_parallel do
  foo = token.get "/foo"
  bar = token.get "/bar"
puts foo # only ready after `in_parallel` block has executed
puts bar # only ready after `in_parallel` block has executed

Setting headers

To set additional headers on a request you can pass a Hash of headers as the 3rd argument.

For example: "customers", { firstName: "John", lastName: "Doe", email: "" },
                        { 'Idempotency-Key': 'a52fcf63-0730-41c3-96e8-7147b5d1fb01' }


Requests return a DwollaV2::Response.

res = token.get "/"
# => #<DwollaV2::Response response_status=200 response_headers={"server"=>"cloudflare-nginx", "date"=>"Mon, 28 Mar 2016 15:30:23 GMT", "content-type"=>"application/vnd.dwolla.v1.hal+json; charset=UTF-8", "content-length"=>"150", "connection"=>"close", "set-cookie"=>"__cfduid=d9dcd0f586c166d36cbd45b992bdaa11b1459179023; expires=Tue, 28-Mar-17 15:30:23 GMT; path=/;; HttpOnly", "x-request-id"=>"69a4e612-5dae-4c52-a6a0-2f921e34a88a", "cf-ray"=>"28ac1f81875941e3-MSP"} {"_links"=>{"events"=>{"href"=>""}, "webhook-subscriptions"=>{"href"=>""}}}>

# => 200

# => {"server"=>"cloudflare-nginx", "date"=>"Mon, 28 Mar 2016 15:30:23 GMT", "content-type"=>"application/vnd.dwolla.v1.hal+json; charset=UTF-8", "content-length"=>"150", "connection"=>"close", "set-cookie"=>"__cfduid=d9dcd0f586c166d36cbd45b992bdaa11b1459179023; expires=Tue, 28-Mar-17 15:30:23 GMT; path=/;; HttpOnly", "x-request-id"=>"69a4e612-5dae-4c52-a6a0-2f921e34a88a", "cf-ray"=>"28ac1f81875941e3-MSP"}
# => ""


If the server returns an error, a DwollaV2::Error (or one of its subclasses) will be raised. DwollaV2::Errors are similar to DwollaV2::Responses.

  token.get "/not-found"
rescue DwollaV2::NotFoundError => e
  # => #<DwollaV2::NotFoundError response_status=404 response_headers={"server"=>"cloudflare-nginx", "date"=>"Mon, 28 Mar 2016 15:35:32 GMT", "content-type"=>"application/vnd.dwolla.v1.hal+json; profile=\"\"; charset=UTF-8", "content-length"=>"69", "connection"=>"close", "set-cookie"=>"__cfduid=da1478bfdf3e56275cd8a6a741866ccce1459179332; expires=Tue, 28-Mar-17 15:35:32 GMT; path=/;; HttpOnly", "access-control-allow-origin"=>"*", "x-request-id"=>"667fca74-b53d-43db-bddd-50426a011881", "cf-ray"=>"28ac270abca64207-MSP"} {"code"=>"NotFound", "message"=>"The requested resource was not found."}>

  # => 404

  # => {"server"=>"cloudflare-nginx", "date"=>"Mon, 28 Mar 2016 15:35:32 GMT", "content-type"=>"application/vnd.dwolla.v1.hal+json; profile=\"\"; charset=UTF-8", "content-length"=>"69", "connection"=>"close", "set-cookie"=>"__cfduid=da1478bfdf3e56275cd8a6a741866ccce1459179332; expires=Tue, 28-Mar-17 15:35:32 GMT; path=/;; HttpOnly", "access-control-allow-origin"=>"*", "x-request-id"=>"667fca74-b53d-43db-bddd-50426a011881", "cf-ray"=>"28ac270abca64207-MSP"}

  # => "NotFound"
rescue DwollaV2::Error => e
  # ...

DwollaV2::Error subclasses:

See for more info.

  • DwollaV2::AccessDeniedError
  • DwollaV2::InvalidCredentialsError
  • DwollaV2::NotFoundError
  • DwollaV2::BadRequestError
  • DwollaV2::InvalidGrantError
  • DwollaV2::RequestTimeoutError
  • DwollaV2::ExpiredAccessTokenError
  • DwollaV2::InvalidRequestError
  • DwollaV2::ServerError
  • DwollaV2::ForbiddenError
  • DwollaV2::InvalidResourceStateError
  • DwollaV2::TemporarilyUnavailableError
  • DwollaV2::InvalidAccessTokenError
  • DwollaV2::InvalidScopeError
  • DwollaV2::UnauthorizedClientError
  • DwollaV2::InvalidAccountStatusError
  • DwollaV2::InvalidScopesError
  • DwollaV2::UnsupportedGrantTypeError
  • DwollaV2::InvalidApplicationStatusError
  • DwollaV2::InvalidVersionError
  • DwollaV2::UnsupportedResponseTypeError
  • DwollaV2::InvalidClientError
  • DwollaV2::MethodNotAllowedError
  • DwollaV2::ValidationError
  • DwollaV2::TooManyRequestsError
  • DwollaV2::ConflictError

Sample code

The following gist contains some sample bootstrapping code:

If you have any questions regarding your specific implementation we'll do our best to help at


After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to


Bug reports and pull requests are welcome on GitHub at


The gem is available as open source under the terms of the MIT License.


  • 2.2.0 - Change token url from to
  • 2.1.0 - Ensure Time.iso8601 is defined so timestamps get parsed. #38 (Thanks @javierjulio!)
  • 2.0.3 - Add DuplicateResourceError #34 (Thanks @javierjulio!)
  • 2.0.2 - Fix bug in #30 (Thanks again @sobrinho!)
  • 2.0.1 - Fix bugs in #27 + #28 (Thanks @sobrinho!)
  • 2.0.0
  • Rename DwollaV2::Response #status => #response_status, #headers => #response_headers to prevent conflicts with response body properties.
  • Remove support for Ruby versions < 2 (Bump public_suffix dependency version).
  • 1.2.3 - Implement #empty? on DwollaV2::Token to allow it to be passed to ActiveRecord constructor.
  • 1.2.2 - Strip domain from URLs provided to token.* methods.
  • 1.2.1 - Update sandbox URLs from uat => sandbox.
  • 1.2.0 - Refer to Client :id as :key in docs/public APIs for consistency.
  • 1.1.2 - Add support for verified_account and dwolla_landing auth flags.
  • 1.1.1 - Add TooManyRequestsError and ConflictError classes.
  • 1.1.0 - Support setting headers on a per-request basis.
  • 1.0.1 - Set user agent header.
  • 1.0.0 - Refactor Error class to be more like response, add ability to access keys using methods.
  • 0.4.0 - Refactor and document how DwollaV2::Response works
  • 0.3.1 - better DwollaV2::Error error messages
  • 0.3.0 - ISO8601 values in response body are converted to Time objects
  • 0.2.0 - Works with attr_encrypted
  • 0.1.1 - Handle 500 error with HTML response body when requesting a token