API Reference
BASE URL: HTTPS://API.SENTIMENTFX.ORG
Authentication
All API endpoints require an API key passed as the X-API-Key request header. Get one below — no card, no account, 1,000 free calls every 30 days.
| Plan | Included Calls | Past the allowance |
|---|---|---|
| Free | 1,000 per 30-day window | Requests stop until the window ends |
| Pro | 15,000 / month | Requests stop until the 1st |
| Data | 200,000 / month | Requests stop until the 1st |
Full history on all 42 tickers, every endpoint, REST and MCP. If you've already made a free key above, enter the same email and we'll raise that key's allowance rather than issuing a second one.
Already subscribed? Keys generated from the dashboard are linked to your account and pick up your plan's monthly allowance automatically.
402 with "type": "insufficient_quota".
GET /v1/usage keeps working when you're out, so you can always
check where you stand. Need more than your plan includes?
Request a higher allowance.
# Curl curl https://api.sentimentfx.org/v1/sentiment/BTC \ -H "X-API-Key: sfx_your_api_key_here" # Python import requests res = requests.get( "https://api.sentimentfx.org/v1/sentiment/BTC", headers={"X-API-Key": "sfx_your_api_key_here"} ) # JavaScript const res = await fetch( "https://api.sentimentfx.org/v1/sentiment/BTC", { headers: { "X-API-Key": "sfx_your_api_key_here" } } )
Sentiment
Returns sentiment-scored headlines for the specified ticker. Default 25 headlines = 1 call. Every additional 25 = 1 more call.
| Parameter | Type | Default | Description |
|---|---|---|---|
| ticker | string | — | 42 supported across crypto, FX, stocks, ETFs, commodities |
| limit | integer | 25 | Headlines to return, 1–100. Costs 1 credit per 25 returned. |
| sources | string | news | news returns editorial news. social returns Reddit, StockTwits and X posts only. all returns both. |
Social posts are kept separate from news and never count towards a sentiment average. Each headline's source_kind is news, reddit, stocktwits, x or youtube.
{
"ticker": "BTC",
"limit": 25,
"sources": "news",
"calls_used": 1,
"data": [
{
"date": "2026-04-27T12:00:00",
"title": "Bitcoin hits new yearly high amid ETF inflows",
"source": "CoinDesk",
"source_kind": "news",
"sentiment_score": 0.6821,
"sentiment_label": "positive"
}
]
}
Summary
Returns daily averaged sentiment scores. Costs 1 credit per day actually returned — a window with no coverage costs nothing.
| Parameter | Type | Default | Description |
|---|---|---|---|
| ticker | string | — | 42 supported across crypto, FX, stocks, ETFs, commodities |
| days | integer | 30 | Days of history, 1–365. Costs 1 credit per day returned. |
| sources | string | news | news averages editorial news. social gives a separate daily average of Reddit, StockTwits and X posts. |
{
"ticker": "BTC",
"days": 30,
"sources": "news",
"calls_used": 30,
"data": [
{
"date": "2026-04-27",
"avg_sentiment": 0.2341,
"article_count": 12,
"label": "positive"
}
]
}
Prices
Returns daily closing prices in the asset's native currency: GBP for crypto, exchange rates for FX pairs, USD for stocks, ETFs and commodity futures. Costs 1 credit per day actually returned — a window with no coverage costs nothing.
| Parameter | Type | Default | Description |
|---|---|---|---|
| ticker | string | — | 42 supported across crypto, FX, stocks, ETFs, commodities |
| days | integer | 30 | Days of history, 1–365. Costs 1 credit per day returned. |
{
"ticker": "BTC",
"days": 30,
"calls_used": 30,
"currency": "GBP",
"data": [
{
"date": "2026-04-27T00:00:00",
"close_price": 72841.50,
"volume": 18294830293.0
}
]
}
Correlation
Returns the Pearson correlation between sentiment shifts and next-day price returns, with a 95% confidence interval and signal strength rating. Always 1 call.
| Parameter | Type | Default | Description |
|---|---|---|---|
| ticker | string | — | 42 supported across crypto, FX, stocks, ETFs, commodities |
{
"ticker": "BTC",
"calls_used": 1,
"window_days": 180,
"sample_size": 87,
"primary_signal": {
"type": "sentiment_shift_vs_next_day_return",
"correlation": 0.241,
"p_value": 0.0241,
"ci_95": [0.033, 0.431],
"strength": "weak",
"direction": "positive (momentum)"
},
"interpretation": "Sentiment shifts show a weak positive (momentum) signal (r=0.241, p=0.0241, n=87)"
}
strong (|r|≥0.25), weak (|r|≥0.10), or inconclusive (|r|<0.10). CI uses Fisher z-transform.
MCP — Claude, Cursor & other AI clients
SentimentFX also speaks the Model Context Protocol, so Claude Code, Claude.ai desktop, Cursor, Cline and any other MCP-compatible client can call the sentiment tools natively without you writing HTTP-plumbing code. Same X-API-Key, same billing, same rate limits — you just point the client at a URL.
Endpoint: https://api.sentimentfx.org/mcp
Auth: X-API-Key: sfx_... header, or Authorization: Bearer sfx_... for clients that can only send a bearer token (get a free key).
Tools exposed
| Tool | Args | Cost |
|---|---|---|
list_tickers | — | free |
get_usage | — | free — plan, calls used, allowance, reset date |
get_sentiment | ticker, limit (≤100) | 1 credit / 25 headlines returned |
get_summary | ticker, days (≤365) | 1 credit / day returned |
get_prices | ticker, days (≤365) | 1 credit / day returned |
get_correlation | ticker | 1 credit |
Claude Code
Run once in a terminal. --scope user makes the tools available in every project; leave it out to add them to the current project only:
claude mcp add --transport http --scope user sentimentfx https://api.sentimentfx.org/mcp --header "X-API-Key: sfx_your_key_here"
Check it with claude mcp list, or /mcp inside a session. Start a new session and Claude will discover the six tools. Try "What's Bitcoin sentiment looking like this week?".
Cursor / Windsurf
Add this to ~/.cursor/mcp.json (or .cursor/mcp.json in a project) for Cursor, or to Windsurf's mcp_config.json:
{
"mcpServers": {
"sentimentfx": {
"url": "https://api.sentimentfx.org/mcp",
"headers": { "X-API-Key": "sfx_your_key_here" }
}
}
}
Cline
In the MCP Servers panel, open the Configure tab and click Configure MCP Servers. Cline needs "type": "streamableHttp": without it, Cline falls back to the older SSE transport, which this server doesn't offer.
{
"mcpServers": {
"sentimentfx": {
"type": "streamableHttp",
"url": "https://api.sentimentfx.org/mcp",
"headers": { "X-API-Key": "sfx_your_key_here" }
}
}
}
Claude API (custom apps)
Use the Messages API's MCP connector. It needs the server in mcp_servers and a matching mcp_toolset in tools. The connector can't send custom headers, so your key goes in authorization_token, which arrives as Authorization: Bearer:
from anthropic import Anthropic
client = Anthropic()
resp = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=16000,
betas=["mcp-client-2025-11-20", "server-side-fallback-2026-07-01"],
fallbacks="default",
mcp_servers=[{
"type": "url",
"url": "https://api.sentimentfx.org/mcp",
"name": "sentimentfx",
"authorization_token": "sfx_your_key_here",
}],
tools=[{"type": "mcp_toolset", "mcp_server_name": "sentimentfx"}],
messages=[{"role": "user", "content": "Rank the top 5 tickers by 7-day sentiment shift."}],
)
print("".join(b.text for b in resp.content if b.type == "text"))
Every MCP tool call counts against the same allowance as the equivalent /v1/* HTTP call — check usage on the dashboard's API Access panel.
Error Codes
| Code | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 402 | Allowance used up — insufficient_quota. Wait for the refill or request more |
| 403 | Plan does not include API access |
| 404 | No data found for ticker |
| 429 | Rate limit exceeded |
| 500 | Server error |
Request more calls
Every plan stops at its allowance rather than billing per call. If your application needs more than your plan includes, tell us roughly how many calls and what for, and we'll raise your key's allowance. The extra calls apply every period: each 30-day window on a free key, each month on Pro or Data.
Use the email your API key was issued to, so we can find the key.
Bulk dataset licence
The API is sold as a monthly call allowance, which suits an application reading current sentiment. If you need the whole corpus at once — to backtest against, to train on, or to join to your own data — that's a licence rather than a subscription, delivered as CSV or JSONL.
| Contents | Detail |
|---|---|
| Headlines | 180,000+ FinBERT-scored |
| Price rows | 120,000+ daily OHLCV |
| Tickers | 42 — crypto, FX, US equities, ETFs, commodity futures |
| Per headline | ticker, title, source, URL, FinBERT score (-1 to +1), label, published timestamp |
| Formats | CSV or JSONL, one-off snapshot or refreshed periodically |
Scores come from the same FinBERT
pipeline behind the live API, so a backtest on the archive and a signal read
from /v1/sentiment are directly comparable. Methodology is
documented in full under Sentiment Scoring.
Pricing depends on scope and whether you're redistributing, so this starts a conversation rather than a checkout. Tell us what you need and we'll come back with terms.
Methodology
HOW SENTIMENTFX SCORES, ANALYSES, AND SIGNALS
Sentiment Scoring
Every headline is scored using FinBERT, a BERT-based transformer model fine-tuned on financial news. The model outputs three probabilities: positive, negative, and neutral.
We compute the score as:
score = positive_probability − negative_probability
This gives a value in the range −1.0 to +1.0, where +1 is maximally positive, −1 is maximally negative, and 0 is neutral. We deliberately exclude the neutral label from the score — only the relative weight of positive vs negative drives it.
The daily sentiment figure shown on the dashboard is the mean score across all headlines published for that ticker on that day.
| Score Range | Label |
|---|---|
| > +0.3 | Strongly Bullish |
| +0.1 to +0.3 | Bullish |
| −0.1 to +0.1 | Neutral |
| −0.3 to −0.1 | Bearish |
| < −0.3 | Strongly Bearish |
Sentiment Shift
Raw sentiment level is a lagging, noisy signal — markets tend to price in known information quickly. What is more useful is the change in sentiment relative to recent baseline.
We define the daily sentiment shift as:
shift = today's sentiment − 7-day rolling average
A positive shift means today's news is meaningfully more positive than the recent norm. A negative shift means the tone has deteriorated relative to baseline. This is the primary input to the correlation and signal models.
The 7-Day Trend shown on the dashboard compares the average sentiment of the last 7 days to the 7 days before that — a broader directional indicator separate from the daily shift.
Correlation Analysis
We compute a Pearson correlation between daily sentiment shifts and the next-day price return (close-to-close, in the ticker's native currency) over a rolling 180-day window. A minimum of 30 overlapping data points is required to return a result.
r = corr(sentiment_shift[d], price_return[d+1])
The result includes:
| Field | Description |
|---|---|
| correlation (r) | Pearson r. Range −1 to +1. Closer to ±1 = stronger relationship. |
| p_value | Probability the result is due to chance. <0.05 = statistically significant. |
| ci_95 | 95% confidence interval via Fisher z-transform. Narrower = more reliable. |
| sample_size (n) | Number of overlapping trading days used in the calculation. |
We also compute a momentum baseline (autocorrelation of price returns) to test whether the sentiment signal adds value beyond simple price momentum. primary_beats_momentum: true means it does.
Signal Strength
Signal strength reflects the statistical reliability of the historical sentiment-price correlation model for a given ticker — not the size of today's specific shift.
| Label | Criteria | Meaning |
|---|---|---|
| Strong | |r| ≥ 0.25 | Consistent relationship across the analysis window |
| Weak | |r| ≥ 0.10 | Detectable relationship but modest in magnitude |
| Inconclusive | |r| < 0.10 | No meaningful directional relationship found |
Strength is based on correlation magnitude (|r|), consistent with how practitioners use rolling correlations in quantitative finance. The p-value is included in the response for reference. Tickers with fewer headlines (SOL, XRP, DOGE) tend to have noisier correlations and are more likely to be inconclusive.
Shift Percentile
The shift percentile ranks today's sentiment shift against all historical daily shifts for that ticker over the last 180 days.
| Percentile | Label | Meaning |
|---|---|---|
| ≥ 90th | Extreme | Larger than 90% of all recorded shifts — rare |
| 75th – 89th | Significant | Top quartile of historical shifts |
| 50th – 74th | Moderate | Above-median shift |
| < 50th | Minor | Below-median — normal day-to-day noise |
A high shift percentile means today's sentiment move is unusually large relative to history — which, combined with a reliable signal model, increases confidence in the direction. A minor shift in isolation has limited predictive value even if the historical correlation is strong.
Momentum vs Contrarian
The direction label describes how sentiment shifts have historically related to price moves for a given ticker.
| Label | r sign | Meaning |
|---|---|---|
| Momentum | Positive (+) | Positive sentiment shifts tend to be followed by price rises. Negative shifts tend to be followed by drops. |
| Contrarian | Negative (−) | Positive sentiment shifts tend to be followed by price drops — the market may already have priced in the optimism. Negative shifts may precede rebounds. |
Neither direction is inherently better — both can be traded if the correlation is strong enough. The direction is determined purely by the sign of the Pearson r value over the analysis window.