Ruby wrapper for the Coinbase API
Ruby Shell

README.md

Coinbase Wallet Gem

This is the official client library for the Coinbase Wallet API v2. We provide an intuitive, stable interface to integrate Coinbase Wallet into your Ruby project.

Important: As this library is targeted for newer API v2, it requires v2 permissions (i.e. wallet:accounts:read). If you're still using v1, please use older version of this library.

Installation

Add this line to your application's Gemfile:

gem 'coinbase'

Then execute:

bundle install

Or install it yourself as:

gem install coinbase

Authentication

API Key (HMAC Client)

We provide a synchronous client based on Net::HTTP as well as a asynchronous client based on the EM-HTTP-Request gem. For most users, the synchronous client will suffice.

require 'coinbase/wallet'
client = Coinbase::Wallet::Client.new(api_key: <api key>, api_secret: <api secret>)

The primary intention of the asynchronous client is to integrate nicely with the Coinbase Exchange Gem. If your project interfaces with our Exchange as well, please consider using this. To use this interface, you must include em-http-request gem on your own.

require 'coinbase/wallet'
require 'em-http'

client = Coinbase::Wallet::AsyncClient.new(api_key: <api_key>, api_secret: <api secret>)

OAuth2 Client

We provide an OAuth client if you need access to user accounts other than your own. Currently, the gem does not handle the handshake process, and assumes you have an access token when it's initialized. The OAuth client is synchronous. Please reach out if you would like us to add an asynchronous OAuth client as well.

require 'coinbase/wallet'

# Initializing OAuthClient with both access and refresh token
client = Coinbase::Wallet::OAuthClient.new(access_token: <access token>, refresh_token: <refresh_token>)

# Initializing OAuthClient with only access token
client = Coinbase::Wallet::OAuthClient.new(access_token: <access token>)

The OAuth client provides a few extra methods to refresh and revoke the access token.

client.refresh!
client.revoke!

Protip™️: You can test OAuth2 authentication easily with Developer Access Tokens which can be created under your OAuth2 application settings. These are short lived tokens which authenticate but don't require full OAuth2 handshake to obtain.

Two factor authentication

Send money endpoint requires 2FA token in certain situations (read more here). Specific exception is thrown when this is required:

account = client.primary_account
begin
  account.send(to: 'test@test.com', amount: '1', currency: "BTC")
rescue Coinbase::Client::TwoFactorRequiredError
  # Show 2FA dialog to user and collect 2FA token

  # Re-try call with `two_factor_token` param
  account.send(to: 'test@test.com', amount: '1', currency: "BTC", two_factor_token: "123456")
end

Requests

We provide one method per API endpoint. Several methods require one or more identifiers to be passed as arguments. Additionally, all parameters can be appended as keyword arguements. If a required parameter is not supplied, the client will raise an error. For instance, the following call will send 100 bitcoin to the account registered with example@coinbase.com.

account = client.primary_account
account.send(to: 'example@coinbase.com', amount: 100, currency: "USD", description: 'Sending 100 bitcoin')

Pagination

Several endpoints are paginated. By default, the gem will only fetch the first page of data for a given request. You can implement your own pagination scheme, such as pipelining, by setting the starting_after parameter in your response.

client.transactions(account_id) do |data, resp|
  transactions = data
end

more_pages = true
while more_pages
  client.transactions(account_id, starting_after: transactions.last['id']) do |data, resp|
    more_pages = resp.has_more?
    transactions << data
    transactions.flatten!
  end
end

If you want to automatically download the entire dataset, you may pass fetch_all=true as a parameter.

client.transactions(account_id, fetch_all: true) do |data, resp|
  ...
end

Responses

We provide several ways to access return data. Methods will return the data field of the response in hash format.

txs = account.transactions(account_id)
txs.each do |tx|
  p tx['id']
end

You can also handle data inside a block you pass to the method. You must access data this way if you're using the asynchronous client.

account.transactions(account_id) do |txs|
  txs.each { |tx| p tx['id'] }
end

If you need to access the response metadata (headers, pagination info, etc.) you can access the entire response as the second block paramenter.

account.transactions(account_id) do |txs, resp|
  p "STATUS: #{resp.status}"
  p "HEADERS: #{resp.headers}"
  p "BODY: #{resp.body}"
end

Response Object

The default representation of response data is a JSON hash. However, we further abstract the response to allow access to response fields as though they were methods.

account = client.primary_account
p "Account:\t account.name"
p "ID:\t account.id"
p "Balance:\t #{account.balance.amount} #{account.balance.currency}"

All values are returned directly from the API unmodified, except the following exceptions:

  • Money amounts are always converted into BigDecimal objects. You should always use BigDecimal when handing bitcoin amounts for accurate presicion
  • Timestamps are always converted into Time objects

Most methods require an associated account. Thus, responses for the account endpoints contain methods for accessing all the relevant endpoints. This is convient, as it doesn't require you to supply the same account id over and over again.

account = client.primary_account
account.send(to: "example@coinbase.com", amount: 100, description: "Sending 100 bitcoin")

Alternatively you can pass the account ID straight to the client:

client.transactions(<account_id>)

