brapi-ruby-sdk

CI Gem Version Downloads License Ruby

Ruby SDK for the brapi.dev API — Brazilian stock market quotes, cryptocurrencies, currency exchange rates, inflation (IPCA) and prime rate (SELIC) data.

This SDK provides parity with the official brapi TypeScript and brapi Python SDKs, covering 11 endpoints in v0.1.

Installation

Add this line to your application's Gemfile:

gem "brapi-ruby-sdk"

And then execute:

bundle install

Or install it yourself:

gem install brapi-ruby-sdk

The gem package is brapi-ruby-sdk but you still require "brapi" and call Brapi.* in code.

Requires Ruby >= 3.1.

Quickstart

Get a free token from brapi.dev/dashboard (four assets — PETR4, MGLU3, VALE3, ITUB4 — work without authentication for testing).

require "brapi"

Brapi.configure do |c|
  c.token = ENV.fetch("BRAPI_TOKEN")
end

response = Brapi.quote.retrieve("PETR4")
puts response.results.first.regular_market_price # => 36.65
puts response.results.first.symbol               # => "PETR4"

Configuration

Global

Brapi.configure do |c|
  c.token        = ENV.fetch("BRAPI_TOKEN")
  c.base_url     = "https://brapi.dev"     # default
  c.timeout      = 30                      # seconds
  c.open_timeout = 10                      # seconds
  c.user_agent   = "my-app/1.0"            # default: "brapi-ruby-sdk/<VERSION>"
  c.adapter      = nil                     # Faraday adapter (e.g. :net_http, :test)
end

# Call via singleton:
Brapi.quote.retrieve("PETR4")
Brapi.v2.crypto.retrieve(coin: "BTC")

Per-instance

For multi-tenant apps or testing, create a Brapi::Client directly:

client = Brapi::Client.new(token: "my-token", timeout: 5)
client.quote.retrieve("PETR4")

Available methods

Method HTTP Description
client.quote.retrieve(tickers, ...) GET /api/quote/{tickers} Stock quote (single or comma-separated)
client.quote.list(...) GET /api/quote/list List/filter all available stocks
client.available.list(...) GET /api/available List of available tickers/indexes
client.v2.crypto.retrieve(...) GET /api/v2/crypto Cryptocurrency quotes
client.v2.crypto.list_available(...) GET /api/v2/crypto/available Available cryptocurrencies
client.v2.currency.retrieve(...) GET /api/v2/currency Currency exchange quotes (USD-BRL etc)
client.v2.currency.list_available(...) GET /api/v2/currency/available Available currency pairs
client.v2.inflation.retrieve(...) GET /api/v2/inflation Inflation/IPCA series
client.v2.inflation.list_available GET /api/v2/inflation/available Countries with inflation data
client.v2.prime_rate.retrieve(...) GET /api/v2/prime-rate SELIC / prime-rate series
client.v2.prime_rate.list_available GET /api/v2/prime-rate/available Countries with prime-rate data
client.v2.fii.list(...) GET /api/v2/fii/list Real Estate Funds (FIIs) listing
client.v2.fii.indicators(syms, ...) GET /api/v2/fii/indicators FII indicators (NAV, dividend yield)
client.v2.fii.historical(syms, ...) GET /api/v2/fii/historical FII OHLCV historical prices
client.v2.fii.dividends(syms, ...) GET /api/v2/fii/dividends FII dividend payment history
client.v2.macro.retrieve(syms, ...) GET /api/v2/macro Macro time series (SELIC, IPCA, CDI…)
client.v2.macro.list_available GET /api/v2/macro/available Available macro series
client.v2.treasury.list(...) GET /api/v2/treasury/list Tesouro Direto bonds listing
client.v2.treasury.indicators(syms…) GET /api/v2/treasury/indicators Current rates / prices for bonds

All params are passed as Ruby kwargs (snake_case) and the SDK converts them to the camelCase expected by the API (e.g. sort_by: "volume"?sortBy=volume).

Examples

Stock quote with modules

resp = Brapi.quote.retrieve(
  "PETR4",
  range: "1mo",
  interval: "1d",
  modules: "summaryProfile,financialData",
  dividends: true
)

quote = resp.results.first
quote.symbol                       # => "PETR4"
quote.regular_market_price         # => 36.65
quote.regular_market_change_percent # => -0.95
quote.market_cap                   # => 483937892568
quote.fifty_two_week_range         # => "28.86 - 38.66"
quote.financial_data               # => Brapi::Models::FinancialDataEntry
quote.summary_profile              # => Brapi::Models::SummaryProfile
quote.summary_profile.industry     # => "Petróleo e Gás Integrado"
quote.default_key_statistics       # => Brapi::Models::KeyStatisticsEntry
quote.income_statement_history     # => [Brapi::Models::IncomeStatementEntry]
quote.cashflow_history             # => [Brapi::Models::CashflowEntry]
quote.value_added_history          # => [Brapi::Models::ValueAddedEntry]
quote.historical_data_price        # => [Brapi::Models::HistoricalDataPrice]
quote.dividends_data               # => Brapi::Models::DividendsData (cash + stock + subscriptions)

Multi-ticker

resp = Brapi.quote.retrieve(%w[PETR4 VALE3 MGLU3 ITUB4])
resp.results.each { |q| puts "#{q.symbol}: R$ #{q.regular_market_price}" }

Cryptocurrencies

resp = Brapi.v2.crypto.retrieve(coin: "BTC,ETH", currency: "BRL")
resp.coins.each { |c| puts "#{c.coin}: R$ #{c.regular_market_price}" }

Currency exchange

