Finlight Client

May 24, 2026 ยท View on GitHub

A Python client library for interacting with the Finlight News API. Finlight delivers real-time and historical financial news articles, enriched with sentiment analysis, company tagging, and market metadata. This library makes it easy to integrate Finlight into your Python applications.


โœจ Features

  • Fetch structured news articles with date parsing and metadata.
  • Filter by tickers, sources, languages, and date ranges.
  • Stream real-time news updates via Enhanced and Raw WebSocket with auto-reconnect.
  • Webhook support with HMAC signature verification and replay attack protection.
  • Advanced WebSocket features:
    • Exponential backoff reconnection strategy
    • Ping/pong keepalive mechanism
    • Proactive connection rotation (before AWS 2-hour limit)
    • Connection takeover for replacing existing connections
    • Rate limit and admin kick handling
  • Strongly typed models using pydantic and dataclass.
  • Lightweight and developer-friendly.

๐Ÿ“ฆ Installation

pip install finlight-client

๐Ÿš€ Quick Start

Fetch Articles via REST API

from finlight_client import FinlightApi, ApiConfig
from finlight_client.models import GetArticlesParams

def main():
    # Initialize the client
    config = ApiConfig(api_key="your_api_key")
    client = FinlightApi(config)

    # Create query parameters
    params = GetArticlesParams(
        query="Nvidia",
        language="en",
        from_="2024-01-01",
        to="2024-12-31",
        includeContent=True
    )

    # Fetch articles
    response = client.articles.fetch_articles(params=params)

    # Print results
    for article in response.articles:
        print(f"{article.publishDate} | {article.title}")

if __name__ == "__main__":
    main()

Fetch Article by Link

from finlight_client import FinlightApi, ApiConfig
from finlight_client.models import GetArticleByLinkParams

def main():
    config = ApiConfig(api_key="your_api_key")
    client = FinlightApi(config)

    params = GetArticleByLinkParams(
        link="https://www.reuters.com/technology/example-article",
        includeContent=True,
        includeEntities=True
    )

    article = client.articles.fetch_article_by_link(params=params)
    print(f"{article.publishDate} | {article.title}")

if __name__ == "__main__":
    main()

Stream Real-Time Articles via WebSocket

import asyncio
from finlight_client import FinlightApi, ApiConfig
from finlight_client.models import GetArticlesWebSocketParams

def on_article(article):
    print("๐Ÿ“จ Received:", article.title)

async def main():
    # Initialize the client
    config = ApiConfig(api_key="your_api_key")
    client = FinlightApi(config)

    # Create WebSocket parameters
    payload = GetArticlesWebSocketParams(
        query="Nvidia",
        sources=["www.reuters.com"],
        language="en",
        extended=True,
    )

    # Connect and listen for articles
    await client.websocket.connect(
        request_payload=payload,
        on_article=on_article
    )

if __name__ == "__main__":
    asyncio.run(main())

Stream Raw Articles via WebSocket

The Raw WebSocket delivers articles faster by skipping AI enrichment (no sentiment, confidence, or company tagging). It supports field-level filtering with source:, title:, and summary: fields.

import asyncio
from finlight_client import FinlightApi, ApiConfig, RawWebSocketOptions
from finlight_client.models import GetRawArticlesWebSocketParams

def on_article(article):
    print("๐Ÿ“จ Received:", article.title)

async def main():
    config = ApiConfig(api_key="your_api_key")
    client = FinlightApi(
        config,
        raw_websocket_options=RawWebSocketOptions(
            takeover=True
        )
    )

    payload = GetRawArticlesWebSocketParams(
        query="title:Nvidia",
        sources=["www.reuters.com"],
        language="en",
    )

    await client.raw_websocket.connect(
        request_payload=payload,
        on_article=on_article
    )

if __name__ == "__main__":
    asyncio.run(main())

โš™๏ธ Configuration

ApiConfig

Core API configuration:

ParameterTypeDescriptionDefault
api_keystrYour API keyRequired
base_urlAnyHttpUrlBase REST API URLhttps://api.finlight.me
wss_urlAnyHttpUrlWebSocket server URLwss://wss.finlight.me
timeoutintRequest timeout in ms5000
retry_countintRetry attempts on failures3

FinlightApi WebSocket Options

Advanced WebSocket configuration (all optional). You can use flat kwargs or option objects:

# Using flat kwargs (Enhanced WebSocket only)
client = FinlightApi(config, websocket_takeover=True)

