Documentation

Authentication, request examples, error codes, and billing. Download the Markdown file to share.

AkkruData API & MCP — User Guide

This document describes the /data and /metric HTTP APIs: request and response fields, HTTP status codes, credit usage, and rate limits. It is intended for application integrators.

Base URL: https://api.akkrudata.ai/api/v1

Endpoint paths in this guide are appended to that prefix (for example, POST …/data/filings means POST https://api.akkrudata.ai/api/v1/data/filings).


Table of Contents

SectionLink
1. Conventions
└ Authentication
└ Success and error payloads
└ Credits
└ Rate limiting
└ Examples Disclaimer
└ Filing caveats
└ Workflow budgets
└ History truncation notice
└ Coverage scope notice
└ Industry classification (Pro+)
2. Credit summary
3. Rate limits
4. Data API
POST /data/filings
POST /data/company
GET /data/company/list
POST /data/line-items
POST /data/facts
POST /data/statement
POST /data/filing-statements
└ Statement endpoints (/data/income-statement, /comprehensive-income, /balance-sheet, /cash-flow-statement, /equity-statement)
POST /data/facts/dimensional-breakdown
POST /data/line-items/dimensional-breakdown
POST /data/compare/line-items
POST /data/compare/facts
GET …/excel
5. Metrics API
└ Response conventions
└ Supported metric catalog
POST /metric/filings
POST /metric/all
POST /metric/all/filing-date
POST /metric/items
POST /metric/historical
└ Category endpoints (/metric/profitability, /growth, /financial-health, /efficiency, /cash-flow, /valuation, /valuation/filing-date)
6. Screener API
POST /screener/metrics
GET /screener/metrics/filters
└ Filter DSL (/screener/metrics)
└ Credit formula (/screener/metrics)
POST /screener/ownership
└ Filters (/screener/ownership)
└ Credit formula (/screener/ownership)
7. Ownership API
└ Transaction object
POST /ownership/transactions
POST /ownership/stats
POST /ownership/transaction-ids
GET /ownership/tickers
POST /ownership/names
GET /ownership/transaction-types
8. API key, account, and plan errors
9. Request limits (validation)
10. MCP access
└ Connect via OAuth
└ Connect via X-API-Key
└ Tool catalog

1. Conventions

1.1 Authentication

All requests to /data/*, /metric/*, /screener/*, and /ownership/* require:

HeaderValue
X-API-KeyYour API key (create and manage keys in the product dashboard after sign-in).

For POST requests with a JSON body, also send:

HeaderValue
Content-Typeapplication/json

1.2 Success and error payloads

Structured errors return JSON of the form:

{
  "detail": {
    "error_code": "SOME_CODE",
    "message": "Human-readable explanation."
  }
}

Validation errors (error_code: "VALIDATION_ERROR") additionally include a fields array describing each rejected input. Each entry has type (a stable code such as missing, extra_forbidden, int_parsing, string_too_long), loc (path to the field), msg (human text), and input (the value that failed). Use detail.message for a single-line summary and detail.fields if you need per-field structured detail.

A small number of authentication failures (401 missing API key, 403 invalid API key) still return "detail" as a plain string. Any other 4xx and 5xx response uses the object form above.

Plan-tier responses. A request may be rejected because the caller's plan does not include the requested endpoint or option. These return 403 with one of PLAN_TIER_INSUFFICIENT, PLAN_TIER_INSUFFICIENT_HISTORY, PLAN_TIER_INSUFFICIENT_FORMULA_OVERRIDE, or PLAN_TIER_INSUFFICIENT_COVERAGE. The detail body also carries required_tier (the lowest plan that would accept the request) and current_tier (the caller's current plan). See Section 8.

1.3 Credits

Credits are deducted from the account tied to your API key. Amounts and timing are listed under each endpoint and in Section 2. 402 Payment Required indicates insufficient credits for that operation.

1.4 Rate limiting

When limits are exceeded, the API returns 429 Too Many Requests with detail.error_code RATE_LIMIT_EXCEEDED. Limits apply per account across all API keys on that account.

1.5 Examples Disclaimer

Note: All request and response JSON examples in this documentation are provided for reference purposes only. They may be abbreviated or truncated for readability, and the exact structure or available fields are subject to change without prior notice.

1.6 Filing caveats

A filing may carry a free-text disclaimer about its extraction completeness — for example, when a portion of the original filing was deliberately excluded from the extracted facts. When present, the disclaimer surfaces in two places on every endpoint that returns filing information, facts, or statements:

  • A caveat field on the filing information itself (top-level for single-filing responses; per-row in results[] for compare endpoints; per-item in filings[] for the listing endpoint). Either null / absent (no caveat), or a string.
  • A _warnings entry of the form Filing <TICKER> <FORM> FY<YEAR>[ <QUARTER>] has caveat: <text>. Compare endpoints aggregate per-filing caveats into a single deduplicated _warnings list.

The caveat is informational and does not affect billing or response status.

1.7 Workflow budgets

Indicative credit ranges for common workflows, so you can size a plan before you start. Numbers assume L1 (alias) tier on common line-item names (revenue, net income, operating income, etc.). Rarer or ambiguous names land at L2–L3 and cost more; see the tier list in §2.

WorkflowEndpoint patternTypical credits
Discover one company (identity + coverage map)POST /data/company8
List all filings for one company-yearPOST /data/filings10
Pull all three primary statements (income / balance / cash flow) for one filingPOST /data/income-statement + /balance-sheet + /cash-flow-statement84 (28 × 3)
Pull a few specific line items from one filing (3 items × L1)POST /data/line-items60 (3 × 20)
Five-year trend on one metric for one companyPOST /data/line-items × 5 filings, 1 item, L1100 (5 × 20)
Peer comparison: 5 companies × 1 metric × 1 year (L1)POST /data/compare/line-items100 (1 × 20 × 5)
All key metrics snapshot for one company (1 call)POST /metric/all148
Full dimensional breakdown of revenue for one filing (~50 slice facts)POST /data/line-items/dimensional-breakdown~120 (20 + 100)
Download one filing's Excel workbookGET /data/filings/{id}/excel300

Reference: a Starter plan (20,000 credits / month) covers about 330 three-item line-item queries, 240 three-statement pulls, or 135 /metric/all snapshots per month — pick the mix that fits your workflow.

1.8 History truncation notice

List, range, and discovery endpoints attach a generic _warnings entry when results would be larger on a higher plan. Affected endpoints: POST /data/filings, POST /data/company (the coverage map), POST /metric/filings, POST /metric/historical, POST /screener/metrics, and POST /ownership/transactions, POST /ownership/stats, POST /ownership/names, POST /screener/ownership (on filing_date). For /screener/metrics the lookback is additionally auto-clamped to your plan's window so you are only billed for the portion you can access. Single-filing endpoints (/data/facts, /data/statement, /data/line-items, etc.) instead return 403 PLAN_TIER_INSUFFICIENT_HISTORY when the requested filing is out of window. POST /ownership/transaction-ids lists out-of-window ids in restricted_ids and returns that 403 only when every id found is out of scope.

1.9 Coverage scope notice

Each plan covers a subset of companies. Single-company endpoints return 403 PLAN_TIER_INSUFFICIENT_COVERAGE with detail.required_tier when the requested company is outside your plan's scope. /ownership/* endpoints do this whenever the request is anchored on a ticker. List, discovery, /screener/metrics, /screener/ownership, and /ownership/* requests not anchored on a ticker are silently filtered to your plan's scope and attach a generic _warnings entry when companies are excluded. POST /ownership/transaction-ids reports out-of-scope ids in restricted_ids instead.

1.10 Industry classification (Pro+)

Pro-plan and higher responses attach an industry classification block per company on GET /data/company/list, POST /data/compare/line-items, POST /data/compare/facts, and POST /screener/metrics results. Sub-Pro callers receive the same responses without it; attaching it costs no extra credits.

"classification": {
  "sectors": ["Technology"],
  "source": { "scheme": "US_SIC", "code": "3571", "url": "https://www.sec.gov/search-filings/standard-industrial-classification-sic-code-list" }
}
FieldMeaning
sectorsOne or two of the 12 canonical buckets — primary first, plus an optional secondary when a code genuinely spans two.
source.schemeUS_SIC (US, SEC SIC), KR_KSIC (Korea, KSIC), JP_TSE33 (Japan, TSE 33-sector), or EU_ICB (Europe, ICB).
source.codeThe company's official industry code as filed.
source.urlOfficial page to look that code up.

The 12 canonical buckets: Technology, Healthcare, Finance, Consumer Discretionary, Consumer Staples, Communications, Industrials, Energy, Utilities, Materials, Real Estate, Other. POST /screener/metrics (§6.1) and POST /screener/ownership (§6.5) both accept a sectors filter over these.


2. Credit summary

Credit charges for /data, /metric, /screener, and /ownership are as follows.

EndpointCredits
POST /data/filings10 per successful debit. Debited even if the returned filings list is empty.
POST /data/company8 per successful debit. Debited even if DATA_COMPANY_NOT_FOUND is returned.
GET /data/company/list175 per successful debit.
POST /data/line-itemsSum over requested line items: tier L0=10, L1=20, L2=30, L3=50 per line item. If your balance is less than the full sum, you may be charged up to your remaining balance.
POST /data/factsceil(n / 5) × 10 where n is the number of deduplicated fact ids.
POST /data/statement (role_label mode)Tier exact=28, llm=48. If your balance is less than the tier price, you may be charged up to your remaining balance.
POST /data/statement (statement_type mode)28 flat per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING.
POST /data/filing-statements10 per successful debit. Debited even if the filing is missing.
POST /data/income-statement28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING.
POST /data/comprehensive-income28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING.
POST /data/balance-sheet28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING.
POST /data/cash-flow-statement28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING.
POST /data/equity-statement28 per successful debit. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING.
POST /data/facts/dimensional-breakdownceil((1 + N) / 5) × 10 where N is the number of returned slice facts. 10 credits are debited on DATA_FACT_NOT_FOUND.
POST /data/line-items/dimensional-breakdownTier credit for line_item (L0=10 … L3=50) + ceil(N_total / 5) × 10 for returned slice facts. Partial billing applies.
POST /data/compare/line-itemsFor each line item, (tier credits) × (number of filings in the request). Same partial charging as POST /data/line-items when your balance is below the full price.
POST /data/compare/factsceil(total_deduplicated_ids / 5) × 10 across all filing rows.
GET /data/filings/{filing_id}/excel300 when the download is issued.
POST /metric/filings10
POST /metric/all148
POST /metric/all/filing-date148
POST /metric/items148
POST /metric/profitability148
POST /metric/growth148
POST /metric/financial-health148
POST /metric/efficiency148
POST /metric/cash-flow148
POST /metric/valuation148
POST /metric/valuation/filing-date148
POST /metric/historical55 base fee, plus 148 × (number of filing rows returned on the current page). Default page size is 3 filing rows max.
POST /screener/metricsDynamic per request: max(65, 425 − tickerDiscount − lookbackDiscount − quarterlyDiscount + lookbackSurcharge + filterSurcharge + temporalSurcharge + includeSurcharge). Range 89–1825. See §6.4 for the formula. Debited even if results are empty.
GET /screener/metrics/filters10 per call.
POST /ownership/transactions30 per page. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned.
POST /ownership/stats40 base + ceil(n / 1000) × 5, where n is the number of participating transactions. The base is debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned.
POST /ownership/transaction-idsceil(n / 5) × 10 where n is the number of deduplicated ids (max 200).
POST /screener/ownershipDynamic per request: max(65, 200 − tickerDiscount − shortWindowDiscount + fullHistorySurcharge + 40 × conditions). Range 65–920. See §6.7 for the formula. Debited even if results are empty.
GET /ownership/tickers175 per successful debit.
POST /ownership/names30 per successful debit. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned.
GET /ownership/transaction-types0 — static catalog, no charge.
GET /billing/balance0 — free balance check. Returns {"credits_balance": <int>} for the API key's account. Rate-limited at 30/minute.

Metrics resolution tiers (for /data/line-items and /data/compare/line-items): each requested label is classified into L0–L3, which sets that line item’s credit cost. The chosen tier is echoed on each result as _resolution_level ("L0" through "L3"). The response may include _correction and _warnings when resolution is non-trivial.


3. Rate limits

Per-account limits (requests per minute, per route):

MethodPathLimit
POST/data/filings100
POST/data/company100
GET/data/company/list60
POST/data/line-items100
POST/data/facts100
POST/data/statement60
POST/data/filing-statements100
POST/data/income-statement60
POST/data/comprehensive-income60
POST/data/balance-sheet60
POST/data/cash-flow-statement60
POST/data/equity-statement60
POST/data/facts/dimensional-breakdown60
POST/data/line-items/dimensional-breakdown60
POST/data/compare/line-items60
POST/data/compare/facts60
GET/data/filings/{filing_id}/excel20
POST/metric/filings100
POST/metric/all60
POST/metric/all/filing-date60
POST/metric/items60
POST/metric/profitability60
POST/metric/growth60
POST/metric/financial-health60
POST/metric/efficiency60
POST/metric/cash-flow60
POST/metric/valuation60
POST/metric/valuation/filing-date60
POST/metric/historical60
POST/screener/metrics10
GET/screener/metrics/filters60
POST/screener/ownership10
POST/ownership/transactions100
POST/ownership/stats60
POST/ownership/transaction-ids100
GET/ownership/tickers60
POST/ownership/names60
GET/ownership/transaction-types60

4. Data API

Filing caveats apply to every endpoint in this section. When a filing carries a free-text disclaimer, it is echoed as a caveat field on the filing information and mirrored to the response's _warnings list. See §1.6 Filing caveats for the exact shape; per-endpoint sections below only call it out where the placement differs (lists, compare).


4.1 POST /data/filings

Purpose: List filings available for one company and one fiscal year, optionally filtered by form type and quarter.

Request:

FieldTypeRequiredNotes
tickerstringYes1–32 characters; matched case-insensitively.
fiscal_yearintegerYes1990–2100.
form_typestringNoMax 32 characters. US forms: 10-K, 10-Q. Foreign-issuer annual reports: 20-F (US-listed foreign companies), 40-F (Canadian filers). Korean (DART) and Japanese (EDINET) filings use the same values — 10-K for the annual report, 10-Q for the quarterly report. If omitted, all forms for that ticker and year are considered.
quarterstringNoMax 4 characters (e.g. Q1). Use when you need a single quarterly filing among several.

Response:

FieldMeaning
credits_usedAlways 10 when successful.
fiscal_yearEcho of request.
form_typePresent only if you sent form_type.
quarterPresent only if you sent quarter.
companyCompany profile (ticker, cik, legal_name) or null if unknown.
filingsArray of filings: id, ticker, form_type, fiscal_year, quarter, total_facts, total_blocks, has_excel, caveat (see §1.6).

Optional amendment_context may appear on a filing item when restatement or amendment information is available (English summary and optional references).

Errors:

HTTPerror_codeWhen
402CREDITS_INSUFFICIENTNot enough credits.
422Validation (body rules).

Example Request:

{
  "ticker": "AAPL",
  "fiscal_year": 2024,
  "form_type": "10-K"
}

Example MCP tool call:

list_filings(ticker="AAPL", fiscal_year=2024, form_type="10-K")

Example Response:

{
  "credits_used": 10,
  "fiscal_year": 2024,
  "company": {
    "ticker": "AAPL",
    "cik": "0000320193",
    "legal_name": "Apple Inc."
  },
  "filings": [
    {
      "id": 12345,
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2024,
      "quarter": "FY",
      "total_facts": 1500,
      "total_blocks": 12,
      "has_excel": true
    }
  ]
}

4.2 POST /data/company

Purpose: Resolve one company by ticker, cik, dart_corp_code, or edinet_code and return its identity plus a coverage summary — every form_type × fiscal_year × quarter we hold for that issuer. Use this as the entry point when you only know a company name/ticker and need to discover what filings exist.

Request:

FieldTypeRequiredNotes
tickerstringConditionalExactly one of ticker, cik, dart_corp_code, or edinet_code must be provided. 1–32 characters; case-insensitive.
cikstringConditionalNumeric string; zero-padded to 10 digits on the server side. SEC-listed companies only.
dart_corp_codestringConditionalNumeric string; zero-padded to 8 digits on the server side. Korean DART-listed companies only.
edinet_codestringConditionalEDINET issuer code (E + 5 digits). Japanese EDINET-listed companies only.

Response:

FieldMeaning
ticker, cik, dart_corp_code, edinet_code, lei, legal_nameCompany identity. Only the applicable identifier is present — cik for SEC-listed companies, dart_corp_code for Korean companies, edinet_code for Japanese companies, lei for European companies; the others are omitted. legal_name may be absent for rare records.
jurisdiction"US" for SEC-listed companies; "KR" for Korean DART-listed companies; "JP" for Japanese EDINET-listed companies; "EU" for European ESEF-listed companies.
sec_filings_urlEDGAR public browse URL for the company, derived from CIK. Omitted for companies with no CIK (e.g. Korean and Japanese companies).
dart_filings_urlDART public browse URL for the company, derived from dart_corp_code. Omitted for companies with no DART corp code (e.g. US and Japanese companies).
edinet_filings_urlEDINET public browse URL for the company, derived from edinet_code. Omitted for companies with no EDINET code (e.g. US and Korean companies).
esef_filings_urlfilings.xbrl.org public browse URL for the company, derived from lei. Omitted for companies with no LEI.
filings_countTotal filings we hold for this company across all forms and years.
coverageObject keyed by filing-type name. US: SEC form names ("10-K", "10-Q", "20-F", "40-F"). KR / JP / EU: jurisdiction-neutral labels ("annual", "quarterly"). Each value has fiscal_years (sorted list), earliest, latest, fiscal_year_quarters (year → list of quarter labels: "FY", "Q1""Q4"), and normalized_form — a uniform identifier ("annual" / "quarterly") you can use to iterate across jurisdictions without checking the key.
credits_usedAlways 8 when successful.

Charging: A DATA_COMPANY_NOT_FOUND response is still charged 8 credits.

Errors:

HTTPerror_codeWhen
404DATA_COMPANY_NOT_FOUNDNo company on file for the given identifier. Still debits 8 credits.
403PLAN_TIER_INSUFFICIENT_COVERAGEThe requested company is outside your plan's coverage scope.
402CREDITS_INSUFFICIENTNot enough credits.
422Validation (zero or more than one of ticker/cik/dart_corp_code/edinet_code supplied; non-numeric cik or dart_corp_code).

Example Request:

{
  "ticker": "AAPL"
}

Example MCP tool call:

lookup_company(ticker="AAPL")

Example Response:

{
  "ticker": "AAPL",
  "jurisdiction": "US",
  "cik": "0000320193",
  "legal_name": "Apple Inc.",
  "sec_filings_url": "https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0000320193&type=&dateb=&owner=include&count=40",
  "filings_count": 12,
  "coverage": {
    "10-K": {
      "fiscal_years": [2020, 2021, 2022, 2023, 2024],
      "earliest": 2020,
      "latest": 2024,
      "fiscal_year_quarters": {
        "2020": ["FY"],
        "2021": ["FY"],
        "2022": ["FY"],
        "2023": ["FY"],
        "2024": ["FY"]
      },
      "normalized_form": "annual"
    },
    "10-Q": {
      "fiscal_years": [2023, 2024],
      "earliest": 2023,
      "latest": 2024,
      "fiscal_year_quarters": {
        "2023": ["Q1", "Q2", "Q3"],
        "2024": ["Q1", "Q2", "Q3"]
      },
      "normalized_form": "quarterly"
    }
  },
  "credits_used": 8
}

4.3 GET /data/company/list

Purpose: Discovery — return every company covered. Cache the result locally and refresh at most once per day.

Request:

QueryTypeDefaultNotes
jurisdictionstring(omitted)Optional. "US", "KR", "JP", "EU", or "all". When omitted, returns everything your plan includes.

Response:

FieldMeaning
companiesArray of objects sorted by ticker, each with ticker, jurisdiction, and the one identifier that applies — cik (SEC-listed), dart_corp_code (Korean), edinet_code (Japanese), or lei (European); the others are omitted. All are omitted for the rare row whose identifier is not yet on file.
companies[].classificationIndustry classification block — Pro+ only, omitted otherwise. See §1.10.
credits_usedAlways 175 when successful.

Errors:

HTTPerror_codeWhen
403PLAN_TIER_INSUFFICIENT_COVERAGEThe requested jurisdiction is outside your plan's coverage scope.
402CREDITS_INSUFFICIENTNot enough credits.
400JURISDICTION_INVALIDjurisdiction is not one of US, KR, JP, EU, all.

Example Request:

GET /api/v1/data/company/list
X-API-Key: <your-api-key>

Example MCP tool call:

list_companies()

Example Response:

{
  "companies": [
    {"ticker": "AAPL",   "jurisdiction": "US", "cik": "0000320193",
     "classification": {"sectors": ["Technology"], "source": {"scheme": "US_SIC", "code": "3571", "url": "https://www.sec.gov/search-filings/standard-industrial-classification-sic-code-list"}}},
    {"ticker": "MSFT",   "jurisdiction": "US", "cik": "0000789019"},
    {"ticker": "005930", "jurisdiction": "KR", "dart_corp_code": "00126380"},
    {"ticker": "1332",   "jurisdiction": "JP", "edinet_code": "E00014"},
    {"ticker": "VIRI_F", "jurisdiction": "EU", "lei": "969500FCVQ5SLAAUJV59"}
  ],
  "credits_used": 175
}

4.4 POST /data/line-items

Purpose: Return structured facts for one filing by line-item name (e.g. revenue, net income, operating expenses). Names are resolved through a tiered L0–L3 path; per-line-item credit pricing.

Filing selection: supply filing_id, or supply ticker, fiscal_year, form_type (default 10-K), and optional quarter. If filing_id is present with identity fields, filing_id wins.

Request:

FieldTypeRequiredNotes
filing_idintegerConditional1–10⁹. If set, ticker/year fields are optional.
tickerstringConditionalRequired if filing_id omitted. 1–32 characters.
form_typestringNoDefault 10-K, max 32.
fiscal_yearintegerConditionalRequired if filing_id omitted. 1990–2100.
quarterstringNoMax 4 characters.
line_itemsarray of stringYesNon-empty; max 50 entries; each entry max 256 characters.
light_weight_modebooleanNoDefault false. Recommended. When true, each results[*].dimensional_breakdowns is set to null. A notice is appended to _warnings. Charged identically.

Response: ticker, form_type, fiscal_year, quarter, source_url_prefix, results, credits_used, optional _correction / _warnings, optional amendment_context. Each entry in results carries metric, concept, value, raw_value, unit, period, dimensions, dimensional_breakdowns, restated / prior (same meaning as on POST /data/facts; null when the fact was not touched by an amendment), _resolution_level ("L0", "L1", "L2", or "L3"), and one of:

  • fact_id (string) + source_locator (string) — the number appears at exactly one position in the source filing.
  • fact_ids (list of {fact_id, source_locator} objects) — the same logical fact (matching concept, value, period, dimensions, and breakdowns) is reported at multiple positions in the source filing (e.g. income statement + equity statement + cash flow). All positions are listed equal-rank.

The two are mutually exclusive on the wire — a row carries either the singular pair or the plural list, never both. Iterate by reading whichever is present.

is_consolidated_total is a string: "true" (the source filing explicitly tags the value as a consolidated total), "equivalent" (the source filing does not explicitly tag the value as a consolidated total; the attribute was inferred by the akkru engine — a note is appended to _warnings), or "false".

revenue follows each filing's own reported top line. For financial-sector companies (banks, brokers, insurers) that top line is a net figure (e.g. net interest income plus net fee income, or insurance revenue), so it is not directly comparable to the gross sales reported by non-financial companies.

Some filings tag per-share items (dividends per share, share counts) only per share class or dividend type; rows carrying such classifications do not resolve by name. They remain readable in the source statements and notes via POST /data/filing-statements + POST /data/statement.

Credits: tiered L0=10 … L3=50 per line item, partial-credit billing. Zero-balance → HTTP 402.

Errors: DATA_FILING_NOT_FOUND, DATA_FILING_QUARTER_REQUIRED, CREDITS_ZERO_BALANCE.

Example Request:

{
  "filing_id": 12345,
  "line_items": ["revenue", "net income"],
  "light_weight_mode": true
}

Example MCP tool call:

query_line_items(filing_id=12345, line_items=["revenue", "net income"], light_weight_mode=True)

Example response excerpt (one single-position row + one multi-position row):

{
  "results": [
    {
      "metric": "depreciation",
      "concept": "us-gaap_Depreciation",
      "fact_id": "f-665",
      "source_locator": "aapl-20250927.htm#fact-identifier-780",
      "value": 8000000000.0,
      "raw_value": "8.0",
      "unit": "usd",
      "period": "2024-09-29 ~ 2025-09-27",
      "is_consolidated_total": "true",
      "_resolution_level": "L1"
    },
    {
      "metric": "revenue",
      "concept": "us-gaap_RevenueFromContractWithCustomerExcludingAssessedTax",
      "fact_ids": [
        { "fact_id": "f-78",   "source_locator": "aapl-20250927.htm#fact-identifier-95"  },
        { "fact_id": "f-392",  "source_locator": "aapl-20250927.htm#fact-identifier-113" },
        { "fact_id": "f-1021", "source_locator": "aapl-20250927.htm#fact-identifier-121" },
        { "fact_id": "f-1113", "source_locator": "aapl-20250927.htm#fact-identifier-143" }
      ],
      "value": 416161000000.0,
      "raw_value": "416,161",
      "unit": "usd",
      "period": "2024-09-29 ~ 2025-09-27",
      "is_consolidated_total": "true",
      "_resolution_level": "L1"
    }
  ],
  "credits_used": 40
}

4.5 POST /data/facts

Purpose: Return structured facts for one filing by raw XBRL fact_id. For line-item-name queries (e.g. revenue, net income) use POST /data/line-items instead.

Filing selection: supply filing_id, or supply ticker, fiscal_year, form_type (default 10-K), and optional quarter. If filing_id is present with identity fields, filing_id wins.

Request:

FieldTypeRequiredNotes
filing_idintegerConditional1–10⁹. If set, ticker/year fields are optional.
tickerstringConditionalRequired if filing_id omitted. 1–32 characters.
form_typestringNoDefault 10-K, max 32.
fiscal_yearintegerConditionalRequired if filing_id omitted. 1990–2100.
quarterstringNoMax 4 characters.
fact_idsarray of stringYesNon-empty; max 500 strings; each max 128 characters.
light_weight_modebooleanNoDefault false. Recommended. Leaner response — see Light-weight mode below. Charged identically.

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarterFiling identity.
source_url_prefixSEC viewer URL base for this filing. May be null. The API does not return full SEC URLs; callers concatenate source_url_prefix with each fact's source_locator.
resultsArray of facts (each includes metric, concept, fact_id, optional source_locator, values, units, period fields, plus dimensions, dimensional_breakdowns and is_consolidated_total — same meaning as in §4.4). source_locator may be null or a fragment / relative path (amendments may use a ../-relative locator); callers concatenate it with source_url_prefix as-is. Amendment-affected facts also carry restated: true plus a prior object: for a value-changed fact prior holds the superseded value (raw_value / calculated_value / unit / decimals / fact_id / source_locator); for a fact added by the amendment prior is the sentinel { "added_by_amendment": "This fact was not present in the original filing; it was added by an amendment." }. Both fields are always present; on original/unaffected facts they are null.
credits_usedceil(deduped_fact_id_count / 5) × 10.
amendment_contextOptional; same idea as under filings when applicable.
_warningsOptional strings (duplicate ids deduplicated, missing ids not found in the filing, plus the Light-weight mode notice when that flag is on).

Light-weight mode (light_weight_mode=true): each results[*].dimensional_breakdowns is set to null. A notice is appended to _warnings.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDSeveral filings match without a quarter; message lists available quarters.
404DATA_FILING_NOT_FOUNDNo filing for the given id or identity.
402CREDITS_INSUFFICIENTNot enough credits.
422Validation (empty fact_ids, limits, missing filing selector).

Example Request:

{
  "filing_id": 12345,
  "fact_ids": ["ix_1", "ix_2"]
}

Example MCP tool call:

get_filing_facts(filing_id=12345, fact_ids=["ix_1", "ix_2"])

4.6 POST /data/statement

Purpose: Return one or more financial statement block(s) (JSON) for a filing. Two mutually exclusive lookup modes:

  • role_label mode — the filer's original XBRL role string (varies per filer; e.g. "CONSOLIDATED STATEMENTS OF OPERATIONS" for Apple). Resolved through a tiered exact / llm path against the filing's role labels. Returns the one matched block.
  • statement_type mode — the canonical statement name (e.g. "Income Statement", "Balance Sheet", "Comprehensive Income", "Stockholders Equity", "Cash Flow Statement"). Call POST /data/filing-statements for the valid values in a specific filing. Case-insensitive; trailing (N) suffix is ignored. Returns every matching block. Not yet available for Korean (DART), Japanese (EDINET), or European (ESEF) filings — coming soon (not charged); use role_label mode for KR/JP/EU.

For the 5 main statements prefer the dedicated statement endpoints (/data/income-statement etc.) — same response shape, with the target spelled in the URL.

Filing selection: same pattern as POST /data/facts (filing_id or ticker + fiscal_year + form_type + optional quarter).

Request:

FieldTypeRequiredNotes
filing_idintegerConditionalSame rules as facts.
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo
role_labelstringXOR statement_type1–4000 characters; original filer XBRL role string.
statement_typestringXOR role_label1–4000 characters; canonical statement-type label.
light_weight_modebooleanNoDefault false. Recommended. Leaner response — see Light-weight mode below. Charged identically.

Credits:

  • role_label mode: tiered 28 (exact) / 48 (llm), partial-credit billing. Zero-balance → HTTP 402.
  • statement_type mode: 28 flat. No charge for DATA_STATEMENT_NOT_AVAILABLE_IN_FILING.

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarterFiling identity.
matchesArray of match objects (length 1 for role_label mode; length 1+ for statement_type mode). Each has block_index, role_label, statement_type, matched_via (describes how it was selected), and block (the full statement block content).
credits_usedNumber of credits deducted.
amendment_contextOptional; restatement or amendment information.
_correctionOptional; present on the llm match tier.
_warningsOptional; includes the Light-weight mode notice when that flag is on.

Light-weight mode (light_weight_mode=true) — applied to every match's block:

  • block.child_components → replaced by a placeholder string
  • In every block.parent_xbrl_table.mapped_xbrl_facts[*]:
    • xbrl_fact: concept_ns, concept_local, item_type, decimals, sign_attr, sign_from_xbrl, format
    • html_locator: xlsx_sheet, xlsx_cell

A notice is appended to _warnings.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDAmbiguous quarterly filings.
404DATA_FILING_NOT_FOUNDFiling not found.
404DATA_STATEMENT_ROLE_LABEL_UNRESOLVEDrole_label mode: no block matched; charged for the match tier reached.
404DATA_STATEMENT_NOT_AVAILABLE_IN_FILINGstatement_type mode: no block has this statement_type (not charged).
400DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_KRstatement_type mode: Korean (DART) filings not yet supported — coming soon (not charged).
400DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_JPstatement_type mode: Japanese (EDINET) filings not yet supported — coming soon (not charged).
400DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_EUstatement_type mode: European (ESEF) filings not yet supported — coming soon (not charged).
404DATA_STATEMENT_BLOCK_JSON_MISSINGLabel matched but the block content is unavailable (charged).
402CREDITS_INSUFFICIENT / CREDITS_ZERO_BALANCEstatement_type mode: insufficient for the flat price; role_label mode: zero balance.
422Validation (e.g. both role_label and statement_type given, or neither).

Example Request (role_label mode):

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "role_label": "CONSOLIDATED STATEMENTS OF OPERATIONS"
}

Example Request (statement_type mode):

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "statement_type": "Income Statement"
}

Example MCP tool call:

get_filing_statement(ticker="AAPL", form_type="10-K", fiscal_year=2024,
                    statement_type="Income Statement")

Example Response:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "quarter": "FY",
  "matches": [
    {
      "block_index": 1,
      "role_label": "CONSOLIDATED STATEMENTS OF OPERATIONS",
      "statement_type": "Income Statement",
      "matched_via": {
        "source": "statement_type",
        "query": "Income Statement",
        "matched_statement_type": "Income Statement"
      },
      "block": { "elements": [ "... truncated ..." ] }
    }
  ],
  "credits_used": 28
}

4.7 POST /data/filing-statements

Purpose: Discovery — list every statement block in a filing with its block_index, statement_type (canonical statement-type label; may be null for non-financial blocks such as the cover page), and role_label (filer-specific XBRL string). Use this to find out exactly which statement_type / role_label values a specific filing exposes before calling POST /data/statement or the convenience endpoints.

Filing selection: standard (filing_id or ticker + fiscal_year + form_type + optional quarter).

Request:

FieldTypeRequiredNotes
filing_idintegerConditional
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarterFiling identity.
statementsArray of {block_index, statement_type, role_label}, ordered by block_index.
credits_usedAlways 10 when successful.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDAmbiguous quarterly filings.
404DATA_FILING_NOT_FOUNDFiling not found. Still charged 10 credits (this matches /data/filings and /data/company — discovery endpoints charge to cover the lookup attempt).
402CREDITS_INSUFFICIENTInsufficient credits.
422Validation.

Example Request:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024
}

Example MCP tool call:

list_filing_statements(ticker="AAPL", form_type="10-K", fiscal_year=2024)

Example Response:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "quarter": "FY",
  "statements": [
    { "block_index": 0, "statement_type": null,                  "role_label": "Cover Page" },
    { "block_index": 1, "statement_type": "Income Statement",    "role_label": "CONSOLIDATED STATEMENTS OF OPERATIONS" },
    { "block_index": 2, "statement_type": "Comprehensive Income","role_label": "CONSOLIDATED STATEMENTS OF COMPREHENSIVE INCOME" },
    { "block_index": 3, "statement_type": "Balance Sheet",       "role_label": "CONSOLIDATED BALANCE SHEETS" },
    { "block_index": 4, "statement_type": "Stockholders Equity", "role_label": "CONSOLIDATED STATEMENTS OF SHAREHOLDERS' EQUITY" },
    { "block_index": 5, "statement_type": "Cash Flow Statement", "role_label": "CONSOLIDATED STATEMENTS OF CASH FLOWS" },
    { "block_index": 6, "statement_type": "Earnings Per Share",  "role_label": "Earnings Per Share - Computation of Basic and Diluted..." }
  ],
  "credits_used": 10
}

4.8 Statement endpoints (/data/<statement>)

Five endpoints that fetch one specific statement directly by URL. Each is equivalent to POST /data/statement with the matching statement_type — fixed by the URL path, so role_label and statement_type are not accepted in the body. Flat 28 credits per successful debit, rate limit 60/minute. No charge on DATA_STATEMENT_NOT_AVAILABLE_IN_FILING. Not yet available for Korean (DART), Japanese (EDINET), or European (ESEF) filings — coming soon (not charged).

EndpointStatement returned
POST /data/income-statementIncome Statement
POST /data/comprehensive-incomeStatement of Comprehensive Income
POST /data/balance-sheetBalance Sheet
POST /data/cash-flow-statementCash Flow Statement
POST /data/equity-statementStatement of Stockholders' / Shareholders' Equity

Request body: same fields as POST /data/statement minus role_label and statement_type.

FieldTypeRequiredNotes
filing_idintegerConditional
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo
light_weight_modebooleanNoDefault false. Recommended.

Response: identical to POST /data/statement (matches: [...]). matched_via.source is always "statement_type".

Errors: identical to POST /data/statement (statement_type mode).

Example request:

{ "ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2024 }

Example MCP tool calls:

get_income_statement(ticker="AAPL", form_type="10-K", fiscal_year=2024, light_weight_mode=True)
get_comprehensive_income(ticker="AAPL", form_type="10-K", fiscal_year=2024)
get_balance_sheet(ticker="AAPL", form_type="10-K", fiscal_year=2024)
get_cash_flow_statement(ticker="AAPL", form_type="10-K", fiscal_year=2024)
get_equity_statement(ticker="AAPL", form_type="10-K", fiscal_year=2024)

4.9 POST /data/facts/dimensional-breakdown

Purpose: Return one consolidated fact plus every slice fact it breaks down into. Slice facts are grouped by the set of XBRL axes their dimensions sit on.

Filing selection: standard (filing_id or ticker + fiscal_year + form_type + optional quarter).

Request:

FieldTypeRequiredNotes
filing_idintegerConditional
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo
fact_idstringYesThe fact_id of a consolidated fact.
recursivebooleanNoDefault true. When false, only the immediate children are returned.

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarter, source_url_prefixFiling identity.
rootThe fact identified by fact_id: concept, value, raw_value, unit, period, dimensions, is_consolidated_total, fact_id, source_locator. The metric, fact_ids, restated, prior, and dimensional_breakdowns fields of POST /data/facts are not returned here.
groupsArray of {axes, facts} entries. axes is the sorted list of XBRL axis keys shared by every fact in facts; facts is the list of slice facts. Sorted by descending fact count, ties broken lexicographically by axes.
groups[].facts[].groupsPresent only when recursive=true. Same shape, nested per level.
_warningsOptional.
credits_usedceil((1 + N) / 5) × 10, where N is the number of returned slice facts.

Member granularity within a group: A single axis may carry both summary members and their detail components. Summary members overlap their detail components, so summing all facts in one group can double-count.

Credits: ceil((1 + N) / 5) × 10. 10 credits are charged on DATA_FACT_NOT_FOUND. A root with no breakdowns returns 200 with groups: [] and is charged 10 credits.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDAmbiguous quarterly filings.
404DATA_FILING_NOT_FOUNDFiling not found.
404DATA_FACT_NOT_FOUNDfact_id is not present in this filing. Still charged 10 credits.
402CREDITS_INSUFFICIENTNot enough credits.
422Validation.

Example Request:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2025,
  "fact_id": "f-78"
}

Example MCP tool call:

get_dimensional_breakdown_by_fact_id(
    ticker="AAPL", form_type="10-K", fiscal_year=2025, fact_id="f-78"
)

Example Response (abridged):

{
  "ticker": "AAPL", "form_type": "10-K",
  "fiscal_year": 2025, "quarter": "FY",
  "source_url_prefix": "...",
  "root": {
    "concept": "us-gaap_RevenueFromContractWithCustomerExcludingAssessedTax",
    "fact_id": "f-78",
    "value": 416161000000.0,
    "raw_value": "416,161",
    "unit": "usd",
    "period": "2024-09-29 ~ 2025-09-27",
    "is_consolidated_total": "true",
    "dimensions": []
  },
  "groups": [
    {
      "axes": ["srt_ProductOrServiceAxis"],
      "facts": [
        {"concept": "us-gaap_RevenueFromContractWithCustomerExcludingAssessedTax",
         "fact_id": "f-72", "value": 307003000000.0,
         "dimensions": [{"axis": "srt_ProductOrServiceAxis","member": "us-gaap_ProductMember"}],
         "groups": []},
        {"fact_id": "f-377", "value": 209586000000.0,
         "dimensions": [{"axis": "srt_ProductOrServiceAxis","member": "aapl_IPhoneMember"}],
         "groups": []}
      ]
    },
    {
      "axes": ["srt_ConsolidationItemsAxis","us-gaap_StatementBusinessSegmentsAxis"],
      "facts": [
        {"fact_id": "f-1016", "value": 178353000000.0,
         "dimensions": [
           {"axis":"srt_ConsolidationItemsAxis","member":"us-gaap_OperatingSegmentsMember"},
           {"axis":"us-gaap_StatementBusinessSegmentsAxis","member":"aapl_AmericasSegmentMember"}
         ],
         "groups": []}
      ]
    },
    {
      "axes": ["srt_StatementGeographicalAxis"],
      "facts": [
        {"fact_id": "f-1104", "value": 151790000000.0,
         "dimensions": [{"axis":"srt_StatementGeographicalAxis","member":"country_US"}],
         "groups": []}
      ]
    }
  ],
  "credits_used": 28
}

4.10 POST /data/line-items/dimensional-breakdown

Purpose: Resolve a line-item name (e.g. revenue, net income) and return the dimensional breakdown of every consolidated fact that matches. Each match is one root with its axis-grouped slice facts.

Filing selection: standard (filing_id or ticker + fiscal_year + form_type + optional quarter).

Request:

FieldTypeRequiredNotes
filing_idintegerConditional
tickerstringConditional
form_typestringNoDefault 10-K.
fiscal_yearintegerConditional
quarterstringNo
line_itemstringYesA single line-item name (e.g. "revenue").
recursivebooleanNoDefault true.

Response:

FieldMeaning
ticker, form_type, fiscal_year, quarter, source_url_prefixFiling identity.
matchesArray of {root, groups, duplicate_root_fact_ids?} entries.
matches[].rootSame shape as root in POST /data/facts/dimensional-breakdown, plus metric (echoes the request line_item) and _resolution_level ("L0""L3").
matches[].groupsSame shape and ordering as groups in POST /data/facts/dimensional-breakdown. Each fact also carries metric and _resolution_level.
matches[].duplicate_root_fact_idsOptional. Other fact_id values that resolved to the same logical fact as root.
_correctionOptional. Same shape as on POST /data/line-items.
_warningsOptional.
credits_usedResolver tier credit + ceil(N_total / 5) × 10, where N_total is the slice facts returned across all roots.

Member granularity within a group: Same as POST /data/facts/dimensional-breakdown — summary members and their detail components may coexist; summing all facts in one group can double-count.

Credits: Tiered resolution credit (L0=10 … L3=50) + ceil(N_total / 5) × 10. Partial billing applies.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDAmbiguous quarterly filings.
404DATA_FILING_NOT_FOUNDFiling not found.
402CREDITS_ZERO_BALANCEBalance is zero.
402CREDITS_INSUFFICIENTInsufficient credits.
422Validation.

Example Request:

{
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2025,
  "line_item": "revenue"
}

Example MCP tool call:

get_dimensional_breakdown_by_line_item(
    ticker="AAPL", form_type="10-K", fiscal_year=2025, line_item="revenue"
)

Example Response (abridged):

{
  "ticker": "AAPL", "form_type": "10-K",
  "fiscal_year": 2025, "quarter": "FY",
  "source_url_prefix": "...",
  "matches": [
    {
      "root": {
        "metric": "revenue",
        "concept": "us-gaap_RevenueFromContractWithCustomerExcludingAssessedTax",
        "fact_id": "f-78",
        "value": 416161000000.0,
        "period": "2024-09-29 ~ 2025-09-27",
        "is_consolidated_total": "true",
        "dimensions": [],
        "_resolution_level": "L1"
      },
      "duplicate_root_fact_ids": ["f-392","f-1021","f-1113"],
      "groups": [ /* same shape as 4.9 */ ]
    },
    {
      "root": { "metric": "revenue", "fact_id": "f-79",
                "value": 391035000000.0, "period": "2023-10-01 ~ 2024-09-28", "_resolution_level": "L1", "..." : "..." },
      "duplicate_root_fact_ids": ["f-393","f-1050","f-1114"],
      "groups": [ /* ... */ ]
    },
    {
      "root": { "metric": "revenue", "fact_id": "f-80",
                "value": 383285000000.0, "period": "2022-09-25 ~ 2023-09-30", "_resolution_level": "L1", "..." : "..." },
      "duplicate_root_fact_ids": ["f-394","f-1079","f-1115"],
      "groups": [ /* ... */ ]
    }
  ],
  "credits_used": 110
}