Account response objects will automatically update if they detect any changes to the account. The easiest way to refresh an account is to call the refresh! method.

account.refresh!

Warnings

It's prudent to be conscious of warnings. By default, the gem will print all warning to STDERR. If you wish to redirect this stream to somewhere else, such as a log file, then you can simply change the $stderr global variable.

Errors

If the request is not successful, the gem will raise an error. We try to raise a unique error for every possible API response. All errors are subclasses of Coinbase::Wallet::APIError.

Error Status
APIError *
BadRequestError 400
ParamRequiredError 400
InvalidRequestError 400
PersonalDetailsRequiredError 400
AuthenticationError 401
UnverifiedEmailError 401
InvalidTokenError 401
RevokedTokenError 401
ExpiredTokenError 401
TwoFactorRequiredError 402
InvalidScopeError 403
NotFoundError 404
ValidationError 422
RateLimitError 429
InternalServerError 500
ServiceUnavailableError 503

Usage

This is not intended to provide complete documentation of the API. For more detail, please refer to the official documentation.

###Market Data

List supported native currencies

client.currencies

List exchange rates

client.exchange_rates

Buy price

client.buy_price
# or
client.buy_price(currency: 'BTC-USD')

Sell price

client.sell_price
# or
client.sell_price(currency: 'ETH-BTC')

Spot price

client.spot_price
# or
client.spot_price(currency: 'BTC-EUR')

Current server time

client.time

###Users

Get authorization info

client.auth_info

Lookup user info

client.user(user_id)

Get current user

client.current_user

Update current user

client.update_current_user(name: "New Name")

###Accounts

List all accounts

client.accounts

List account details

client.account(account_id)

List primary account details

client.primary_account

Set account as primary

account.make_primary!

Create a new bitcoin account

client.create_account(name: "New Account")

Update an account

account.update!(name: "New Account Name")

Delete an account

account.delete!

###Addresses

List receive addresses for account

account.addresses

Get receive address info

account.address(address_id)

List transactiona for address

account.address_transactions(address_id)

Create a new receive address

account.create_address

###Transactions

List transactions

account.transactions

Get transaction info

account.transaction(transaction_id)

Send funds

account.send(to: <bitcoin address>, amount: "5.0", currency: "USD", description: "Your first bitcoin!")

Transfer funds to a new account

account.transfer(to: <account ID>, amount: "1", currency: "BTC", description: "Your first bitcoin!")

Request funds

account.request(to: <email>, amount: "8.0", currency: "USD", description: "Burrito")

Resend request

account.resend_request(request_id)

Cancel request

account.cancel_request(request_id)

Fulfill request

account.complete_request(request_id)

###Buys

List buys

account.list_buys

Get buy info

account.list_buy(buy_id)

Buy bitcoins

account.buy(amount: "1", currency: "BTC")

Commit a buy

You only need to do this if you pass commit=true when you call the buy method.

buy = account.buy(amount: "1", currency: "BTC", commit: false)
account.commit_buy(buy.id)

###Sells

List sells

account.list_sells

Get sell info

account.list_sell(sell_id)

Sell bitcoins

account.sell(amount: "1", currency: "BTC")

Commit a sell

You only need to do this if you pass commit=true when you call the sell method.

sell = account.sell(amount: "1", currency: "BTC", commit: false)
account.commit_sell(sell.id)

###Deposit

List deposits

account.list_deposits

Get deposit info

account.list_deposit(deposit_id)

Deposit funds

account.deposit(amount: "10", currency: "USD")

Commit a deposit

You only need to do this if you pass commit=true when you call the deposit method.

deposit = account.deposit(amount: "1", currency: "BTC", commit: false)
account.commit_deposit(deposit.id)

###Withdrawals

List withdrawals

account.list_withdrawals

Get withdrawal

account.list_withdrawal(withdrawal_id)

Withdraw funds

account.withdraw(amount: "10", currency: "USD")

Commit a withdrawal

You only need to do this if you pass commit=true when you call the withdrawal method.

withdraw = account.withdraw(amount: "1", currency: "BTC", commit: false)
account.commit_withdrawal(withdrawal.id)

###Payment Methods

List payment methods

client.payment_methods

Get payment method

client.payment_method(payment_method_id)

###Merchants

Get merchant

client.merchant(merchant_id)

Verify a merchant callback

client.verify_callback(request.raw_post, request.headers['CB-SIGNATURE']) # true/false

###Orders

List orders

client.orders

Get order

client.order(order_id)

Create order

client.create_order(amount: "1", currency: "BTC", name: "Order #1234")

Refund order

order = client.orders.first
order.refund!

Checkouts

List checkouts

client.checkouts

Get checkout

client.checkout(checkout_id)

Get checkout's orders

checkout = client.checkout(checkout_id)
checkout.orders

Create order for checkout

checkout = client.checkout(checkout_id)
checkout.create_order

Contributing and testing

Any and all contributions are welcome! The process is simple: fork this repo, make your changes, add tests, run the test suite, and submit a pull request. Tests are run via rspec. To run the tests, clone the repository and then:

# Install the requirements
gem install coinbase

# Run tests
rspec spec