# Using option objects (Enhanced and Raw WebSocket)
from finlight_client import WebSocketOptions, RawWebSocketOptions

client = FinlightApi(
    config,
    websocket_options=WebSocketOptions(takeover=True),
    raw_websocket_options=RawWebSocketOptions(takeover=True),
)

Both WebSocketOptions and RawWebSocketOptions accept the same fields:

FieldTypeDescriptionDefault
ping_intervalintPing interval in seconds25
pong_timeoutintPong timeout in seconds60
base_reconnect_delayfloatInitial reconnect delay in seconds0.5
max_reconnect_delayfloatMaximum reconnect delay in seconds10.0
connection_lifetimeintConnection lifetime in seconds6900 (115m)
takeoverboolTakeover existing connectionsFalse
on_closeCallableCallback for close events (code, reason)None

๐Ÿ“š API Overview

ArticleService.fetch_articles(params: GetArticlesParams) -> ArticleResponse

Fetch articles with flexible filtering:

  • Supports advanced query strings with boolean operators
  • Automatically parses ISO date strings into datetime
  • Pagination with configurable page size (1-1000)
  • Optional full content and entity tagging

ArticleService.fetch_article_by_link(params: GetArticleByLinkParams) -> Article

Fetch a single article by its URL:

  • Returns the article if found in the database
  • Optional full content and entity tagging
  • Useful for retrieving specific articles by URL

SourcesService.get_sources() -> List[Source]

Retrieve available news sources:

  • Returns list of sources with metadata
  • Indicates content availability and default sources
  • Useful for building source filters

WebSocketClient.connect(request_payload, on_article)

Subscribe to live article updates:

  • Reconnects automatically with exponential backoff
  • Handles rate limiting and admin actions gracefully
  • Pings the server every 25s to keep the connection alive
  • Proactively rotates connections before AWS 2-hour timeout
  • Optional connection takeover mode

RawWebSocketClient.connect(request_payload, on_article)

Subscribe to live raw article updates (faster delivery, no AI enrichment):

  • Same reconnection and keepalive features as the enhanced WebSocket
  • Connects to wss://wss.finlight.me/raw
  • Returns RawArticle objects (no sentiment, confidence, or companies)
  • Supports field-level query filters: source:, title:, summary:

WebhookService.construct_event(raw_body, signature, endpoint_secret, timestamp?)

Securely receive webhook events:

  • HMAC-SHA256 signature verification
  • Replay attack protection (5-minute tolerance)
  • Returns validated Article objects
  • Raises WebhookVerificationError on invalid requests

๐Ÿงฏ Error Handling

  • Invalid date strings raise clear Python ValueErrors.
  • REST and WebSocket exceptions are logged and managed.
  • WebSocket includes reconnect, watchdog, and ping/pong mechanisms.

๐Ÿ“– Additional Examples

Fetch Available Sources

from finlight_client import FinlightApi, ApiConfig

def main():
    config = ApiConfig(api_key="your_api_key")
    client = FinlightApi(config)

    sources = client.sources.get_sources()

    for source in sources:
        print(f"{source.domain} - Content: {source.isContentAvailable}")

if __name__ == "__main__":
    main()

Receive Webhook Events (Flask)

from flask import Flask, request
from finlight_client import WebhookService, WebhookVerificationError
import os

app = Flask(__name__)
webhook_service = WebhookService()

@app.route('/webhook', methods=['POST'])
def webhook():
    raw_body = request.get_data(as_text=True)
    signature = request.headers.get('X-Webhook-Signature')
    timestamp = request.headers.get('X-Webhook-Timestamp')

    try:
        article = webhook_service.construct_event(
            raw_body,
            signature,
            os.getenv('WEBHOOK_SECRET'),
            timestamp
        )
        print(f"๐Ÿ“จ New article: {article.title}")
        return '', 200
    except WebhookVerificationError as e:
        print(f"โŒ Invalid webhook: {e}")
        return '', 400

if __name__ == "__main__":
    app.run(port=3000)

Advanced WebSocket with Custom Configuration

import asyncio
from finlight_client import FinlightApi, ApiConfig
from finlight_client.models import GetArticlesWebSocketParams

def on_article(article):
    print(f"๐Ÿ“จ {article.title}")

def on_close(code, reason):
    print(f"๐Ÿ”Œ Connection closed: {code} - {reason}")