4.11 POST /data/compare/line-items

Purpose: Compare a list of line-item names (e.g. revenue, net income) across up to 25 filings. Names are resolved through the same L0–L3 tiered path as POST /data/line-items; per-line-item × per-filing pricing applies.

Request:

FieldTypeRequiredNotes
filingsarrayYes1–25 rows. Each row: filing_id or (ticker + fiscal_year + form_type + optional quarter), same resolution rules as POST /data/facts. No fact_ids field on rows.
line_itemsarray of stringYesNon-empty; max 50 strings; each max 256 chars.
light_weight_modebooleanNoDefault false. Recommended. Leaner response — see Light-weight mode below. Charged identically.

Response:

FieldMeaning
amendment_contextsArray parallel to results; each entry is an object or null.
resultsEach element: ticker, form_type, fiscal_year, quarter, source_url_prefix (filing-level SEC URL base, may be null), optional caveat (per-row; see §1.6), facts (array of fact objects; each fact includes optional source_locator as in POST /data/facts, plus _resolution_level = "L0""L3" indicating which tier matched that line item), and — for Pro+ callers — a per-row classification block (see §1.10).
credits_usedPer credit rules in Section 2.
_correction, _warningsOptional; same general meaning as POST /data/line-items. The dimensional-breakdown notice is aggregated into a single string listing affected filings + fact ids. Per-row caveats are also aggregated into top-level _warnings (deduplicated; see §1.6).