resp = Brapi.v2.currency.retrieve(currency: "USD-BRL,EUR-BRL,GBP-BRL")
resp.currency.each { |c| puts "#{c.from_currency}-#{c.to_currency}: #{c.bid_price}" }

Inflation (IPCA)

resp = Brapi.v2.inflation.retrieve(country: "brazil", historical: true)
resp.inflation.each { |i| puts "#{i.date}: #{i.value}%" }

Prime rate (SELIC)

resp = Brapi.v2.prime_rate.retrieve(country: "brazil")
resp.prime_rate.each { |p| puts "#{p.date}: #{p.value}% p.a." }

Real Estate Funds (FIIs)

# Browse FIIs with pagination
page = Brapi.v2.fii.list(limit: 20)
page.fiis.each { |f| puts "#{f.symbol} (#{f.segmento_atuacao}): R$ #{f.price}" }
puts "Page #{page.pagination.page}/#{page.pagination.total_pages}"

# Current indicators for specific FIIs
ind = Brapi.v2.fii.indicators(%w[MXRF11 KNRI11])
ind.fiis.each { |f| puts "#{f.symbol} NAV=#{f.nav_per_share} DY12m=#{f.dividend_yield12m}" }

# Dividend history
divs = Brapi.v2.fii.dividends("MXRF11")
divs.dividends.each { |d| puts "#{d.payment_date}: R$ #{d.rate}" }

Macro time series (SELIC, IPCA, CDI...)

resp = Brapi.v2.macro.retrieve("SELIC")
result = resp.results.first
puts "#{result.series.name} (#{result.series.unit})"
result.observations.each { |o| puts "#{o.date}: #{o.value}" }

# List available series
Brapi.v2.macro.list_available.results.each { |s| puts "#{s.slug}: #{s.name}" }

Tesouro Direto (Treasury)

# Browse available bonds
page = Brapi.v2.treasury.list
page.results.each do |bond|
  puts "#{bond.symbol}: buy=#{bond.buy_rate}% sell_price=R$ #{bond.sell_price}"
  puts "  Rate interpretation: #{bond.rate_info.description}"
end

# Current rates for specific bonds
Brapi.v2.treasury.indicators("tesouro-selic-01032031")

List/filter stocks

resp = Brapi.quote.list(sort_by: "volume", sort_order: "desc", limit: 10, sector: "Energy")
resp.stocks.each { |s| puts "#{s.stock} (#{s.name}): R$ #{s.close}" }
puts "Page #{resp.current_page}/#{resp.total_pages}"

Auto-pagination

Every paginated resource (client.quote.list, client.v2.fii.list, client.v2.treasury.list) gains #each_page, #each and the full Ruby Enumerable surface:

# Yield each row across all pages — lazy by default, stops when
# the API reports has_next_page = false.
Brapi.v2.fii.each { |f| puts "#{f.symbol}: DY12m=#{f.dividend_yield12m}" }

# Or yield one page at a time:
Brapi.v2.treasury.each_page(max_pages: 5) do |page|
  puts "Page #{page.pagination.page}/#{page.pagination.total_pages}"
end

# Enumerable methods Just Work — `each` without a block returns
# an Enumerator, so you can use first/select/lazy/etc.:
top_yield = Brapi.v2.fii
  .first(100)
  .sort_by { |f| -(f.dividend_yield12m || 0) }
  .first(5)

ipca_bonds = Brapi.v2.treasury
  .lazy
  .select { |b| b.indexer == "ipca" }
  .first(10)

# Custom params pass through to the underlying `list` call:
Brapi.quote.each(sort_by: "volume", sort_order: "desc") { |s| ... }

max_pages: (default 10_000) caps the walk in case the upstream forgets to signal the end. page: lets you start from a specific page.

count and size take a fast path: they fetch only the first page and read pagination.total_items (or item_count on Quote), so Brapi.v2.fii.count is one HTTP call, not 81. Pass a block to count when you want Enumerable filtering semantics — that still walks every page, as expected.

Error handling

All errors inherit from Brapi::Error:

begin
  Brapi.quote.retrieve("UNKNOWN")
rescue Brapi::AuthenticationError => e
  warn "Bad or missing token: #{e.message}"
rescue Brapi::RateLimitError => e
  warn "Rate limited; retry after #{e.retry_after}s"
rescue Brapi::NotFoundError
  warn "Ticker not found"
rescue Brapi::ServerError => e
  warn "brapi.dev outage (HTTP #{e.status})"
rescue Brapi::Error => e
  warn "Other API error: #{e.message}"
end
Exception Status
Brapi::BadRequestError 400
Brapi::AuthenticationError 401
Brapi::PaymentRequiredError 402
Brapi::PermissionDeniedError 403
Brapi::NotFoundError 404
Brapi::RateLimitError 429
Brapi::ServerError 5xx
Brapi::ConnectionError Network
Brapi::Error base class

Each error exposes #status, #response_body, and #raw_response. RateLimitError also has #retry_after.

The SDK automatically retries transient 5xx errors (502/503/504) up to twice with exponential backoff.

Roadmap

v0.1 shipped the 11 endpoints supported by the official SDKs. v0.2 added typed models for every Quote fundamental module. v0.3 added FIIs, Macro and Tesouro Direto. Future minor versions:

  • client.v2.options.* — Options chain & history
  • client.v2.futures.* — Futures contracts

Development

bin/setup            # bundle install
bundle exec rspec    # tests
bundle exec rubocop  # lint
bin/console          # IRB with brapi loaded

License

Apache-2.0. See LICENSE.

Disclaimer

This is an unofficial community SDK. For official SDKs, see brapi-dev on GitHub.