NetNest Design Fundamentals

Fundamentals and SEC filing events for companies that file with the SEC, each value linked to its source filing.

Hosted MCP Server

npx add-mcp 'https://api.netnestdesign.com/mcp'

Installs into Claude Code, Codex, Cursor and more

Documentation

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: true with the inputs used.
  • Missing data comes back as null with 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.

PackageInstallFor
netnest-fundamentals (npm)npm install netnest-fundamentalsTypeScript and JavaScript, plus Vercel AI SDK tools
netnest-fundamentals (PyPI)pip install netnest-fundamentalsPython
langchain-netnestpip install langchain-netnestLangChain tools
llama-index-tools-netnestpip install llama-index-tools-netnestLlamaIndex 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 pathCostWhat it returns
GET /v1/search?q=appleFreeTicker and company name lookup
GET /v1/company/{ticker}PaidCompany profile plus the latest values of key metrics for every period type
GET /v1/fundamentals/{ticker}?metrics=a,b&period=annualPaidThe latest value of each requested metric for one period type (annual, quarterly or ttm)
GET /v1/history/{ticker}/{metric}?period=quarterly&limit=20PaidOne metric over time, newest first, up to 200 periods
GET /v1/events?since=<cursor>&types=&tickers=&limit=100Paid (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>FreeThe latest events cursor and how many events are newer than yours
POST /v1/signupFreeCreates a free account and returns a key
POST /v1/signup/verifyFreeVerifies your email with the code from the welcome email, or sends a fresh code
GET /v1/accountFreeYour plan, usage and keys
POST /v1/keys/rotateFreeIssues a new key and revokes the one you used
DELETE /v1/keys/currentFreeRevokes the key you used
DELETE /v1/accountFreeDeletes your account, keys and usage records (a paying account also sends its confirmation code)
POST /v1/billing/checkoutFreeStarts a paid plan: returns a Stripe Checkout link
POST /v1/billing/codeFreeEmails a one time confirmation code for billing changes; it works once, for 15 minutes
POST /v1/billing/change-planFreeChanges your plan or billing interval; send the confirmation code as code or in an X-Billing-Code header
POST /v1/billing/portalFreeOpens the billing portal (invoices, payment method, cancellation); needs the confirmation code
GET /v1/statusFreeData refresh health
GET /v1/accuracyFreeToday'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

KeyMetricUnitXBRL concepts, in order of preference
revenueRevenueCurrency of the filingus-gaap:Revenues, us-gaap:RevenueFromContractWithCustomerExcludingAssessedTax, us-gaap:SalesRevenueNet, us-gaap:RevenueFromContractWithCustomerIncludingAssessedTax, us-gaap:RevenuesNetOfInterestExpense
net_incomeNet incomeCurrency of the filingus-gaap:NetIncomeLoss, us-gaap:ProfitLoss, us-gaap:NetIncomeLossAvailableToCommonStockholdersBasic
eps_basicBasic EPSUSD/sharesus-gaap:EarningsPerShareBasic, us-gaap:EarningsPerShareBasicAndDiluted
eps_dilutedDiluted EPSUSD/sharesus-gaap:EarningsPerShareDiluted, us-gaap:EarningsPerShareBasicAndDiluted
operating_incomeOperating incomeCurrency of the filingus-gaap:OperatingIncomeLoss
total_assetsTotal assetsCurrency of the filingus-gaap:Assets
total_liabilitiesTotal liabilitiesCurrency of the filingus-gaap:Liabilities
equityStockholders equityCurrency of the filingus-gaap:StockholdersEquity, us-gaap:StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest
cashCash and cash equivalentsCurrency of the filingus-gaap:CashAndCashEquivalentsAtCarryingValue, us-gaap:CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalents
operating_cash_flowOperating cash flowCurrency of the filingus-gaap:NetCashProvidedByUsedInOperatingActivities, us-gaap:NetCashProvidedByUsedInOperatingActivitiesContinuingOperations
capexCapital expendituresCurrency of the filingus-gaap:PaymentsToAcquirePropertyPlantAndEquipment
free_cash_flowFree cash flowCurrency of the filingDerived: operating cash flow minus capex
shares_outstandingShares outstandingsharesdei:EntityCommonStockSharesOutstanding, us-gaap:WeightedAverageNumberOfSharesOutstandingBasic
revenue_contractContract revenue (ASC 606)Currency of the filingus-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: true values include a derivation object with the formula and every input, each with its own filing.
  • stale: true means 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: true means a later filing changed the originally reported number; you get the most recently filed value.
  • A null value always has a reason.
  • Revenue values carry revenue_standard: ASC 605, ASC 606 or null.
    • 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 is null. A period before adoption reads ASC 605 when its value comes from a filing for a period that ended before adoption. When it comes from a later filing, it reads ASC 606 if the company states the full retrospective method, ASC 605 if it states the modified retrospective method, and null if it states no method or its filings disagree.
    • Certain ASC 605: a value from a filing whose fiscal year began before December 16, 2016 reads ASC 605 for 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, read ASC 606 for every company.
    • Tag dating after adoption: where we find no usable adoption statement, ASC 606 starts 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.
    • null means we can't state the standard, and revenue_standard_reason says 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: true and concept_change with 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:
ItemTypeEvent
1.018k_material_agreementEntry into a material agreement
1.038k_bankruptcyBankruptcy or receivership
2.018k_acquisition_completedCompletion of an acquisition or disposition
2.028k_resultsResults of operations and financial condition
2.048k_obligation_triggeredTriggering event on a direct financial obligation
3.018k_listing_noticeNotice of delisting or failure to satisfy a listing rule
4.018k_accountant_changeChange in the registrant’s certifying accountant
4.028k_non_relianceNon reliance on previously issued financial statements
5.028k_officer_director_changeDeparture or appointment of directors or officers
7.018k_regulation_fdRegulation FD disclosure
8.018k_other_eventsOther 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. fields carries insider (name, CIK, director, officer, ten percent owner, other, officer title), reporting_owners (every owner on a joint form; insider is 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) and amendment.
  • Schedule 13D and 13G stakes (13d_stake, 13g_stake), one event per filing, on the subject company, whose ticker is the event's ticker. fields carries subject (CIK, name, CUSIP), security_title, date_of_event, reporting_persons (name, CIK, shares, percent of class, sole and shared voting power, type) and amendment. 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

StatusCodeMeaning
400invalid_requestA parameter is wrong; fieldErrors says which
401invalid_key, auth_requiredMissing, unknown or revoked key
402Payment required (x402)
403billing_code_required, billing_code_invalidA billing change needs the confirmation code from your email (POST /v1/billing/code)
404unknown_tickerNo SEC registrant for that ticker
410cursor_expiredThe events cursor is ahead of the feed's head; the answer carries the current head, poll from there
422no_financial_dataThe company files no 10-K or 10-Q data (for example foreign issuers filing 20-F)
422no_dataThe company files, but reports none of the values you asked for
429rate_limited, quota_exceeded, overage_cap_reachedSlow down, the plan limit is reached, or a paid plan hit its overage cap (3 times the included calls) for the period
500internal_errorOur fault; retry

Calls that return an error do not count toward your quota.

Plans

PlanPriceIncludedBeyond thatRate limit
FreeFree100 calls a day once your email is verified (10 before)Hard daily cap2 per second
Starter$19 a month or $190 a year10,000 calls a month$2 per 1,000 extra calls10 per second
Pro$49 a month or $490 a year50,000 calls a month$1 per 1,000 extra calls25 per second
Scale$99 a month or $990 a year200,000 calls a month$0.5 per 1,000 extra calls50 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 free GET /v1/events/head, and the MCP tools get_events and get_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.