Light-weight mode (light_weight_mode=true): each results[*].facts[*].dimensional_breakdowns is set to null. A notice is appended to top-level _warnings.

Partial-credit behavior: This endpoint charges per line item × per filing with partial-credit billing. If your balance is too low to cover the full request mid-run, later line items will return as unresolved rather than abort the whole call; check _warnings / _correction to see which were skipped, then top up and re-issue for the rest.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDA row needs quarter to disambiguate.
404DATA_FILING_NOT_FOUNDA row’s filing does not exist (message may reference row index).
402CREDITS_ZERO_BALANCEZero balance.
422Limits, missing line_items, or other validation.

Example Request:

{
  "filings": [
    { "ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2024 },
    { "ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2023 }
  ],
  "line_items": ["revenue"]
}

Example MCP tool call:

compare_line_items(
    filings=[
        {"ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2024},
        {"ticker": "AAPL", "form_type": "10-K", "fiscal_year": 2023},
    ],
    line_items=["revenue"],
)

Example Response:

{
  "amendment_contexts": [null, null],
  "results": [
    {
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2024,
      "quarter": "FY",
      "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20240928.htm",
      "facts": [
        {
          "metric": "revenue",
          "concept": "us-gaap_Revenue...",
          "fact_id": "f-1",
          "source_locator": "#fact-identifier-f-1",
          "value": 383285000000.0
        }
      ]
    },
    {
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2023,
      "quarter": "FY",
      "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20230930.htm",
      "facts": [
        {
          "metric": "revenue",
          "concept": "us-gaap_Revenue...",
          "fact_id": "f-1",
          "source_locator": "#fact-identifier-f-1",
          "value": 394328000000.0
        }
      ]
    }
  ],
  "credits_used": 80
}

4.12 POST /data/compare/facts

Purpose: Compare XBRL fact_ids across up to 25 filings. Each filing row carries its own fact_ids list.

Request:

FieldTypeRequiredNotes
filingsarrayYes1–25 rows. Each row: filing_id or (ticker + fiscal_year + form_type + optional quarter), plus a required non-empty fact_ids list (max 500 per row; 2500 total ids across the whole request; each id ≤ 128 chars).
light_weight_modebooleanNoDefault false. Recommended. Leaner response — see Light-weight mode below. Charged identically.

Response: Same shape as POST /data/compare/line-items.

Light-weight mode (light_weight_mode=true): each results[*].facts[*].dimensional_breakdowns is set to null. A notice is appended to top-level _warnings.

Partial-credit behavior: Full request cost is ceil(total_deduped_fact_ids / 5) × 10 credits. The endpoint uses partial-credit billing, so if your balance can only cover part of the request you'll be charged that much and the response serves a proportional subset of the fact_ids (each 10 credits buy up to 5 ids; filings are processed in request order — once the budget runs out the remaining filings come back with facts: []). A _warnings[0] line states how many ids were served vs requested, and credits_used reflects what was actually spent. Zero balance → HTTP 402.

Errors:

HTTPerror_codeWhen
400DATA_FILING_QUARTER_REQUIREDA row needs quarter to disambiguate.
404DATA_FILING_NOT_FOUNDA row’s filing does not exist.
402CREDITS_INSUFFICIENTBalance is zero.
422Limits, missing fact_ids, or other validation.

Example Request:

{
  "filings": [
    { "filing_id": 12345, "fact_ids": ["ix_1", "ix_2"] },
    { "filing_id": 12344, "fact_ids": ["ix_1"] }
  ]
}

Example MCP tool call:

compare_facts(
    filings=[
        {"filing_id": 12345, "fact_ids": ["ix_1", "ix_2"]},
        {"filing_id": 12344, "fact_ids": ["ix_1"]},
    ],
)

4.13 GET /data/filings/{filing_id}/excel

Purpose: Obtain a time-limited download URL for the filing’s Excel attachment when the file is available.

Path parameter: filing_id (integer).

Response:

FieldMeaning
ticker, fiscal_yearFiling identity.
download_urlThe time-limited URL to download the Excel file.
expires_inExpiration time of the URL in seconds (e.g., 3600).
credits_usedAlways 300 when successful.

Errors:

HTTPerror_codeWhen
404DATA_FILING_NOT_FOUNDUnknown filing_id.
404DATA_EXCEL_NOT_AVAILABLE_FOR_FILINGNo Excel attachment on file.
404DATA_EXCEL_OBJECT_NOT_IN_STORAGEThe Excel file is not available.
503DATA_EXCEL_PUBLIC_URL_UNAVAILABLEA download URL cannot be provided for this request.
402CREDITS_INSUFFICIENTInsufficient credits.

Example MCP tool call:

get_filing_excel(filing_id=12345)

Example Response:

{
  "ticker": "AAPL",
  "fiscal_year": 2024,
  "download_url": "https://api.akkrudata.ai/...",
  "expires_in": 3600,
  "credits_used": 300
}

5. Metrics API

All routes accept X-API-Key as in Section 1. Endpoints in this section require the Starter plan or higher; Free callers receive 403 PLAN_TIER_INSUFFICIENT (see Section 8). The formula_override request field is additionally gated to the Pro plan or higher — Starter callers can use these endpoints but must omit formula_override.


Response conventions

Every metric returned by /metric/* endpoints carries a status field and a derivation field. The rest of the object's contents depend on these two.

status

ValueMeaning
okMetric was computed; value is set.
not_applicableMetric does not apply to this filing. Carries a reason string; value is null.
missing_inputA required XBRL fact is missing. Carries a missing_symbols list; value is null.
needs_price_dataPrice-sensitive metric called without current_price. value is null; pass current_price to upgrade to ok.
needs_user_formulaThe filing uses a non-standard concept combination. Pass accept_suggested_formula=true or supply formula_override to compute. value is null; a suggested_formula field is included.
needs_historyA prior-period value is required (e.g. growth rates) but is not available from this filing's payload. value is null.
divide_by_zeroDenominator was zero. value is null.
eval_errorFormula execution failed. value is null.

not_applicable takes precedence over every other status — once an NA rule fires for a metric, the response will be not_applicable regardless of what would otherwise apply.

derivation

ValueMeaning
derivedComputed from multiple XBRL facts via the standard formula.
as_reportedSingle XBRL fact taken at face value, no formula run.
compositeBuilt from multiple non-standard concepts (e.g. REIT CapEx = REInvestment + Maintenance).
segment_sumNo consolidated total in the filing; summed across segment members.
class_sumSummed across asset / liability class members.
company_overrideA company-specific override rule produced the value.
proxy_substitutedA proxy fact was used in place of the primary one (most often on ADR / foreign-issuer price-sensitive metrics).
TTM_rollforwardOn quarterly filings, the engine has rolled the metric forward to a trailing-12-month value. Comparable to annual filings of the same metric without further adjustment.
user_formula_acceptedResult of accept_suggested_formula=true — the engine's own suggested_formula was applied.
user_formula_customResult of a caller-supplied formula_override.
user_must_computeCompanion to status="needs_user_formula". Engine cannot compute automatically.
not_applicableCompanion to status="not_applicable".

When a metric cannot be computed, derivation does not name a computation path — it mirrors that metric's status, so values such as missing_input and needs_price_data also appear here. Branch on status first.

Currency and FX

A metric object may carry these three currency-related fields:

FieldMeaning
unitDisplay unit. Either a currency code (usd, eur, twd, …) for absolute monetary metrics, or ratio / percent / days / shares etc. for non-monetary metrics.
currencySource currency for absolute monetary metrics. Absent on ratio / percent / unitless metrics.
fx_requiredtrue when the metric is denominated in a non-USD currency (caller may want to convert to USD before using the value). false when no conversion is needed (already USD, or unitless).

For price-sensitive metrics on foreign-issuer filings (20-F / 40-F whose reporting_currency is not USD), the metric object also carries a price_used block:

SubfieldMeaning
closeThe price actually used in the formula (in the filer's reporting currency).
dateDate of close.
sourceSource identifier (e.g. local_csv).
original_adr_price_usdThe USD ADR price supplied (or filing-date USD price).
adr_ratioADR ratio (number of common shares per ADR).
fx_rate_local_per_usdConversion factor used for the period.
reporting_ccyFiler's reporting currency (e.g. EUR, TWD, CAD).

To convert a foreign-issuer absolute metric to USD:

value_usd = value / fx_rate_local_per_usd

For USD-reporting filings, fx_required is false, currency (when present) is usd, and price_used contains only close, date, source.

Light-weight mode

All /metric/* endpoints accept light_weight_mode (boolean, default false). When true, each returned metric object is reduced to its essential fields. The following per-metric fields are removed:

FieldRemoved in light-weight mode
components
fact_refs
formula_expression
computed_as
tried_concepts
caveat
missing_symbols

Fields retained: value, status, derivation, unit, currency, fx_required, fx_rate_used, formula, price_used, and any per-metric flags (split_adjusted_value etc.).

A notice is appended to _warnings. Credits are charged identically. Re-issue with light_weight_mode=false (or omit it) for the full payload.


5.0 Supported metric catalog

The API exposes 43 metrics, listed below by category. Use the name column verbatim wherever the API or MCP tools take a metric id (e.g. metric_names on POST /metric/items, formula_override keys, metric_names on POST /metric/historical). Names marked are price-sensitive — their realtime values require current_price in the request body (see §5.2).

Profitability (4)

NameUnitFormula
gross_marginratio(Revenue - CostOfRevenue) / Revenue
operating_marginratioOperatingIncome / Revenue
net_marginratioNetIncome / Revenue
ebitda_marginratio(OperatingIncome + DepreciationAndAmortization) / Revenue

Returns (4)

NameUnitFormula
return_on_equityratioNetIncome / ((Equity + EquityPrior) / 2)
return_on_assetsratioNetIncome / ((Assets + AssetsPrior) / 2)
return_on_invested_capitalratioNetIncome / (((Equity + LongTermDebt + ShortTermDebt) + (EquityPrior + LongTermDebtPrior + ShortTermDebtPrior)) / 2)
return_on_tangible_equityratioNetIncome / (((Equity - Goodwill - Intangibles) + (EquityPrior - GoodwillPrior - IntangiblesPrior)) / 2)

Leverage (4)

NameUnitFormula
debt_to_equityratio(LongTermDebt + ShortTermDebt) / Equity
debt_to_assetsratio(LongTermDebt + ShortTermDebt) / Assets
debt_to_ebitdaratio(LongTermDebt + ShortTermDebt) / (OperatingIncome + DepreciationAndAmortization)
interest_coverageratioOperatingIncome / InterestExpense

Liquidity (3)

NameUnitFormula
current_ratioratioCurrentAssets / CurrentLiabilities
quick_ratioratio(CurrentAssets - Inventory) / CurrentLiabilities
cash_ratioratioCash / CurrentLiabilities

Efficiency / activity (7)

NameUnitFormula
asset_turnoverratioRevenue / ((Assets + AssetsPrior) / 2)
inventory_turnoverratioCostOfRevenue / Inventory
receivables_turnoverratioRevenue / AccountsReceivable
days_inventorydaysPeriodDays * Inventory / CostOfRevenue
days_receivabledaysPeriodDays * AccountsReceivable / Revenue
days_payabledaysPeriodDays * AccountsPayable / CostOfRevenue
cash_conversion_cycledaysdays_inventory + days_receivable − days_payable

Cash flow & shareholder returns (3)

NameUnitFormula
free_cash_flowreporting currencyCFO - Capex
fcf_marginratio(CFO - Capex) / Revenue
payout_ratioratioDividends / NetIncome

Valuation — price-sensitive (12) ★

These require current_price in the request body to compute their realtime values; without it the realtime block returns the standard missing-price hint instead.

Tip: populate current_price from any realtime quote source (e.g. Finnhub, Alpha Vantage, yfinance).

NameUnitFormula
market_capreporting currencySharesOutstanding * Price
enterprise_valuereporting currencyMarketCap + LongTermDebt + ShortTermDebt - Cash
pe_ratioratioPrice / EPS
price_to_bookratioMarketCap / Equity
price_to_salesratioMarketCap / Revenue
price_to_cash_flowratioMarketCap / CFO
ev_to_ebitdaratioEnterpriseValue / (OperatingIncome + DepreciationAndAmortization)
ev_to_revenueratioEnterpriseValue / Revenue
ev_to_fcfratioEnterpriseValue / (CFO - Capex)
fcf_yieldratio(CFO - Capex) / MarketCap
dividend_yieldratioDividendsPerShare / Price
buyback_yieldratioStockRepurchases / MarketCap

Growth (6)

Year-over-year (yoy) growth compares the current period to the same period one year earlier; quarter-over-quarter (qoq) compares the current quarter to the immediately preceding quarter.

NameUnitFormula
revenue_growth_yoyratio(Revenue_t - Revenue_{t-4Q}) / Revenue_{t-4Q}
revenue_growth_qoqratio(Revenue_t - Revenue_{t-1Q}) / Revenue_{t-1Q}
revenue_growth_qoq_single_quarterratio(Revenue_Qn_single - Revenue_Q(n-1)_single) / Revenue_Q(n-1)_single
eps_growth_yoyratio(EPS_t - EPS_{t-4Q}) / EPS_{t-4Q}
net_income_growth_yoyratio(NI_t - NI_{t-4Q}) / NI_{t-4Q}
fcf_growth_yoyratio(FCF_t - FCF_{t-4Q}) / FCF_{t-4Q}

Notes:

  • A given filing may not have every metric — values requiring symbols absent from that filing simply do not appear in the response. The catalog above lists everything the API can return, not what every filing contains.
  • Non-USD reporters (20-F / 40-F filings whose reporting_currency is e.g. brl, eur) report free_cash_flow and market_cap / enterprise_value in their local currency; the per-metric unit field carries the actual currency.

5.1 POST /metric/filings

Purpose: List filings for a ticker that have metrics available, returning one row per filing with identifiers you use as metric_group_id on other metric routes.

Request:

FieldTypeRequiredNotes
tickerstringYes1–32 characters.
fiscal_yearintegerConditional1990–2100. You must supply fiscal_year or a valid as_of_date (YYYY-MM-DD). A blank or invalid date does not satisfy the requirement.
form_typesarray of stringNoMax 8 entries; each max 32 characters.
quarterstringNoMax 4 characters.
as_of_datestringNoIf non-empty and invalid, it is echoed as "error" in the response and ignored for filtering; a warning may be returned.

Response:

FieldMeaning
credits_usedAlways 10 when successful.
fiscal_yearEcho of request.
as_of_dateEcho of request (or "error" if invalid).
companyCompany profile (ticker, cik, legal_name) or null.
metric_groupsArray of objects; each includes metric_group_id, filing identity fields, dates, reporting currency, and optional amendment flags.
form_types, quarterPresent only if you sent them in the request.
_warningsOptional; present when dates exclude all rows or are invalid.

Errors:

HTTPerror_codeWhen
400METRICS_UNSUPPORTED_FOR_KRKorean (DART) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_JPJapanese (EDINET) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_EUEuropean (ESEF) metrics not yet supported — coming soon (not charged).
402CREDITS_INSUFFICIENTInsufficient credits.
422Validation (e.g. neither valid fiscal year nor valid as_of_date).

Example Request:

{
  "ticker": "AAPL",
  "fiscal_year": 2024
}

Example MCP tool call:

list_metric_snapshots(ticker="AAPL", fiscal_year=2024)

Example Response:

{
  "credits_used": 10,
  "fiscal_year": 2024,
  "as_of_date": null,
  "company": {
    "ticker": "AAPL",
    "cik": "0000320193",
    "legal_name": "Apple Inc."
  },
  "metric_groups": [
    {
      "metric_group_id": 9876,
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2024,
      "quarter": "FY",
      "period_end": "2024-09-28",
      "filing_date": "2024-11-01",
      "reporting_currency": "USD"
    }
  ]
}

5.2 POST /metric/all

Purpose: Return the full metrics object for one metric_group_id, including realtime price-sensitive metrics when the caller supplies current_price, and optional formula overrides.

Request:

FieldTypeDefaultNotes
metric_group_idintegerRequired. 1–10⁹. From POST /metric/filings.
as_of_datestringnullYYYY-MM-DD: exclude this filing if its filing date is after this date (amendments are pre-merged into the primary filing — no version switching). Invalid non-empty values echo as "error" and may produce warnings.
accept_suggested_formulabooleanfalseWhen true, applies suggested formula hints included with the filing’s metrics (if any).
formula_overrideobjectnullPer-metric overrides. Keys are metric names (e.g. "operating_margin"). Values are objects containing "concepts" (array of strings, at most 50 entries per metric) and "operators" (array of strings, e.g. ["+", "-"], length must be exactly len(concepts) - 1). A lone top-level { "concepts": ... } object is invalid.
current_pricenumbernullUSD price used to compute realtime price-sensitive metrics (market_cap, pe_ratio, enterprise_value, price_to_book, price_to_sales, price_to_cash_flow, ev_to_ebitda, ev_to_revenue, ev_to_fcf, fcf_yield, dividend_yield, buyback_yield). Must be > 0, ≤ 10,000,000, with at most 4 decimal places. Pass the USD price as-is for all filings, including foreign-issuer ADRs. Invalid values return HTTP 422 without charging credits. When omitted, the realtime block is replaced by { "status": "missing", "hint": "..." } and the same hint appears in _warnings.
current_fx_ratenumbernullOptional fallback FX rate (units of the filing's reporting_currency per 1 USD), used only when the internal FX feed is temporarily unavailable for foreign-issuer ADR filings. Normally not required. Must be > 0, ≤ 1,000,000, with at most 6 decimal places. Invalid values return HTTP 422 without charging credits.
light_weight_modebooleanfalseWhen true, strips per-metric audit fields from every entry. A notice is appended to _warnings. Charged identically. See Light-weight mode.

Response:

FieldMeaning
credits_usedAlways 148 when successful.
metric_group_idThe metric group ID actually used (may be null if excluded by as_of_date).
valuation_contextEcho of flags and formula inputs.
ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, source_url_prefixFiling identity and SEC base URL. source_url_prefix may be null; combine it with each fact’s source_locator (see below) to build the SEC viewer URL.
segmentsArray of segment data.
price_insensitive_metricsObject containing metrics that do not depend on stock price. Within each metric, nested fact_refs / components entries that expose fact_id also expose source_locator (may be null).
price_sensitive_metricsObject containing metrics that depend on stock price. Always includes both a realtime sub-object (computed from the request's current_price; when realtime cannot be computed it becomes { "status": "missing" | "missing_fx_fallback", "hint": "..." } instead) and a filing_date_price + historical pair (the same metrics computed from the filing-date stock price). For foreign-issuer ADR filings each computed metric's price_used block carries the ADR ratio, the filer's reporting currency, and the FX rate used — see Response conventions. Same source_locator convention on nested fact references where fact_id is present. If you only need the filing-date computation, call POST /metric/all/filing-date instead.
price_contextPresent whenever the response would include a realtime block. status is "ok" (price applied), "missing" (no current_price supplied), or "missing_fx_fallback" (foreign-issuer filing and the internal FX feed is temporarily unavailable). When ok, also includes price, price_date, source: "user_supplied", and fx_fallback_used: true if the caller-supplied current_fx_rate was used because the internal feed was unavailable. mode is always present; on the two non-ok statuses a message states what to send.
ttm_composite, dei_correctedOptional root fields, present if they exist in the payload.
amendedPresent and true only when this filing had a later amendment merged in. The returned metric values are already the amended figures.
corporate_actionsOptional root field, present when the ticker has splits in the lookback window. Contains splits_in_lookback, splits_after_period_end, split_factor_to_today, and a human-readable summary. When split_factor_to_today is not 1, three per-share metrics — pe_ratio, dividend_yield, eps_growth_yoy — additionally carry split_adjusted_value, split_adjustment_factor, and comparable_to_post_split_basis, so values from this filing can be compared on the current per-share basis; when it is 1 the filing is already on that basis and those three fields are absent. Total values (revenue, market_cap, etc.) are unaffected by splits. Tickers with no splits in the window omit the field entirely.
reporting_currencyThe currency the filer reports in (e.g. usd, brl, eur). US filers (10-K / 10-Q) are always usd; foreign filers (20-F / 40-F) may be any local currency. Each metric's actual unit is on its own unit field; non-USD absolute metrics also carry currency and fx_required: true. See Response conventions.
_warningsOptional; warnings about amendments, formulas, or invalid dates.

Errors:

HTTPerror_codeWhen
404METRIC_GROUP_NOT_FOUNDUnknown metric_group_id.
404METRIC_SUMMARY_NOT_FOUNDFiling has no metrics summary.
404METRIC_SUMMARY_OBJECT_MISSINGThe metrics summary could not be retrieved.
500METRIC_SUMMARY_INVALID_FORMATThe metrics summary data is invalid.
402CREDITS_INSUFFICIENTInsufficient credits.
409METRIC_FORMULA_OVERRIDE_INVALIDInvalid formula_override.
422METRIC_FORMULA_APPLY_FAILEDFormula application failed.
422VALIDATION_ERRORcurrent_price is non-numeric, non-finite, ≤ 0, > 10,000,000, or has more than 4 decimal places; or current_fx_rate is non-numeric, non-finite, ≤ 0, > 1,000,000, or has more than 6 decimal places.

Example Request:

{
  "metric_group_id": 12345,
  "current_price": 225.0,
  "formula_override": {
    "operating_margin": {
      "concepts": ["us-gaap_GrossProfit", "us-gaap_SellingGeneralAndAdministrativeExpense"],
      "operators": ["-"]
    }
  }
}

Example MCP tool call:

get_metrics_bundle(
    metric_group_id=12345,
    current_price=225.0,
    formula_override={
        "operating_margin": {
            "concepts": ["us-gaap_GrossProfit", "us-gaap_SellingGeneralAndAdministrativeExpense"],
            "operators": ["-"],
        }
    },
)

Example Response:

{
  "credits_used": 148,
  "metric_group_id": 12345,
  "valuation_context": {    "as_of_date": null,
    "accept_suggested_formula": false,
    "formula_override": null
  },
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "quarter": "FY",
  "cik": "0000320193",
  "source_accession": "0000320193-24-000123",
  "primary_document": "aapl-20240928.htm",
  "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20240928.htm",
  "segments": [],
  "price_insensitive_metrics": {
    "revenue": { "value": 383285000000.0, "unit": "USD" }
  },
  "price_sensitive_metrics": {
    "realtime": {
      "market_cap": { "value": 3404250000000.0, "unit": "USD" }
    }
  },
  "price_context": {
    "mode": "user_supplied",
    "status": "ok",
    "price": 225.0,
    "price_date": "2026-05-18",
    "source": "user_supplied"
  },
  "_warnings": []
}

Example Response (filing affected by a stock split):

{
  "ticker": "NVDA",
  "fiscal_year": 2025,
  "quarter": "Q1",
  "corporate_actions": {
    "splits_after_period_end": [
      { "ex_date": "2024-06-10", "ratio": 10.0, "type": "forward" }
    ],
    "splits_in_lookback": [
      { "ex_date": "2021-07-20", "ratio": 4.0,  "type": "forward" },
      { "ex_date": "2024-06-10", "ratio": 10.0, "type": "forward" }
    ],
    "split_factor_to_today": 10.0,
    "summary": "10:1 forward split on 2024-06-10. Multiply per-share values from this filing by 10 to compare with current-basis quotes."
  },
  "price_sensitive_metrics": {
    "realtime": {
      "pe_ratio": {
        "value": 24.25,
        "split_adjusted_value": 2.43,
        "split_adjustment_factor": 10.0,
        "comparable_to_post_split_basis": false
      }
    }
  }
}

5.3 POST /metric/all/filing-date

Purpose: Same metrics bundle as POST /metric/all, but returns only the filing-date price block — no realtime computation. Use this when you don't need today's market price (analyzing historical filings, batch loads, or any case where current stock price is irrelevant).

Request: Same body fields as POST /metric/all minus current_price and current_fx_rate. See the note below.

FieldTypeDefaultNotes
metric_group_idintegerRequired. 1–10⁹. From POST /metric/filings.
as_of_datestringnullSame as POST /metric/all.
accept_suggested_formulabooleanfalseSame as POST /metric/all.
formula_overrideobjectnullSame as POST /metric/all.
light_weight_modebooleanfalseSame as POST /metric/all. See Light-weight mode.

Note on realtime-only fields: Sending current_price or current_fx_rate returns 422 VALIDATION_ERROR (type: extra_forbidden) without charging credits. If you need realtime price-sensitive metrics, call POST /metric/all instead.

Response: Same shape as POST /metric/all except price_sensitive_metrics contains only filing_date_price + historical (no realtime); price_context is not present.

Credits: Same flat 148 as POST /metric/all.

Errors: Same as POST /metric/all.

Example Request:

{
  "metric_group_id": 12345
}

Example MCP tool call:

get_metrics_bundle_filing_date(metric_group_id=12345)

5.4 POST /metric/items

Purpose: Same sourcing as POST /metric/all, but returns only the metric names you list.

Request: Same as POST /metric/all, plus:

FieldTypeRequiredNotes
metric_namesarray of stringYes1–100 names; each max 256 characters. Each name must be a supported metric name and appear in that filing’s metrics (otherwise 400).
light_weight_modebooleanNoSame as POST /metric/all. See Light-weight mode.

Credits: 148 per successful debit.

Response:

FieldMeaning
credits_usedAlways 148 when successful.
metric_group_idThe metric group ID actually used.
valuation_contextEcho of flags, formula inputs, and requested metric_names.
ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, source_url_prefixFiling identity and SEC base URL. source_url_prefix may be null; combine it with each fact’s source_locator (see below) to build the SEC viewer URL.
price_insensitive_metricsObject containing the requested price-insensitive metrics. Nested fact_refs / components entries with fact_id also expose source_locator (may be null).
price_sensitive_metricsObject containing the requested price-sensitive metrics. Its realtime sub-object follows the same convention as POST /metric/all: metric rows when current_price is supplied, { "status": "missing", "hint": "..." } otherwise. Same source_locator convention on nested fact references where fact_id is present.
price_contextPresent whenever the response would include a realtime block (same shape as in POST /metric/all).
segmentsArray of segment data.
ttm_composite, dei_correctedOptional root fields, present if they exist in the payload.
corporate_actionsOptional root field; same shape and semantics as in POST /metric/all. The same per-metric split variants appear on pe_ratio / dividend_yield / eps_growth_yoy when you request them.
_warningsOptional; warnings about amendments, formulas, or invalid dates.

Errors: Same classes as POST /metric/all, plus:

HTTPerror_codeWhen
400METRIC_INVALID_METRIC_NAMEUnknown name or name not in this filing’s payload.
402CREDITS_INSUFFICIENTInsufficient credits.

Example Request:

{
  "metric_group_id": 12345,
  "metric_names": ["revenue", "net_income"]
}

Example MCP tool call:

get_metrics_subset(metric_group_id=12345, metric_names=["revenue", "net_income"])

Example Response:

{
  "credits_used": 148,
  "metric_group_id": 12345,
  "metric_group_id": 12345,
  "valuation_context": {    "as_of_date": null,
    "accept_suggested_formula": false,
    "formula_override": null,
    "metric_names": ["revenue", "net_income"]
  },
  "ticker": "AAPL",
  "form_type": "10-K",
  "fiscal_year": 2024,
  "quarter": "FY",
  "cik": "0000320193",
  "source_accession": "0000320193-24-000123",
  "primary_document": "aapl-20240928.htm",
  "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20240928.htm",
  "price_insensitive_metrics": {
    "revenue": { "value": 383285000000.0, "unit": "USD" },
    "net_income": { "value": 93736000000.0, "unit": "USD" }
  },
  "price_sensitive_metrics": {}
}

5.5 POST /metric/historical

Purpose: Return metrics for many periods (quarterly or annual) for one ticker, paginated. Price-sensitive values use filing-date figures only (no live market refresh).

Request:

FieldTypeDefaultNotes
tickerstringRequired. 1–32 characters (returned uppercased).
period_typestringquarterlyEither quarterly or annual. annual covers 10-K plus the foreign-issuer annual reports 20-F and 40-F; quarterly covers 10-Q only (foreign issuers have no quarterly counterpart). Korean (DART) and Japanese (EDINET) filings are included via the same form types (annual → 10-K, quarterly → 10-Q).
start_period_startstringnullOptional filter: period start ISO date (YYYY-MM-DD). Invalid values echo as "error" in query_context and are ignored for filtering.
end_period_endstringnullOptional filter: same date rules.
metric_namesarraynullIf omitted or null, all metrics returned for each period; if set, only those names (must be supported and present in each returned period—otherwise 400). Max 100 names.
as_of_datestringnullSame meaning as /metric/all.
accept_suggested_formulabooleanfalse
formula_overrideobjectnullSame structure rules as /metric/all (including ≤ 50 concepts per metric).
sortstringperiod_end_ascperiod_end_asc or period_end_desc.
pageinteger1Page index, 1–10⁶.
page_sizeinteger31–5 (maximum page size).
light_weight_modebooleanfalseSame as POST /metric/all but applied to every metric object inside every periods[*]. See Light-weight mode.

Credits: 55 (base) + 148 × (number of rows in periods for this response). If the base debit succeeds but the per-row debit fails, you receive 402 with an explanation; the base 55 credits are spent.

Response:

FieldMeaning
page_infoObject with pagination details (current_page, total_pages, page_size, total_items, next_page_hint).
credits_usedNumber of credits deducted for this request.
tickerEcho of request.
query_contextEcho of the request parameters used for the query.
periodsArray of period objects. Each includes filing metadata (including source_url_prefix per period, may be null), price_insensitive_metrics, price_sensitive_metrics (as static maps), and optional root meta fields. Within each metric object, fact_refs / components entries that expose fact_id also expose source_locator (may be null). Each period may carry its own corporate_actions field, an amended flag (true when that period's filing had a merged amendment), and per-metric split variants as described in POST /metric/all; when comparing a per-share metric across periods that straddle a split, use split_adjusted_value instead of raw value.
_warningsOptional; warnings about amendments, formulas, or invalid dates.

Errors:

HTTPerror_codeWhen
400METRIC_INVALID_METRIC_NAMEInvalid or missing names in a period when metric_names is set.
400METRICS_UNSUPPORTED_FOR_KRKorean (DART) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_JPJapanese (EDINET) metrics not yet supported — coming soon (not charged).
400METRICS_UNSUPPORTED_FOR_EUEuropean (ESEF) metrics not yet supported — coming soon (not charged).
402CREDITS_INSUFFICIENTInsufficient credits for base or per-row charges.
409METRIC_FORMULA_OVERRIDE_INVALIDInvalid formula_override.
422METRIC_FORMULA_APPLY_FAILEDFormula application failed; or validation (period_type, sort, limits).

Example Request:

{
  "ticker": "AAPL",
  "period_type": "quarterly",
  "page": 1,
  "page_size": 2
}

Example MCP tool call:

get_metrics_timeseries(ticker="AAPL", period_type="quarterly", page=1, page_size=2)

Example Response:

{
  "page_info": {
    "current_page": 1,
    "total_pages": 5,
    "page_size": 2,
    "total_items": 10,
    "next_page_hint": "Use the same request body with \"page\": 2."
  },
  "credits_used": 351,
  "ticker": "AAPL",
  "query_context": {
    "period_type": "quarterly",
    "start_period_start": null,
    "end_period_end": null,
    "as_of_date": null,    "accept_suggested_formula": false,
    "formula_override": null,
    "metric_names": null,
    "sort": "period_end_asc"
  },
  "periods": [
    {
      "metric_group_id": 9876,
      "period_start": "2024-07-01",
      "period_end": "2024-09-28",
      "filing_date": "2024-11-01",
      "ticker": "AAPL",
      "form_type": "10-K",
      "fiscal_year": 2024,
      "quarter": "Q4",
      "cik": "0000320193",
      "source_accession": "0000320193-24-000123",
      "primary_document": "aapl-20240928.htm",
      "source_url_prefix": "https://www.sec.gov/ix?doc=/Archives/edgar/data/.../aapl-20240928.htm",
      "segments": [],
      "price_insensitive_metrics": {
        "revenue": { "value": 94930000000.0, "unit": "USD" }
      },
      "price_sensitive_metrics": {
        "filing_date_price": 222.91,
        "historical": {
          "market_cap": { "value": 3300000000000.0, "unit": "USD" }
        }
      }
    }
  ]
}

5.6 Category endpoints (/metric/<category>)

Seven endpoints returning curated metric sets — margins, growth, leverage, efficiency, cash-flow, valuation. Use these when you want a coherent slice of metrics without enumerating names. Flat 148 credits, rate limit 60/minute.

EndpointMetrics returned
POST /metric/profitabilitygross_margin, operating_margin, net_margin, ebitda_margin, return_on_equity, return_on_assets, return_on_invested_capital, return_on_tangible_equity, fcf_margin (9)
POST /metric/growthrevenue_growth_yoy, revenue_growth_qoq, revenue_growth_qoq_single_quarter, eps_growth_yoy, net_income_growth_yoy, fcf_growth_yoy (6)
POST /metric/financial-healthdebt_to_equity, debt_to_assets, debt_to_ebitda, interest_coverage, current_ratio, quick_ratio, cash_ratio (7)
POST /metric/efficiencyasset_turnover, inventory_turnover, receivables_turnover, days_inventory, days_receivable, days_payable, cash_conversion_cycle (7)
POST /metric/cash-flowfree_cash_flow, fcf_margin, payout_ratio (3 — fcf_margin also in /metric/profitability)
POST /metric/valuationAll 12 price-sensitive ratios: market_cap, enterprise_value, pe_ratio, price_to_book, price_to_sales, price_to_cash_flow, ev_to_ebitda, ev_to_revenue, ev_to_fcf, fcf_yield, dividend_yield, buyback_yield. Accepts current_price for realtime; returns both realtime and filing_date_price blocks.
POST /metric/valuation/filing-dateSame 12 valuation ratios as above but only the filing-date price block — current_price and current_fx_rate are rejected with 422 VALIDATION_ERROR.

Request body (5 simple categories + /metric/valuation): metric_group_id required (1–10⁹). Optional: accept_suggested_formula, formula_override, as_of_date, current_price, current_fx_rate, light_weight_mode — same semantics as on POST /metric/all. metric_names is not accepted (the category fixes the metric set; sending it returns 422 VALIDATION_ERROR).

Request body (/metric/valuation/filing-date): same as above minus current_price / current_fx_rate — see POST /metric/all/filing-date. light_weight_mode is accepted on this endpoint as well.

Response shape: ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, metric_group_id, source_url_prefix, valuation_context, segments, price_insensitive_metrics, price_sensitive_metrics, credits_used, plus the conditional price_context and the optional root fields ttm_composite, dei_corrected, corporate_actions and _warnings. For /metric/valuation and /metric/valuation/filing-date the price_insensitive_metrics block is always {} (all 12 valuation ratios are price-sensitive).

Errors: METRIC_GROUP_NOT_FOUND, CREDITS_INSUFFICIENT, standard 422 VALIDATION_ERROR.


6. Screener API

Query the universe of US-listed filers by composing metric conditions ("ROE > 20% for the last 5 years AND PE < 20"). Supports OR/NOT, time-window modifiers (for_latest / for_consecutive / for_at_least), 1–120 period lookback, USD-normalized values for ADR foreign filers, and paging up to 500 cumulative results.

§6.5 screens insider trades rather than metrics; its rows use the transaction object defined in §7.

Plan-tier gate: Every endpoint in this section requires the Pro plan or higher; Free / Starter callers receive 403 PLAN_TIER_INSUFFICIENT (see Section 8). The MCP wrappers (search_stocks, list_screener_filters, search_insider_trades) forward the same REST endpoints and surface the same 403 envelope.

Pricing note: Filters that touch price-sensitive metrics (market_cap, enterprise_value, all 12 valuation ratios) use the price observed on each filer's filing date; these dates differ across filers. For same-day cross-ticker comparison, call POST /metric/all per ticker with a common current_price.

6.1 POST /screener/metrics

Purpose: Return filings that match a DSL filter tree, grouped by ticker (default) or flattened.

Request body (APIRequest, extra="forbid"):

FieldTypeDefaultNotes
as_of_dateISO datetoday (UTC)Must be ≤ today. Filings with filing_date > as_of_date are excluded (avoids backtest leakage).
lookbackint 1–1201Most recent N filings per ticker within scope.
include_quarterlyboolfalsefalse → annual only (10-K / 20-F / 40-F). true adds 10-Q.
tickersstring[]omittedWhitelist, max 100. Case-insensitive (normalized to upper). Empty or omitted = full universe.
exclude_tickersstring[][]Blacklist, max 100.
usd_onlyboolfalseWhen true, exclude foreign-currency reporters.
sectorsstring[]omittedRestrict the universe to these canonical sector buckets (the 12 in §1.10). Omitted = no sector restriction.
where.filterDSL tree(required)See §6.3. Leaf count 1–10, nesting depth ≤ 4.
where.sort_bystringsee §6.3Metric name, "ticker", "period_end", "filing_date", or "match_count".
where.sort_order"asc" | "desc""asc"
include_metrics_using_filing_date_pricebooltruefalse rejects price-sensitive metrics in filter / sort_by / include_metrics.
exclude_derivationsstring[][]Subset of derived, as_reported, composite, class_sum, segment_sum, company_override, proxy_substituted, TTM_rollforward.
include_metricsstring[][]Extra metric names (≤ 10) to include in the response beyond filter-referenced ones.
group_by_tickerbooltruetrue → grouped by ticker with nested filings[]. false → flat per-filing rows.
pageint ≥ 111-indexed.
page_sizeint 1–10050Counts tickers (when grouped) or filings (when flat).

Pagination cap: page × page_size ≤ 500 (validation 422). Use larger page_size rather than more pages. Tighten filters to look beyond the first 500 results.

Response (group_by_ticker=true, default):

{
  "page": 1, "page_size": 50,
  "has_more": true,
  "next_page": 2,
  "as_of_date_applied": "2024-12-31",
  "lookback_applied": 5,
  "include_quarterly_applied": false,
  "results": [
    {
      "ticker": "AAPL",
      "match_count": 5,
      "filings": [
        {
          "metric_id": 46,
          "form_type": "10-K",
          "fiscal_year": 2024, "quarter": "FY",
          "period_end": "2024-09-28",
          "filing_date": "2024-11-01",
          "reporting_currency": "usd",
          "metrics": {
            "return_on_equity": {"value": 1.5774, "derivation": "derived", "unit": "ratio"},
            "pe_ratio": {"value": 33.21, "derivation": "derived", "unit": "ratio", "price_date": "2024-11-01"},
            "market_cap": {"value": 3.37e12, "derivation": "as_reported", "unit": "usd", "price_date": "2024-11-01"}
          }
        }
        /* T-1, T-2, … up to lookback filings within ticker */
      ]
    }
  ],
  "credits_used": 242
}

