jintel-api
v0.3.0
Published
Jintel — paid intelligence API for financial data and research
Readme
Jintel
Multi-source intelligence API for trading and risk research. Part of YojinHQ -- Jintel is the paid data layer that powers Yojin and any other client that needs unified financial, news, and regulatory intelligence through a single GraphQL endpoint.
Quick Start
git clone https://github.com/YojinHQ/Jintel.git
cd Jintel
pnpm install
cp .env.example .env # fill in API keys
pnpm dev # starts on http://localhost:4000Open http://localhost:4000 for the dashboard with org management, usage tracking, and connector controls. Visit /graphiql for the interactive GraphQL playground or /docs for API documentation.
GraphQL API
Single endpoint: POST /api/graphql
All queries require an Authorization: Bearer <api_key> header.
Search entities
{
searchEntities(query: "Tesla", type: COMPANY, limit: 5) {
id name type tickers
}
}Look up by ticker (primary Yojin path)
{
entityByTicker(ticker: "AAPL") {
name type tickers
market {
quote { ticker price open high low previousClose changePercent volume marketCap }
fundamentals { fiftyTwoWeekHigh fiftyTwoWeekLow sector industry }
}
risk { overallScore signals { type severity description } }
regulatory { sanctions { matchedName score } }
}
}Batch quotes (portfolio dashboard)
{
quotes(tickers: ["AAPL", "MSFT", "GOOGL"]) {
ticker price open high low previousClose changePercent volume marketCap
}
}Crypto quotes (via CoinGecko)
{
cryptoQuotes(ids: ["BTC", "ETH", "SOL"]) {
id symbol name price marketCap volume24h changePercent24h high24h low24h
}
}Technical indicators
{
technicals(ticker: "AAPL") {
rsi macd { macd signal histogram }
bollingerBands { upper middle lower }
ema sma atr vwma mfi
}
}Sanctions screening
{
sanctionsScreen(name: "Gazprom") {
listName matchedName score details
}
}Each enrichment field resolves independently and in parallel. Clients pay only for the fields they request.
Authentication
Self-serve signup:
curl -X POST http://localhost:4000/api/v1/signup \
-H "Content-Type: application/json" \
-d '{"name": "My Org", "type": "personal"}'Returns an org record and a raw API key. Use the key as a Bearer token:
Authorization: Bearer <your-api-key>Yojin integration: Yojin calls /api/v1/signup on behalf of users and stores the key in its vault.
Google OAuth: Users can sign in with their Google account at /login. The flow:
- Click "Continue with Google" on the login page
- Redirects to Google consent →
/auth/callback - Auto-creates an org + API key on first login
- Sets a session cookie and redirects to the dashboard
Requires GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and GOOGLE_REDIRECT_URI environment variables.
Dashboard
A React SPA served at the root (/) provides org management and monitoring:
| Page | Path | Description |
|------|------|-------------|
| Welcome | / | Landing page |
| Login | /login | Google OAuth sign-in |
| Overview | /overview | Org stats, API usage summary |
| Usage | /usage | Detailed usage tracking with date range filters |
| Keys | /keys | API key management (create, list, revoke) |
| Connectors | /connectors | Connector health status, per-org enable/disable |
| Playground | /playground | Interactive GraphQL query builder |
Built with React 19, React Router, Vite, and Chart.js for data visualization.
Data Sources
Jintel runs on 11 free data connectors — no API keys required:
| Connector | Category | OpenBB | Provides | Models / Endpoints |
|---|---|:---:|---|---|
| Yahoo Finance | Market | Yes | Quotes, profiles, fundamentals, OHLC, market cap | EquityQuote, EquityInfo |
| CBOE | Market | Yes | Index search (S&P 500, VIX, etc.) | IndexSearch |
| Multpl | Market | Yes | S&P 500 P/E, Shiller P/E, dividend yield | SP500Multiples |
| CoinGecko | Market | — | Crypto prices, market cap, volume, 24h change | /coins/markets, /search |
| OFAC | Regulatory | — | US sanctions screening (SDN list, cached locally) | Treasury.gov CSV + local fuzzy match |
| SEC EDGAR | Regulatory | Yes | US public company filings search | EquitySearch |
| OECD | Economics | Yes | GDP, CPI, interest rates, leading indicators | GdpReal, GdpNominal, GdpForecast, ConsumerPriceIndex, CountryInterestRates, CompositeLeadingIndicator |
| IMF | Economics | Yes | Global CPI, economic indicators, trade data | ConsumerPriceIndex, EconomicIndicators |
| ECB | Economics | Yes | European balance of payments | BalanceOfPayments |
| Deribit | Derivatives | Yes | Crypto futures curves, options chains | FuturesCurve, OptionsChains |
| Technical Analysis | Market | Yes | RSI, MACD, Bollinger Bands, EMA, SMA, ATR, VWMA, MFI | EquityHistorical, CryptoHistorical + trading-signals |
9 of 11 connectors route through OpenBB via @traderalice/opentypebb. The remaining 2 (CoinGecko, OFAC) call upstream APIs directly.
Performance
The API includes several optimizations to minimize upstream calls:
- Mercurius loaders (N+1 elimination) -- Entity nested fields (
market,risk,regulatory) use batched loaders. Querying 10 entities makes 2 upstream calls (not 20) - Comma-separated batch calls --
quotes()and Entity market loaders send all tickers in a single upstream call to Yahoo Finance (e.g."AAPL,MSFT,GOOGL") - Per-request enrichment cache -- when
Entity.riskandEntity.regulatoryboth need OFAC data for the same entity, the second call reuses the first's result (zero extra API calls) - Cross-request TTL cache -- Yahoo Finance quotes cached 2 min, profiles 1 hour. Repeated queries for the same ticker skip API calls entirely
- Local OFAC SDN list -- sanctions data downloaded once from Treasury.gov and cached 24 hours in memory. Fuzzy bigram matching runs locally with zero per-query API calls
- Parallel resolution --
entity(id)queries all connectors in parallel instead of waterfall - Query depth limit (7) and list size caps (20) prevent unbounded API usage
Org API (self-serve)
Authenticated with the org's own API key (Authorization: Bearer <key>).
| Method | Route | Description |
|----------|--------------------------------|--------------------------------------|
| GET | /api/v1/me | Org profile + key count |
| GET | /api/v1/usage | Aggregated usage (from/to params)|
| GET | /api/v1/keys | List org's API keys |
| POST | /api/v1/keys | Create a new API key |
| DELETE | /api/v1/keys/:keyId | Revoke an API key |
| GET | /api/v1/connectors | List connectors with health status |
| PUT | /api/v1/connectors/:name | Enable/disable a connector |
| GET | /api/v1/session | Session info from httpOnly cookie |
Admin API
All admin routes require the X-Admin-Secret header matching JINTEL_ADMIN_SECRET.
| Method | Route | Description |
|----------|--------------------------------|---------------------------|
| GET | /admin/orgs | List all organisations |
| POST | /admin/orgs | Create an organisation |
| GET | /admin/orgs/:orgId/keys | List API keys for an org |
| POST | /admin/orgs/:orgId/keys | Create an API key |
| DELETE | /admin/keys/:keyId | Revoke an API key |
| GET | /admin/keys/:keyId/usage | Query usage (from/to date params) |
Architecture
Client (Yojin UI, curl, any HTTP client)
|
| POST /api/graphql + Authorization: Bearer <key>
v
Fastify + Mercurius (GraphQL)
|
+---> Auth (preExecution hook, API key validation)
+---> Query depth limit (7)
+---> Rate limiter (100 req/min)
|
v
Resolvers ----> Per-request enrichCache (deduplicates connector calls)
|
v
Connector Registry (11 free connectors)
| +---> Cross-request TTL cache (quotes 2m, profiles 1h)
+---> Yahoo Finance (market) -- Quotes, profiles, fundamentals
+---> CBOE (market) -- Index search
+---> Multpl (market) -- S&P 500 multiples
+---> CoinGecko (market) -- Crypto prices, market cap, volume
+---> Technicals (market) -- RSI, MACD, BB, EMA, SMA, ATR, VWMA, MFI
+---> OFAC (regulatory) -- SDN list (local CSV, 24h cache)
+---> SEC EDGAR (regulatory) -- Company filings search
+---> OECD (economics) -- GDP, CPI, interest rates
+---> IMF (economics) -- Global economic indicators
+---> ECB (economics) -- Balance of payments
+---> Deribit (derivatives) -- Crypto futures & options
|
v
Upstream APIs (partial failures return partial results)Testing
pnpm test # watch mode
pnpm test:ci # single run218 tests across 23 test files:
| File | Coverage |
|---|---|
| auth/store.test.ts | Org CRUD, API key lifecycle, usage tracking, persistence |
| auth/service.test.ts | Token authentication edge cases |
| auth/org-connector-config.test.ts | Per-org connector enable/disable, isolation, persistence |
| auth/org-routes.test.ts | Org API endpoints: profile, usage, key management, connector toggle |
| auth/google-routes.test.ts | Google OAuth redirect, callback, org creation, session cookies |
| connectors/registry.test.ts | Lookups, category filtering, search connectors |
| connectors/market/alpha-vantage.test.ts | Quote fetching, cross-request TTL cache, error handling |
| connectors/regulatory/ofac.test.ts | CSV parsing, bigram similarity, SDN search, caching |
| graphql/schema.test.ts | SDL validation, Yojin field compatibility |
| graphql/context.test.ts | Context building, auth, debug flag, enrichCache |
| integration.test.ts | Auth enforcement, signup flow, admin routes, debug extensions |
Commands
pnpm dev # Start with tsx watch (development)
pnpm build # Compile TypeScript + build frontend with Vite
pnpm start # Run compiled output
pnpm test # Run tests in watch mode (vitest)
pnpm test:ci # Run tests once
pnpm typecheck # Type check without emitting
pnpm ci # Typecheck + test:ciTech Stack
- Fastify -- HTTP server
- Mercurius -- GraphQL adapter for Fastify
- TypeScript -- strict mode, ES modules
- React -- dashboard SPA (with React Router, Vite, Chart.js)
- Vitest -- test runner (218 tests)
- Pino -- structured logging
- tsx -- development watcher
Adding a Connector
Every data source implements the Connector interface in src/connectors/types.ts:
interface Connector {
name: string;
source: string;
category: 'market' | 'news' | 'regulatory' | 'corporate' | 'search';
search(query: string, options?: SearchOptions): Promise<SourceResult[]>;
enrich(entity: EntityRef, options?: EnrichOptions): Promise<any>;
healthcheck(): Promise<HealthStatus>;
}Create a module under src/connectors/, implement the interface, then call registerConnector() in src/connectors/registry.ts. The new source is immediately available to the GraphQL resolvers with no changes to core logic.
License
Proprietary. All rights reserved.