async def main():
    config = ApiConfig(api_key="your_api_key")

    # Advanced WebSocket configuration
    client = FinlightApi(
        config,
        websocket_ping_interval=30,  # Custom ping interval
        websocket_pong_timeout=90,   # Custom pong timeout
        websocket_takeover=True,     # Replace existing connections
        websocket_on_close=on_close  # Close event callback
    )

    payload = GetArticlesWebSocketParams(
        tickers=["NVDA", "AAPL"],
        language="en",
        extended=True,
        includeEntities=True
    )

    await client.websocket.connect(
        request_payload=payload,
        on_article=on_article
    )

if __name__ == "__main__":
    asyncio.run(main())

๐Ÿงฐ Model Summary

GetArticlesParams (REST API)

Query parameters to filter articles:

FieldTypeDescription
querystrSearch text with boolean operators
tickersList[str]Filter by ticker symbols (e.g., ["AAPL", "NVDA"])
sourcesList[str]Include specific sources
excludeSourcesList[str]Exclude specific sources
optInSourcesList[str]Include non-default sources
languagestrLanguage filter (e.g., "en", "de")
countriesList[str]Filter by country codes (e.g., ["US", "GB"])
from_strStart date (YYYY-MM-DD or ISO)
tostrEnd date (YYYY-MM-DD or ISO)
includeContentboolInclude full article content (default: False)
includeEntitiesboolInclude tagged companies (default: False)
excludeEmptyContentboolOnly articles with content (default: False)
orderBystrOrder by "publishDate", "createdAt", or "revisedDate"
orderstrSort order: "ASC" or "DESC"
pageintPage number (starts at 1)
pageSizeintResults per page (1-1000)

GetArticleByLinkParams (REST API)

Parameters for fetching a single article by URL:

FieldTypeDescription
linkstrThe URL of the article to fetch (required)
includeContentboolInclude full article content (default: None)
includeEntitiesboolInclude tagged companies (default: None)

GetArticlesWebSocketParams (WebSocket)

Parameters for WebSocket subscriptions:

FieldTypeDescription
querystrSearch text
tickersList[str]Filter by ticker symbols
sourcesList[str]Include specific sources
excludeSourcesList[str]Exclude specific sources
optInSourcesList[str]Include non-default sources
languagestrLanguage filter
countriesList[str]Filter by country codes (e.g., ["US", "GB"])
extendedboolInclude full article details (default: False)
includeEntitiesboolInclude tagged companies (default: False)
excludeEmptyContentboolOnly articles with content (default: False)

GetRawArticlesWebSocketParams (Raw WebSocket)

Parameters for Raw WebSocket subscriptions:

FieldTypeDescription
querystrSearch text with field filters (source:, title:, summary:)
sourcesList[str]Include specific sources
excludeSourcesList[str]Exclude specific sources
optInSourcesList[str]Include non-default sources
languagestrLanguage filter

Article

Article object fields (Enhanced WebSocket / REST API):

FieldTypeDescription
titlestrArticle title
linkstrArticle URL
publishDatedatetimePublication date
sourcestrSource domain
languagestrArticle language code
summarystrArticle summary
contentstrFull article content (if available)
sentimentstrSentiment analysis result
confidencefloatSentiment confidence score
imagesList[str]List of image URLs
companiesList[Company]Tagged companies with metadata

RawArticle

Raw article object fields (Raw WebSocket):

FieldTypeDescription
titlestrArticle title
linkstrArticle URL
publishDatedatetimePublication date
sourcestrSource domain
languagestrArticle language code
summarystrArticle summary
imagesList[str]List of image URLs

Company

Tagged company information:

FieldTypeDescription
companyIdintUnique company identifier
namestrCompany name
tickerstrPrimary ticker symbol
confidencefloatTagging confidence score
countrystrCompany country
exchangestrPrimary exchange
sectorstrBusiness sector
industrystrIndustry classification
isinstrISIN code
openfigistrOpenFIGI identifier
primaryListingListingPrimary exchange listing
isinsList[str]All ISIN codes
otherListingsList[Listing]Other exchange listings

Source

News source metadata:

FieldTypeDescription
domainstrSource domain (e.g., "www.reuters.com")
isContentAvailableboolWhether full content is available
isDefaultSourceboolWhether source is included by default

๐Ÿค Contributing

We welcome contributions and suggestions!

  • Fork this repo
  • Create a feature branch
  • Submit a pull request with tests if applicable

๐Ÿ“„ License

MIT License โ€“ see LICENSE


๐Ÿ”— Resources