0.0
The project is in a healthy, maintained state
Financial news with sentiment analysis, entity recognition and real-time streaming: REST, WebSocket and webhook verification client for finlight.me.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

 Project Readme

finlight-client (Ruby)

English | 简体中文 | 日本語 | 한국어

Gem Version CI

The official Ruby client for the finlight.me API — financial news with sentiment analysis, entity recognition, and real-time streaming.

📚 Full API documentation: docs.finlight.me

Features

  • REST API: search articles, fetch single articles by link, list sources
  • Real-time streaming: enhanced and raw article streams over WebSocket
  • Resilient by default: request retries with exponential backoff; WebSocket auto-reconnect, keepalive with pong watchdog, proactive connection rotation, and rate-limit handling
  • Webhook support: HMAC-SHA256 signature verification with replay protection
  • Minimal dependencies: stdlib Net::HTTP and OpenSSL, plus the pure-Ruby websocket-driver

Requires Ruby 3.2+.

Installation

# Gemfile
gem "finlight-client"

Or directly:

gem install finlight-client

Quick Start

require "finlight/client"

client = Finlight::Client.new(api_key: ENV["FINLIGHT_API_KEY"])

response = client.articles.fetch_articles(query: "nvidia", page_size: 10)
response.articles.each { |article| puts "[#{article.source}] #{article.title}" }

REST API

Search articles

See the query language reference for the full query syntax. Parameters are snake_case keywords; they map 1:1 to the camelCase API fields.

response = client.articles.fetch_articles(
  query: '(ticker:AAPL OR ticker:NVDA) AND "Elon Musk"',
  tickers: %w[AAPL NVDA],
  from: "2025-01-01",
  include_content: true,
  include_entities: true,
  order_by: "publishDate",
  order: "DESC",
  page_size: 20
)

response.articles.each do |article|
  puts "#{article.publish_date} #{article.title} (#{article.sentiment})"
end

Fetch a single article by link

article = client.articles.fetch_article_by_link(
  link: "https://www.reuters.com/technology/example",
  include_content: true
)

List sources

sources = client.sources.get_sources
defaults = sources.select(&:is_default_source)

Real-time streaming

connect blocks and reconnects automatically until you call stop; use connect_async to run it on a background thread. The enhanced stream delivers articles with sentiment and entities; the raw stream (client.raw_websocket) delivers unenriched articles with minimal latency.

websocket = client.websocket
websocket.connect(tickers: %w[AAPL NVDA], extended: true) do |article|
  puts article.title
end

Custom stream options:

websocket = client.websocket(
  takeover: true, # take over an existing connection for the same key
  on_close: ->(code, reason) { puts "closed: #{code} #{reason}" }
)
thread = websocket.connect_async(query: "bitcoin") { |article| puts article.title }
# ...
websocket.stop
thread.join

If the server permanently rejects the connection (close code 1008), connect raises Finlight::BlockedError — reconnecting will not help; contact support.

Webhooks

Verify incoming webhooks with the raw (unparsed) request body:

# e.g. in a Rails controller
def webhook
  article = Finlight::WebhookService.construct_event(
    request.raw_post,
    request.headers["X-Webhook-Signature"],
    ENV["WEBHOOK_SECRET"],
    request.headers["X-Webhook-Timestamp"]
  )
  Rails.logger.info("New article: #{article.title}")
  head :ok
rescue Finlight::WebhookVerificationError
  head :bad_request
end

Configuration

Option Default Description
base_url: https://api.finlight.me REST endpoint
wss_url: wss://wss.finlight.me WebSocket endpoint
timeout: 5 Per-request and connect timeout in seconds
retry_count: 3 Total attempts for retryable failures (429/5xx)
logger: stderr, WARN Any stdlib-compatible Logger
client = Finlight::Client.new(
  api_key: api_key,
  timeout: 10,
  retry_count: 5,
  logger: Logger.new($stdout, level: Logger::INFO)
)

Development

bundle install
bundle exec rake        # run the test suite

Verification against the real API

The local/ directory is gitignored and holds smoke runners, mirroring the sibling clients — keep credentials in the environment, never in code.

# One-shot smoke: REST endpoints + 30s article stream
FINLIGHT_API_KEY=sk_... bundle exec ruby local/smoke.rb

# REST integration tests (auto-skipped when the key is not set)
FINLIGHT_API_KEY=sk_... bundle exec rspec spec/integration

Optional: FINLIGHT_BASE_URL / FINLIGHT_WSS_URL to target dev.

License

MIT