NetNest Design Fundamentals
Fundamentals and SEC filing events for companies that file with the SEC, each value linked to its source filing.
Máy chủ MCP được lưu trữ
npx add-mcp 'https://api.netnestdesign.com/mcp'Cài vào Claude Code, Codex, Cursor và nhiều công cụ khác
Tài liệu
NetNest Design Fundamentals API
Company fundamentals from SEC filings, with the source filing attached to every number. Data from SEC filings. Not investment advice.
What you get
- The latest annual, quarterly and trailing twelve month values for 13 metrics, for every company that files 10-K and 10-Q reports with US GAAP XBRL data.
- Every value carries its period dates, fiscal year and period, form, filing date, accession number, a link to the SEC filing, and the XBRL concept it came from.
- "Latest" means the most recent period end for the period type you ask for. Fiscal years that do not match the calendar (Apple, Microsoft, NVIDIA, Walmart, Oracle, Costco) are handled per company.
- Values that are calculated rather than reported are marked
derived: truewith the inputs used. - Missing data comes back as
nullwith a reason. We never estimate.
Quickstart
Try without signing up: Authorization: Bearer demo (shared, 500 calls a day).
Get a free key (no card; 10 calls a day until you verify your email, then 100):
curl -X POST https://api.netnestdesign.com/v1/signup -H "Content-Type: application/json" -d '{"email":"you@example.com"}'
Verify your email
Until you verify your email the key has 10 calls a day. The welcome email carries a code; send it back to lift the limit:
curl -X POST https://api.netnestdesign.com/v1/signup/verify -H "Content-Type: application/json" -d '{"token":"CODE_FROM_THE_EMAIL"}'
Lost the code? POST https://api.netnestdesign.com/v1/signup/verify with {"email":"you@example.com"} sends a fresh one.
Call the API:
curl -H "Authorization: Bearer YOUR_KEY" "https://api.netnestdesign.com/v1/fundamentals/AAPL?metrics=revenue,net_income,eps_diluted&period=quarterly"
Python:
import requests
r = requests.get("https://api.netnestdesign.com/v1/fundamentals/MSFT", params={"metrics": "revenue,free_cash_flow", "period": "ttm"},
headers={"Authorization": "Bearer YOUR_KEY"}, timeout=30)
for v in r.json()["data"]:
print(v["metric"], v["value"], v["period_end"], v["form"], v["source_url"])
JavaScript:
const r = await fetch('https://api.netnestdesign.com/v1/history/NVDA/revenue?period=annual&limit=5', { headers: { Authorization: 'Bearer YOUR_KEY' } });
const { data } = await r.json();
Client packages
Open source clients (MIT) in our public repository, published from GitHub Actions through trusted publishing. Each takes your key, or demo to try.
| Package | Install | For |
|---|---|---|
netnest-fundamentals (npm) | npm install netnest-fundamentals | TypeScript and JavaScript, plus Vercel AI SDK tools |
netnest-fundamentals (PyPI) | pip install netnest-fundamentals | Python |
langchain-netnest | pip install langchain-netnest | LangChain tools |
llama-index-tools-netnest | pip install llama-index-tools-netnest | LlamaIndex tools |
import { NetNestClient } from 'netnest-fundamentals';
const nn = new NetNestClient({ apiKey: 'demo' }); // or your key; defaults to NETNEST_API_KEY
const { data } = await nn.fundamentals('MSFT', { metrics: ['revenue', 'net_income'], period: 'quarterly' });
// Vercel AI SDK: needs ai and zod installed
import { netnestTools } from 'netnest-fundamentals/ai-sdk';
const tools = netnestTools({ apiKey: process.env.NETNEST_API_KEY }); // give these to generateText or an agent
from netnest_fundamentals import NetNestClient
c = NetNestClient("demo") # or your key; defaults to NETNEST_API_KEY
print(c.fundamentals("MSFT", metrics=["revenue"], period="quarterly")["data"][0])
from langchain_netnest import NetNestToolkit
from llama_index.tools.netnest import NetNestToolSpec
from netnest_fundamentals import NetNestClient
langchain_tools = NetNestToolkit(client=NetNestClient("demo")).get_tools()
llamaindex_tools = NetNestToolSpec(api_key="demo").to_tool_list()
Agent frameworks (MCP)
The MCP server at https://api.netnestdesign.com/mcp (Streamable HTTP) gives an agent the tools search_company, get_company, get_fundamentals, get_history, get_events and get_events_head. Every framework below connects to it with no package of ours: send Authorization: Bearer YOUR_KEY, or Bearer demo to try it. ChatGPT, Claude and other clients that support MCP sign in connect with OAuth instead. Without a key, the paid tools answer with x402 payment requirements.
Each snippet was run against this server on 2026-10-27 with the package versions named.
LangChain (Python)
Tested with langchain 1.4.7 (the langchain.mcp module is in beta).
# pip install "langchain[mcp]"
from fastmcp.client import Client
from langchain.mcp import MCPAdapter
async with MCPAdapter(Client("https://api.netnestdesign.com/mcp", auth="YOUR_KEY")) as adapter:
tools = await adapter.list_tools() # give these to your agent
LangChain.js
Tested with @langchain/mcp-adapters 2.0.1. Tool names carry the server name you choose: netnest_get_company and so on.
// npm install @langchain/mcp-adapters
import { MCPAdapter } from '@langchain/mcp-adapters';
const adapter = new MCPAdapter({ servers: { netnest: { url: 'https://api.netnestdesign.com/mcp', headers: { Authorization: 'Bearer YOUR_KEY' } } } });
const tools = Object.values(await adapter.listToolsets()).flat();
LlamaIndex
Tested with llama-index-tools-mcp 0.6.0.
# pip install llama-index-tools-mcp
from llama_index.tools.mcp import BasicMCPClient, McpToolSpec
client = BasicMCPClient("https://api.netnestdesign.com/mcp", headers={"Authorization": "Bearer YOUR_KEY"})
tools = await McpToolSpec(client=client).to_tool_list_async()
CrewAI
Tested with crewai 1.15.30 and mcp 1.30.0. Tool names carry the server host: api_netnestdesign_com_mcp_get_company and so on.
# pip install crewai mcp
from crewai import Agent
from crewai.mcp import MCPServerHTTP
analyst = Agent(role="Analyst", goal="Answer questions from SEC filings", backstory="Reads company fundamentals",
mcps=[MCPServerHTTP(url="https://api.netnestdesign.com/mcp", headers={"Authorization": "Bearer YOUR_KEY"})])
Vercel AI SDK
Tested with @ai-sdk/mcp 2.0.85.
// npm install @ai-sdk/mcp
import { createMCPClient } from '@ai-sdk/mcp';
const client = await createMCPClient({ transport: { type: 'http', url: 'https://api.netnestdesign.com/mcp', headers: { Authorization: 'Bearer YOUR_KEY' } } });
const tools = await client.tools(); // give these to your agent
OpenAI Agents SDK
Tested with openai-agents 0.24.0 (Python) and @openai/agents 0.21.0 (JavaScript).
# pip install openai-agents
from agents import Agent
from agents.mcp import MCPServerStreamableHttp
async with MCPServerStreamableHttp(name="netnest", params={"url": "https://api.netnestdesign.com/mcp", "headers": {"Authorization": "Bearer YOUR_KEY"}}) as netnest:
agent = Agent(name="Analyst", instructions="Answer from SEC filings.", mcp_servers=[netnest])
// npm install @openai/agents
import { Agent, MCPServerStreamableHttp } from '@openai/agents';
const netnest = new MCPServerStreamableHttp({ name: 'netnest', url: 'https://api.netnestdesign.com/mcp', requestInit: { headers: { Authorization: 'Bearer YOUR_KEY' } } });
await netnest.connect();
const agent = new Agent({ name: 'Analyst', instructions: 'Answer from SEC filings.', mcpServers: [netnest] });
Pay per call with x402
Agents can pay for each call in USDC on Base with the x402 protocol. No account or key is needed. Call a paid endpoint without a key and you get HTTP 402 with the payment requirements; an x402 client pays and retries.
Every paid endpoint costs $0.02 a call: /v1/company/{ticker}, /v1/fundamentals/{ticker} and
/v1/history/{ticker}/{metric}. /v1/events costs $0.05 a call.
Network: eip155:8453. Payment settles only when the response succeeds (status below 400).
import { x402Client } from '@x402/core/client';
import { ExactEvmScheme } from '@x402/evm/exact/client';
import { wrapFetchWithPayment } from '@x402/fetch';
import { privateKeyToAccount } from 'viem/accounts';
const client = new x402Client();
client.register('eip155:*', new ExactEvmScheme(privateKeyToAccount(process.env.EVM_PRIVATE_KEY)));
const pay = wrapFetchWithPayment(fetch, client);
const res = await pay('https://api.netnestdesign.com/v1/fundamentals/AAPL?metrics=revenue,net_income&period=quarterly');
console.log(await res.json());
Endpoints
| Method and path | Cost | What it returns |
|---|---|---|
GET /v1/search?q=apple | Free | Ticker and company name lookup |
GET /v1/company/{ticker} | Paid | Company profile plus the latest values of key metrics for every period type |
GET /v1/fundamentals/{ticker}?metrics=a,b&period=annual | Paid | The latest value of each requested metric for one period type (annual, quarterly or ttm) |
GET /v1/history/{ticker}/{metric}?period=quarterly&limit=20 | Paid | One metric over time, newest first, up to 200 periods |
GET /v1/events?since=<cursor>&types=&tickers=&limit=100 | Paid (3 calls, or $0.05 by x402) | SEC filing events across companies, newest first: 8-K items, Form 4 insider transactions, Schedule 13D and 13G stakes |
GET /v1/events/head?since=<cursor> | Free | The latest events cursor and how many events are newer than yours |
POST /v1/signup | Free | Creates a free account and returns a key |
POST /v1/signup/verify | Free | Verifies your email with the code from the welcome email, or sends a fresh code |
GET /v1/account | Free | Your plan, usage and keys |
POST /v1/keys/rotate | Free | Issues a new key and revokes the one you used |
DELETE /v1/keys/current | Free | Revokes the key you used |
DELETE /v1/account | Free | Deletes your account, keys and usage records (a paying account also sends its confirmation code) |
POST /v1/billing/checkout | Free | Starts a paid plan: returns a Stripe Checkout link |
POST /v1/billing/code | Free | Emails a one time confirmation code for billing changes; it works once, for 15 minutes |
POST /v1/billing/change-plan | Free | Changes your plan or billing interval; send the confirmation code as code or in an X-Billing-Code header |
POST /v1/billing/portal | Free | Opens the billing portal (invoices, payment method, cancellation); needs the confirmation code |
GET /v1/status | Free | Data refresh health |
GET /v1/accuracy | Free | Today's accuracy check against the filings themselves |
Tickers accept BRK.B, BRK-B and brk.b. The machine readable spec is at /openapi.json.
Metrics
| Key | Metric | Unit | XBRL concepts, in order of preference |
|---|---|---|---|
revenue | Revenue | Currency of the filing | us-gaap:Revenues, us-gaap:RevenueFromContractWithCustomerExcludingAssessedTax, us-gaap:SalesRevenueNet, us-gaap:RevenueFromContractWithCustomerIncludingAssessedTax, us-gaap:RevenuesNetOfInterestExpense |
net_income | Net income | Currency of the filing | us-gaap:NetIncomeLoss, us-gaap:ProfitLoss, us-gaap:NetIncomeLossAvailableToCommonStockholdersBasic |
eps_basic | Basic EPS | USD/shares | us-gaap:EarningsPerShareBasic, us-gaap:EarningsPerShareBasicAndDiluted |
eps_diluted | Diluted EPS | USD/shares | us-gaap:EarningsPerShareDiluted, us-gaap:EarningsPerShareBasicAndDiluted |
operating_income | Operating income | Currency of the filing | us-gaap:OperatingIncomeLoss |
total_assets | Total assets | Currency of the filing | us-gaap:Assets |
total_liabilities | Total liabilities | Currency of the filing | us-gaap:Liabilities |
equity | Stockholders equity | Currency of the filing | us-gaap:StockholdersEquity, us-gaap:StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest |
cash | Cash and cash equivalents | Currency of the filing | us-gaap:CashAndCashEquivalentsAtCarryingValue, us-gaap:CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalents |
operating_cash_flow | Operating cash flow | Currency of the filing | us-gaap:NetCashProvidedByUsedInOperatingActivities, us-gaap:NetCashProvidedByUsedInOperatingActivitiesContinuingOperations |
capex | Capital expenditures | Currency of the filing | us-gaap:PaymentsToAcquirePropertyPlantAndEquipment |
free_cash_flow | Free cash flow | Currency of the filing | Derived: operating cash flow minus capex |
shares_outstanding | Shares outstanding | shares | dei:EntityCommonStockSharesOutstanding, us-gaap:WeightedAverageNumberOfSharesOutstandingBasic |
revenue_contract | Contract revenue (ASC 606) | Currency of the filing | us-gaap:RevenueFromContractWithCustomerExcludingAssessedTax, us-gaap:RevenueFromContractWithCustomerIncludingAssessedTax |
revenue = total revenue as reported on the income statement. For commercial banks it is total net revenue (net interest income plus noninterest income).
revenue_contract (revenue from contracts with customers under ASC 606) is optional: it is returned only when you ask for it by name, for companies that report it.
Every value
{
"metric": "revenue",
"value": 109417000000,
"unit": "USD",
"period_type": "quarterly",
"period_start": "2026-03-29",
"period_end": "2026-06-27",
"fiscal_year": 2026,
"fiscal_period": "Q3",
"form": "10-Q",
"filed_date": "2026-07-31",
"accession_number": "0000320193-26-000020",
"source_url": "https://www.sec.gov/Archives/edgar/data/320193/000032019326000020/0000320193-26-000020-index.htm",
"concept": "us-gaap:RevenueFromContractWithCustomerExcludingAssessedTax",
"derived": false,
"stale": false
}
derived: truevalues include aderivationobject with the formula and every input, each with its own filing.stale: truemeans the company is past its expected filing date by more than 30 days, or this value is far older than the company's newest report.restated: truemeans a later filing changed the originally reported number; you get the most recently filed value.- A
nullvalue always has areason. - Revenue values carry
revenue_standard:ASC 605,ASC 606ornull.- Method from filing text: we read each company's adoption of ASC 606 from its own SEC filings, including the annual report exhibits that hold its financial statements: the date it adopted and the transition method it states (full retrospective or modified retrospective).
- Date rules: a stated adoption date is used when it falls within 7 days of the start of one of the company's fiscal quarters, or before the company's first reported fiscal year; otherwise we use the period of the filing that states the adoption. A date that conflicts with the company's own earlier filings, or falls outside the possible range, is not used.
- Periods that begin on or after adoption read
ASC 606, and a period that spans adoption isnull. A period before adoption readsASC 605when its value comes from a filing for a period that ended before adoption. When it comes from a later filing, it readsASC 606if the company states the full retrospective method,ASC 605if it states the modified retrospective method, andnullif it states no method or its filings disagree. - Certain
ASC 605: a value from a filing whose fiscal year began before December 16, 2016 readsASC 605for every company, because no company could adopt ASC 606 that early. - Certain
ASC 606: annual periods beginning after December 15, 2019, and every period beginning after December 15, 2020, readASC 606for every company. - Tag dating after adoption: where we find no usable adoption statement,
ASC 606starts with the first fiscal year in which the company's own filing reports revenue from contracts with customers for its current period, and never before its first fiscal year beginning after December 15, 2017 unless the company states it adopted early and its filings do not conflict. nullmeans we can't state the standard, andrevenue_standard_reasonsays why: "period spans adoption", "adoption date unknown", "inputs reported under different standards", "transition method pending a check of the filing text", "transition method not found in the adoption filing", "transition method differs between the company filings", "adoption filing not found", "adoption date in the filing text is outside the possible range", "adoption date conflicts with the company's own filings", "period before SEC registration, method unknown", "before adoption or tagging error, unconfirmed".
- Revenue history uses one reported concept per company where possible. When the concept changes and the periods reported under both concepts differ by more than 1 percent (or no period is reported under both and the change is not the usual switch to the ASC 606 concept), the affected values carry
concept_changed: trueandconcept_changewith the old concept, the new concept and the difference, and the history response adds a note.
How the numbers are built
- Source: SEC company facts data, refreshed nightly, plus each new 10-K and 10-Q read from the filing's own XBRL within about an hour on weekdays.
- When SEC's company facts data has not picked up a filing yet, we read that filing's XBRL directly.
- Quarterly values are the three month figures. When a filing reports only year to date figures, the quarter is the difference between year to date periods and is marked derived.
- Fiscal Q4 equals the annual value minus the nine month value, marked derived. EPS is never derived this way, because per share figures do not add up across periods.
- Trailing twelve months adds the last four quarters (marked derived), or uses the annual value when it is the most recent.
- Amended filings win for the same period.
- Values are in the currency the company reports in, shown in
unit.
Events
GET /v1/events is one feed of SEC filing events across every company, newest first, within about a minute of EDGAR publishing them. EDGAR itself publishes 10 to 30 seconds after it accepts a filing (measured 2026-10-21); the feed reads it once a minute inside EDGAR's 6:00 to 22:00 Eastern window on business days, so a new event is usually in the feed one to two minutes after acceptance. History goes back 90 days from the feed's release and grows from there.
An event is one fact from one filing. Three kinds:
- 8-K items, one event per item filed, by plain name:
| Item | Type | Event |
|---|---|---|
| 1.01 | 8k_material_agreement | Entry into a material agreement |
| 1.03 | 8k_bankruptcy | Bankruptcy or receivership |
| 2.01 | 8k_acquisition_completed | Completion of an acquisition or disposition |
| 2.02 | 8k_results | Results of operations and financial condition |
| 2.04 | 8k_obligation_triggered | Triggering event on a direct financial obligation |
| 3.01 | 8k_listing_notice | Notice of delisting or failure to satisfy a listing rule |
| 4.01 | 8k_accountant_change | Change in the registrant’s certifying accountant |
| 4.02 | 8k_non_reliance | Non reliance on previously issued financial statements |
| 5.02 | 8k_officer_director_change | Departure or appointment of directors or officers |
| 7.01 | 8k_regulation_fd | Regulation FD disclosure |
| 8.01 | 8k_other_events | Other events |
fields carries item, items (every item on the form), period_of_report and amendment.
- Form 4 insider transactions (
form4_transaction), one event per transaction row.fieldscarriesinsider(name, CIK, director, officer, ten percent owner, other, officer title),reporting_owners(every owner on a joint form;insideris the first),issuer_symbol,period_of_report,transaction(date, code, shares, price, acquired or disposed, holdings after, security, direct or indirect ownership, whether it is a derivative, and for a derivative its exercise price, expiration and underlying shares) andamendment. - Schedule 13D and 13G stakes (
13d_stake,13g_stake), one event per filing, on the subject company, whose ticker is the event's ticker.fieldscarriessubject(CIK, name, CUSIP),security_title,date_of_event,reporting_persons(name, CIK, shares, percent of class, sole and shared voting power, type) andamendment. Amendments are events too.
Every event carries type, name, form, filed, accepted_at (EDGAR's acceptance time, UTC), observed_at (when the feed first saw the filing; null for history loaded from EDGAR's daily indexes), accession, url (the SEC filing index), cik (the company the event is about), ticker (null when that company has no listed ticker) and its own cursor. Facts from the filing only: nothing is rated, ranked or interpreted, and nothing here is advice.
{
"id": "0001437749-26-033076:001",
"type": "8k_results",
"name": "Results of operations and financial condition",
"form": "8-K",
"filed": "2026-10-21",
"accepted_at": "2026-10-21T15:16:07.000Z",
"observed_at": null,
"accession": "0001437749-26-033076",
"url": "https://www.sec.gov/Archives/edgar/data/1006830/000143774926033076/0001437749-26-033076-index.htm",
"cik": 1006830,
"ticker": "CBKM",
"fields": { "item": "2.02", "items": ["2.02", "9.01"], "period_of_report": "2026-10-21", "amendment": false },
"cursor": "..."
}
Polling the feed
The first call without since returns the newest events and next. Later calls pass since=<next> and get only what is newer, and next moves forward; it is null only when the feed holds no event yet, so poll again without since. When more than limit events are newer than since, continue is the cursor for the next page of older events: pass before=<continue> together with the same since, and the pages stop at your cursor; without since, before pages back through the whole history. Order is by the time each event was recorded, so a filing that arrives late never slips between two polls. types and tickers are comma lists; limit is 1 to 100 (default 100).
Check before you pay: GET /v1/events/head is free and returns the latest cursor and, with ?since=<cursor>, how many events are newer than it. It is rate limited per address like search. A cursor ahead of the feed's head answers 410 cursor_expired with the current head.
Each /v1/events call counts as 3 calls on a plan, or costs $0.05 by x402. The MCP server offers the same as get_events and the free get_events_head.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A parameter is wrong; fieldErrors says which |
| 401 | invalid_key, auth_required | Missing, unknown or revoked key |
| 402 | Payment required (x402) | |
| 403 | billing_code_required, billing_code_invalid | A billing change needs the confirmation code from your email (POST /v1/billing/code) |
| 404 | unknown_ticker | No SEC registrant for that ticker |
| 410 | cursor_expired | The events cursor is ahead of the feed's head; the answer carries the current head, poll from there |
| 422 | no_financial_data | The company files no 10-K or 10-Q data (for example foreign issuers filing 20-F) |
| 422 | no_data | The company files, but reports none of the values you asked for |
| 429 | rate_limited, quota_exceeded, overage_cap_reached | Slow down, the plan limit is reached, or a paid plan hit its overage cap (3 times the included calls) for the period |
| 500 | internal_error | Our fault; retry |
Calls that return an error do not count toward your quota.
Plans
| Plan | Price | Included | Beyond that | Rate limit |
|---|---|---|---|---|
| Free | Free | 100 calls a day once your email is verified (10 before) | Hard daily cap | 2 per second |
| Starter | $19 a month or $190 a year | 10,000 calls a month | $2 per 1,000 extra calls | 10 per second |
| Pro | $49 a month or $490 a year | 50,000 calls a month | $1 per 1,000 extra calls | 25 per second |
| Scale | $99 a month or $990 a year | 200,000 calls a month | $0.5 per 1,000 extra calls | 50 per second |
Annual billing is 10 times the monthly price (two months free). When you change plans during a period, each plan counts for the share of the period you were on it. Overage already billed is not reversed by a later upgrade.
Changelog
- 2026-10-22: SEC events feed. 8-K items, Form 4 insider transactions and Schedule 13D and 13G stakes across every company, newest first, with 90 days of history;
GET /v1/events, the freeGET /v1/events/head, and the MCP toolsget_eventsandget_events_head. - 2026-10-20: First release. 13 metrics, annual, quarterly and TTM, for 5,392 companies with US GAAP XBRL data.
Legal
Data from SEC filings. Not investment advice. NetNest Design LLC. Company names and tickers are trademarks of their owners, used only to identify the companies; we are not affiliated with or endorsed by them. Terms, Privacy, DMCA. Contact: registrations@netnestdesign.com.