Response (group_by_ticker=false): identical envelope, but results[] is a flat list of {ticker, metric_id, form_type, fiscal_year, quarter, period_end, filing_date, reporting_currency, metrics} — one row per matching filing.

Each results[] entry (grouped or flat) also carries an industry classification block — see §1.10.

match_count is the number of filings within lookback that satisfy the whole filter tree on a per-filing basis (using each filing's own metric values).

Foreign-currency filers (ADRs) carry fx_rate_used + currency on FX-converted metric entries:

"market_cap": {
  "value": 2.42e11,            // USD-converted from JPY
  "derivation": "as_reported",
  "unit": "usd",
  "currency": "jpy",
  "fx_rate_used": 145.2,
  "price_date": "2024-06-30"
}

All screener filtering, sorting, and comparison use the USD-converted value. USD reporters omit fx_rate_used and currency.

Within-ticker filings[] ordering is fixed at filing_date DESC, period_end DESC (newest first), independent of where.sort_order. For time-series ordering, use group_by_ticker=false with sort_by="period_end" or "filing_date".

Errors: 422 VALIDATION_ERROR (schema), 402 CREDITS_INSUFFICIENT, 504 QUERY_TIMEOUT when the query exceeds the 15-second server timeout (the request is charged; tighten filters and retry).

6.2 GET /screener/metrics/filters

Purpose: Discovery — returns the supported metric catalog, operators, temporal modifiers, form types, derivations, and one complete example request. 10 credits.

{
  "metrics": [
    {"name": "return_on_equity", "unit": "ratio", "price_sensitive": false},
    {"name": "market_cap", "unit": "usd", "price_sensitive": true}
    /* ... 43 total ... */
  ],
  "operators": ["<", "<=", ">", ">=", "between"],
  "temporal_modifiers": ["for_latest", "for_consecutive", "for_at_least"],
  "form_types": ["10-K", "10-Q", "20-F", "40-F"],
  "derivations": ["TTM_rollforward", "as_reported", "class_sum", "company_override", "composite", "derived", "proxy_substituted", "segment_sum"],
  "sectors": ["Technology", "Healthcare", "Finance", "Consumer Discretionary", "Consumer Staples", "Communications", "Industrials", "Energy", "Utilities", "Materials", "Real Estate", "Other"],
  "example_request": { /* full POST /screener/metrics body */ }
}

sectors lists the 12 canonical buckets accepted by the POST /screener/metrics sectors filter (§1.10).

6.3 Filter DSL (/screener/metrics)

Leaf node

{"metric": "<name>", "op": "<operator>", "value": <number | [lo, hi]>,
 "for_latest": <N> | "for_consecutive": <N> | "for_at_least": <N>}
OperatorValue shapeNotes
>, >=, <, <=single number
between[lo, hi] (lo ≤ hi)Inclusive on both ends.

= / != are not supported in v1. For equality matching use between [v − ε, v + ε].

value must be numeric. null is rejected. Filings where the metric value is missing are excluded from filter comparisons (no synthetic match).

Temporal modifiers (mutually exclusive, at most one per leaf)

ModifierMeaning
(none)Latest filing in lookback must satisfy. Equivalent to for_latest: 1.
for_latest: NMost recent N filings (right-anchored) all satisfy.
for_consecutive: NSome N adjacent filings within lookback all satisfy (sliding window over filing_date).
for_at_least: NAt least N filings within lookback satisfy (any positions).

N ≥ 1 and N ≤ lookback. Tickers without enough filings in lookback to evaluate the modifier are filtered out.

Composite nodes

{"and": [<node>, <node>, …]}
{"or":  [<node>, <node>, …]}
{"not": <node>}

where.filter may itself be a bare leaf (no wrapper required for single-condition queries).

Limits

  • Leaf nodes total: 1–10 (0 → rejected as "filter required"; >10 → rejected as "too complex")
  • Nesting depth: ≤ 4
  • include_metrics length: ≤ 10
  • tickers, exclude_tickers: each ≤ 100 entries

6.4 Credit formula (/screener/metrics)

POST /screener/metrics charges per call (paginate ⇒ each page bills independently):

credits = max(65, 425
              − tickerDiscount             // ceil(200 × (100 − n_tickers) / 100); 0 (whole universe, or ≥ 100 tickers) … 198 (1 ticker)
              − lookbackDiscount           // 0 (lookback ≥ 30) … 78 (lookback = 1)
              − quarterlyDiscount          // 60 when include_quarterly=false, else 0
              + lookbackSurcharge          // 0 (lookback ≤ 30) … 240 (lookback = 120)
              + filterSurcharge            // 40 × (leaves − 1), 0 … 360
              + temporalSurcharge          // per-leaf 60 (for_latest / for_at_least) or 100 (for_consecutive), capped 600
              + includeMetricsSurcharge)   // 20 × |include_metrics \ filter_metrics|, 0 … 200

Examples:

ScenarioCredits
1 ticker, lookback=1, annual only, 1 leaf (best case)89
Whole universe, lookback=30, quarterly+annual, 1 leaf425
2 tickers, lookback=5, annual, 2 leaves, 1 for_latest, 2 extra include_metrics242
Whole universe, lookback=120, 10 leaves all for_consecutive, 10 extra include_metrics1825 (worst case)

Charge applies even when results is empty, and on 504 QUERY_TIMEOUT (the query runs before it times out — that compute is the billable unit). No charge only on 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, or 403 PLAN_TIER_INSUFFICIENT (all rejected before any deduction).

GET /screener/metrics/filters charges 10 credits flat.

6.5 POST /screener/ownership

Purpose: Full-library transaction screening. Trade-level conditions plus company-level aggregate gates; returns the matching transactions.

Request:

FieldTypeDefaultNotes
start_date, as_of_dateISO dateas_of_date ≤ today; start_dateas_of_date.
tickers, exclude_tickersstring[]omitted≤ 100 each.
sectorsstring[]omittedThe 12 canonical buckets (§1.10).
trade_filtersobjectomittedSee §6.6.
aggregate_filtersobject[]omitted≤ 8. Company-level gates — see §6.6.
group_by_tickerbooltruetrue → grouped by ticker. false → flat rows.
sort_bystringGrouped: ticker, txn_count. Flat: transaction_date, filing_date, transaction_value, shares, price_per_share, own_pct_change, split_adjusted_shares, split_adjusted_price.
sort_order"desc" | "asc""desc"
pageint ≥ 11
page_sizeint 1–10050

Pagination cap: page × page_size ≤ 500 (422).

Response:

FieldMeaning
page, page_size, has_more, next_pagePagination.
as_of_date_applied, start_date_appliedWindow actually used.
resultsgroup_by_ticker=true. Each entry: ticker, issuer, issuer_cik, txn_count (the company's full hit count, not the page's), transactions.
transactionsgroup_by_ticker=false. Flat rows, each additionally carrying ticker, issuer, and issuer_cik.
credits_used, _warnings

Every row carries accession_number, filing_date, source_url_prefix, insiders, the transaction object, and computed.

Errors: 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, 403 PLAN_TIER_INSUFFICIENT below Pro, 504 QUERY_TIMEOUT at the 15-second server timeout (charged).

6.6 Filters (/screener/ownership)

trade_filters:

FieldTypeNotes
transaction_codestring[]≤ 20. Unknown codes dropped with a warning.
relationshipstring[]is_director, is_officer, is_ten_percent_owner, is_other. OR semantics.
is_derivativebool
principal_amount_not_sharesboolOmit for no filter, true for debt-principal rows only, false to exclude them.
include_anomaliesboolDefault false.
exclude_likely_mergedboolDefault false.
conditionsobject[]≤ 8. {field, op, value}. fieldtransaction_value, price_per_share, shares, own_pct_change, split_adjusted_shares, split_adjusted_price.

aggregate_filters: {metric, op, value}, metricvalue_acquired, value_disposed, net_value, shares_acquired, shares_disposed, net_shares, txn_count, txn_count_acquired, txn_count_disposed, max_txn_value_acquired, max_txn_value_disposed, distinct_insiders.

Operators (both filter types): >, >=, <, <=, between ([lo, hi], lo ≤ hi).

6.7 Credit formula (/screener/ownership)

POST /screener/ownership charges per call:

credits = max(65, 200
              − tickerDiscount        // 100 − min(n_tickers, 100); 0 when tickers is omitted
              − shortWindowDiscount   // 40 when the window is ≤ 90 days
              + fullHistorySurcharge  // 80 when start_date is omitted
              + 40 × conditions)      // trade conditions + aggregate filters

Range 65–920. Charged even when the result set is empty, and on 504 QUERY_TIMEOUT. No charge on 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, or 403 PLAN_TIER_INSUFFICIENT (all rejected before any deduction).


7. Ownership API

Insider trades reported to the SEC. US filings only. The plan coverage scope (§1.9) and history window (§1.8) apply as they do elsewhere, on the filing's filing_date. The endpoints in this section are available on every plan; full-library screening is POST /screener/ownership in Section 6, which requires Pro or higher.

Credits are deducted before the query runs, so a 404 or 403 raised afterwards is still charged.

Transaction object

Returned by POST /ownership/transactions, POST /ownership/transaction-ids, and POST /screener/ownership.

FieldMeaning
idTransaction id. Pass to POST /ownership/transaction-ids.
is_derivativeDerivative table row (true) or non-derivative (false).
transaction_form_type"4" or "5".
transaction_date, transaction_codeAs filed.
transaction_typeOfficial SEC name for transaction_code.
transaction_type_groupOne of the five SEC groupings — see §7.6.
acquired_disposed_code"A" acquired, "D" disposed, or null. Read direction from this field, not from transaction_code.
shares, price_per_share, transaction_value, shares_owned_followingAs filed. transaction_value may be null or 0.
transaction_noteFiler-side note explaining a null / 0 value. null when absent.
principal_amount_not_sharestrue when shares holds a debt principal amount, not a share count.
security_title, direct_or_indirect, nature_of_ownershipAs filed.
footnote_refsFootnote ids for this transaction. Resolve against the filing's footnotes map.
source_locatorCombine with the filing's source_url_prefix to build the SEC URL.
restatednull, "cancelled", "modified", or "added" — set when an amendment changed this transaction.
priorPresent only when restated is set. The pre-amendment values.
split_adjustedPresent only when the filed values are not on the current per-share basis. See below.
data_quality_flagsPresent only when at least one rule fires. See below.

Derivative rows additionally carry conversion_or_exercise_price, exercise_date, expiration_date, underlying_security_title, underlying_security_shares, underlying_security_value, and value_owned_following.

split_adjusted

shares and price_per_share are in the units of the transaction's own trade date. When those differ from the current per-share basis, the block is present:

"split_adjusted": {
  "shares": 4000.0,
  "price_per_share": 125.86,
  "shares_owned_following": 48000.0,
  "split_adjustment_factor": 4.0,
  "comparable_to_post_split_basis": false
}

Absent means the filed values are already on the current per-share basis. split_adjustment_factor and comparable_to_post_split_basis carry the same meaning and the same presence rule as on the metrics API (§5.2).

data_quality_flags

Rows that fail a consistency check carry one or more of:

future_transaction_date, future_deemed_execution_date, zero_price_open_market, derivative_date_order, negative_shares, negative_price, negative_transaction_value, negative_shares_owned_following, value_mismatch.

Flagged rows are excluded from POST /ownership/stats unless include_anomalies=true, and from POST /screener/ownership unless trade_filters.include_anomalies=true.

computed

POST /screener/ownership rows additionally carry a computed block with shares_owned_before and own_pct_change. Each entry has value, status (ok / unavailable), unit, formula, computed_as, and fact_refs pointing at the inputs. When an input is missing, value is null, status is "unavailable", and computed_as states the reason.


7.1 POST /ownership/transactions

Purpose: Anchored listing of insider-trade filings and their transactions. Requires ticker and/or insider_cik; unanchored queries belong to §6.5.

Request:

FieldTypeDefaultNotes
tickerstringUppercased automatically.
insider_cikstringDigits only, ≤ 10; left-padded to 10.
transaction_codestring[]omitted≤ 20 entries. Unknown codes are dropped with a _warnings entry.
transaction_form_type"4" | "5"omitted
include_unresolved_amendmentsboolfalse
exclude_likely_mergedboolfalse
pageint ≥ 11
page_sizeint 1–10050Counts filings.

At least one of ticker / insider_cik is required (422 otherwise).

Response:

FieldMeaning
page, page_size, has_more, next_pagePagination.
filingsArray. Each carries id, ticker, issuer, issuer_cik, accession_number, form_type, filing_date, period_of_report, date_of_original_submission, merge_status, remarks, source_url_prefix, insiders, footnotes, transactions, and amendments (present only when amendments were merged).
filings[].issuer_cikThe issuer CIK declared by the filing itself. Compare it with the company's own CIK from GET /ownership/tickers to verify the filing belongs to this company. null on filings imported before issuer identity was available.
filings[].insiderscik, name, is_director, is_officer, is_ten_percent_owner, is_other, officer_title, other_text.
filings[].footnotesMap of footnote id → text for this filing.
_warningsOptional.
credits_usedAlways 30.

Credits: 30 per page.

Errors: 404 OWNERSHIP_COMPANY_NOT_FOUND (charged), 403 PLAN_TIER_INSUFFICIENT_COVERAGE when the ticker is outside your plan's coverage scope (charged), 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.


7.2 POST /ownership/stats

Purpose: Aggregate statistics over one company and/or one insider, plus the ids of every transaction that contributed.

Request:

FieldTypeDefaultNotes
tickerstring
insider_cikstring
start_date, as_of_dateISO dateas_of_date ≤ today; start_dateas_of_date.
transaction_codestring[]omitted≤ 20 entries.
method"ad" | "ps""ad"ad splits on acquired_disposed_code. ps treats P as a buy and S as a sell, and narrows the scope to those two codes.
include_anomaliesboolfalse
relationshipstring[]omittedAny of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing.
is_derivativeboolomitted
exclude_likely_mergedboolfalse
ids_pageint ≥ 11Paginates transaction_ids only.
ids_page_sizeint 1–1000200

At least one of ticker / insider_cik is required.

Response: stats, method_applied, start_date_applied, as_of_date_applied, anomalies_excluded_count, credits_used, optional corporate_actions, optional _warnings, then ids_total, ids_page, ids_has_more, transaction_ids.

Key names inside stats follow method: acquired / disposed for ad, bought / sold for ps.

stats fieldMeaning
value_acquired, value_disposed, net_valueCash value totals. Transactions with no cash value contribute 0.
shares_acquired, shares_disposed, net_sharesShare totals on the split-adjusted basis, excluding rows where principal_amount_not_shares is true.
avg_price_acquired, avg_price_disposedTotal value ÷ total split-adjusted shares over the transactions that have a cash value, on the same basis as shares_*. null when there are none.
txn_count, txn_count_acquired, txn_count_disposedCounts.
txn_count_with_valueTransactions carrying a non-zero cash value.
no_value_txn_countTransactions with no cash value.
ad_code_missing_countTransactions counted in neither direction.
principal_amount_txn_countDebt-principal rows excluded from shares_* and avg_price_*.
distinct_insidersDistinct reporting owners in scope.
filings_with_multiple_filersJoint filings in scope.
max_txn_value_acquired, max_txn_value_disposedLargest single transaction per side. null when the side is empty.
avg_value_per_txn_acquired, avg_value_per_txn_disposedMean over transactions that have a cash value.
earliest_transaction_date, latest_transaction_dateRange actually covered.
split_crossingtrue when the window spans a stock split.

corporate_actions is present only when the request is anchored on a ticker that has splits: an array of {ex_date, ratio, type}.

_warnings names the count and the parameter that changes it whenever transactions were excluded, skipped, or carry no value.

Credits: 40 base, plus ceil(n / 1000) × 5 where n is the number of participating transactions. Both charges are recorded as one usage entry.

Errors: 404 OWNERSHIP_COMPANY_NOT_FOUND (charged), 403 PLAN_TIER_INSUFFICIENT_COVERAGE when the ticker is outside your plan's coverage scope (charged), 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.


7.3 POST /ownership/transaction-ids

Purpose: Fetch transactions by id — the detail companion to the transaction_ids returned by §7.2.

Request:

FieldTypeDefaultNotes
transaction_idsint[]Required. 1–100 positive integers. Duplicates are removed with a _warnings entry.
pageint ≥ 11
page_sizeint 1–100100Counts filings.

Response: same envelope as §7.1, plus missing_ids when some ids were not found and restricted_ids when some exist but are outside your plan's scope. Both are charged for.

Credits: ceil(n / 5) × 10 on the deduplicated id count (max 200).

Errors: 404 OWNERSHIP_TRANSACTION_NOT_FOUND when none of the requested ids exist (charged; the response carries missing_ids). 403 PLAN_TIER_INSUFFICIENT_HISTORY when every requested id that exists is outside your plan's scope (charged; the response carries restricted_ids). Partial misses and partial restrictions return 200. 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.


7.4 GET /ownership/tickers

Purpose: Discovery — every ticker with insider-trade coverage. Unpaginated; cache the result.

Response: tickers (array of {ticker, jurisdiction, cik}), credits_used, and optional _warnings.

Credits: 175.

Errors: 402 CREDITS_INSUFFICIENT.


7.5 POST /ownership/names

Purpose: All insiders of one company, aggregated per CIK.

Request:

FieldTypeNotes
tickerstringRequired.
relationshipstring[]Any of ever_director, ever_officer, ever_ten_percent_owner, ever_other. OR semantics. This endpoint aggregates across every filing, so the filter means "ever reported in this role"; the per-filing is_* form is used by §7.2 and §6.5.

Response: names, credits_used, and optional _warnings. Each name carries:

FieldMeaning
owner_cik, owner_nameSpelling from this insider's most recent filing.
name_changedtrue when earlier filings spelled the name differently.
caveatPresent only when name_changed is true.
ever_director, ever_officer, ever_ten_percent_owner, ever_othertrue when any filing reported that role.
latest_officer_titleMost recent non-null officer title. null when never reported.
officer_title_as_ofFiling date latest_officer_title came from.
filing_countFilings of this company naming this insider.
earliest_filing_date, latest_filing_dateRange.

Credits: 30.

Errors: 404 OWNERSHIP_COMPANY_NOT_FOUND (charged), 403 PLAN_TIER_INSUFFICIENT_COVERAGE when the ticker is outside your plan's coverage scope (charged).


7.6 GET /ownership/transaction-types

Purpose: The SEC transaction-code catalog — 20 codes with their official name and grouping.

Response: transaction_types (array of {code, name, group}), source_url (the SEC form the wording is copied from), and credits_used.

Credits: 0. No charge, no usage entry.


8. API key, account, and plan errors

HTTPWhen
401Missing X-API-Key.
403Invalid or inactive key, inactive user, or email not verified.
403AUTH_API_KEY_EXPIRED — key past its expiry.
403AUTH_API_KEY_INACTIVE — key disabled by inactivity policy.
403PLAN_TIER_INSUFFICIENT — the endpoint is not available on the caller's current plan.
403PLAN_TIER_INSUFFICIENT_HISTORY — the requested filing is older than what the caller's current plan covers. Body also carries filing_fiscal_year and earliest_allowed_fiscal_year.
403PLAN_TIER_INSUFFICIENT_FORMULA_OVERRIDE — the formula_override request field is not available on the caller's current plan. Omit formula_override to proceed, or upgrade.
403PLAN_TIER_INSUFFICIENT_COVERAGE — the requested company or filing is outside the caller's plan's coverage scope. Body also carries coverage_band.

Every PLAN_TIER_* response includes required_tier and current_tier strings (lowercase plan names) in the detail body so clients can prompt for an upgrade without parsing the message text.


9. Request limits (validation)

These caps apply at validation time (422 when exceeded):

LimitValue
Line items per request (/data/line-items, /data/compare/line-items)50
Fact ids per request (/data/facts)500
Fact ids per row (/data/compare/facts)500
Total fact ids (/data/compare/facts)2500
Filings per compare request25
Metric names (/metric/items, optional /metric/historical)100
Concepts per metric in formula_override (/metric/all, /metric/items, /metric/historical)50
Form types (/metric/filings)8
Historical page size5

10. MCP access

The Data and Metrics API is also exposed as a Model Context Protocol (MCP) server at:

https://api.akkrudata.ai/mcp

Authenticate via one of the two methods below. Both share your AkkruData account, credits, and rate limits.

For AI clients with built-in MCP support (Claude Desktop, Claude Web, etc.):

  1. In your AI client, add https://api.akkrudata.ai/mcp as a custom MCP connector.
  2. Click Connect. Your browser will open an AkkruData sign-in page.
  3. Sign in with the same credentials you use for the dashboard (email/password, Google, or GitHub).
  4. Review the connecting AI client's reported identity, then click Authorize.
  5. Done. The AI client now holds a token and can call AkkruData on your behalf. Token renewal is automatic.

You can list and disconnect any authorized AI client at any time from the dashboard's Connected AI assistants panel. A single account may have up to 10 simultaneous AI client connections.

10.2 Connect via X-API-Key (programmatic use)

Available only on deployments where MCP OAuth is disabled.

For scripted MCP clients, local development, or any setup where you cannot run the OAuth browser flow:

URL:     https://api.akkrudata.ai/mcp
Header:  X-API-Key: <your-api-key>

The same API key used for REST works for MCP. Create and rotate keys from the dashboard.

10.3 Tool catalog

MCP toolDocumentation
list_filingsPOST /data/filings
lookup_companyPOST /data/company
list_companiesGET /data/company/list
query_line_itemsPOST /data/line-items
get_filing_factsPOST /data/facts
get_filing_statementPOST /data/statement
list_filing_statementsPOST /data/filing-statements
get_income_statementPOST /data/income-statement
get_comprehensive_incomePOST /data/comprehensive-income
get_balance_sheetPOST /data/balance-sheet
get_cash_flow_statementPOST /data/cash-flow-statement
get_equity_statementPOST /data/equity-statement
get_dimensional_breakdown_by_fact_idPOST /data/facts/dimensional-breakdown
get_dimensional_breakdown_by_line_itemPOST /data/line-items/dimensional-breakdown
compare_line_itemsPOST /data/compare/line-items
compare_factsPOST /data/compare/facts
get_filing_excelGET /data/filings/{filing_id}/excel
list_metric_snapshotsPOST /metric/filings
get_metrics_bundlePOST /metric/all
get_metrics_bundle_filing_datePOST /metric/all/filing-date
get_metrics_subsetPOST /metric/items
get_profitability_metricsPOST /metric/profitability
get_growth_metricsPOST /metric/growth
get_financial_health_metricsPOST /metric/financial-health
get_efficiency_metricsPOST /metric/efficiency
get_cash_flow_metricsPOST /metric/cash-flow
get_valuation_metricsPOST /metric/valuation
get_valuation_metrics_filing_datePOST /metric/valuation/filing-date
get_metrics_timeseriesPOST /metric/historical
search_stocksPOST /screener/metrics
list_screener_filtersGET /screener/metrics/filters
list_insider_transactionsPOST /ownership/transactions
get_insider_statsPOST /ownership/stats
get_insider_transactions_by_idPOST /ownership/transaction-ids
search_insider_tradesPOST /screener/ownership
list_insider_tickersGET /ownership/tickers
list_company_insidersPOST /ownership/names
list_insider_transaction_typesGET /ownership/transaction-types

Each linked section includes an Example MCP tool call with the exact tool name, arguments to pass, and the response shape to expect.


AkkruData — API & MCP user guide.