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
| Section | Link |
|---|---|
| 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) | → |
└ POST /screener/initial-holdings | → |
└ POST /screener/institutional-holdings | → |
└ Credit formula (/screener/institutional-holdings) | → |
| 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 | → |
| └ Holding object | → |
└ POST /ownership/initial-holdings | → |
└ POST /ownership/initial-holdings/stats | → |
└ POST /ownership/initial-holding-ids | → |
| └ Snapshot object | → |
| └ Institutional holding object | → |
└ POST /ownership/institutional-holdings/manager-history | → |
└ POST /ownership/institutional-holdings/portfolio | → |
└ POST /ownership/institutional-holdings/security | → |
| 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:
| Header | Value |
|---|---|
X-API-Key | Your API key (create and manage keys in the product dashboard after sign-in). |
For POST requests with a JSON body, also send:
| Header | Value |
|---|---|
Content-Type | application/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.
Authentication failures use the same object form: 401 AUTH_API_KEY_MISSING (no X-API-Key or bearer token), 403 AUTH_API_KEY_INVALID (unknown or inactive key), 403 AUTH_USER_INACTIVE, 403 AUTH_EMAIL_NOT_VERIFIED. Every 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
caveatfield on the filing information itself (top-level for single-filing responses; per-row inresults[]for compare endpoints; per-item infilings[]for the listing endpoint). Eithernull/ absent (no caveat), or a string. - A
_warningsentry of the formFiling <TICKER> <FORM> FY<YEAR>[ <QUARTER>] has caveat: <text>. Compare endpoints aggregate per-filing caveats into a single deduplicated_warningslist.
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 the L1 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.
| Workflow | Endpoint pattern | Typical credits |
|---|---|---|
| Discover one company (identity + coverage map) | POST /data/company | 8 |
| List all filings for one company-year | POST /data/filings | 10 |
| Pull all three primary statements (income / balance / cash flow) for one filing | POST /data/income-statement + /balance-sheet + /cash-flow-statement | 84 (28 × 3) |
| Pull a few specific line items from one filing (3 items × L1) | POST /data/line-items | 60 (3 × 20) |
| Five-year trend on one metric for one company | POST /data/line-items × 5 filings, 1 item, L1 | 100 (5 × 20) |
| Peer comparison: 5 companies × 1 metric × 1 year (L1) | POST /data/compare/line-items | 100 (1 × 20 × 5) |
| All key metrics snapshot for one company (1 call) | POST /metric/all | 148 |
| 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 workbook | GET /data/filings/{id}/excel | 300 |
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, POST /ownership/initial-holdings, POST /ownership/initial-holdings/stats, POST /screener/initial-holdings (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, /screener/initial-holdings, 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 and POST /ownership/initial-holding-ids report 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" }
}
| Field | Meaning |
|---|---|
sectors | One or two of the 12 canonical buckets — primary first, plus an optional secondary when a code genuinely spans two. |
source.scheme | US_SIC (US, SEC SIC), KR_KSIC (Korea, KSIC), JP_TSE33 (Japan, TSE 33-sector), or EU_ICB (Europe, ICB). |
source.code | The company's official industry code as filed. |
source.url | Official 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.
| Endpoint | Credits |
|---|---|
POST /data/filings | 10 per successful debit. Debited even if the returned filings list is empty. |
POST /data/company | 8 per successful debit. Debited even if DATA_COMPANY_NOT_FOUND is returned. |
GET /data/company/list | 175 per successful debit. |
POST /data/line-items | Sum 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/facts | ceil(n / 5) × 10 where n is the number of deduplicated fact ids. |
POST /data/statement (role_label mode) | Tiered 28 / 48: 28 per debit, debited even if the filing is missing or nothing matches; the extra 20 of the higher (48-credit) tier may be capped at your remaining balance. |
POST /data/statement (statement_type mode) | 28 flat per successful debit. Debited even if the filing is missing or has no block of this statement_type. |
POST /data/filing-statements | 10 per successful debit. Debited even if the filing is missing. |
POST /data/income-statement | 28 per successful debit. Debited even if the filing is missing or has no such statement. |
POST /data/comprehensive-income | 28 per successful debit. Debited even if the filing is missing or has no such statement. |
POST /data/balance-sheet | 28 per successful debit. Debited even if the filing is missing or has no such statement. |
POST /data/cash-flow-statement | 28 per successful debit. Debited even if the filing is missing or has no such statement. |
POST /data/equity-statement | 28 per successful debit. Debited even if the filing is missing or has no such statement. |
POST /data/facts/dimensional-breakdown | ceil((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-breakdown | Tier credit for line_item (L0=10 … L3=50) + ceil(N_total / 5) × 10 for returned slice facts. Partial billing applies. |
POST /data/compare/line-items | For 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/facts | ceil(total_deduplicated_ids / 5) × 10 across all filing rows. |
GET /data/filings/{filing_id}/excel | 300 when the download is issued. |
POST /metric/filings | 10 |
POST /metric/all | 148 |
POST /metric/all/filing-date | 148 |
POST /metric/items | 148 |
POST /metric/profitability | 148 |
POST /metric/growth | 148 |
POST /metric/financial-health | 148 |
POST /metric/efficiency | 148 |
POST /metric/cash-flow | 148 |
POST /metric/valuation | 148 |
POST /metric/valuation/filing-date | 148 |
POST /metric/historical | 55 base fee, plus 148 × (number of filing rows returned on the current page). Default page size is 3 filing rows max. |
POST /screener/metrics | Dynamic 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/filters | 10 per call. |
POST /ownership/transactions | 30 per page. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned. |
POST /ownership/stats | 40 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-ids | ceil(n / 5) × 10 where n is the number of deduplicated ids (max 200). |
POST /screener/ownership | Dynamic 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/tickers | 175 per successful debit. |
POST /ownership/names | 30 per successful debit. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned. |
GET /ownership/transaction-types | 0 — static catalog, no charge. |
POST /ownership/initial-holdings | 30 per page. Debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned. |
POST /ownership/initial-holdings/stats | 40 base + ceil(n / 1000) × 5, where n is the number of participating holdings. The base is debited even if OWNERSHIP_COMPANY_NOT_FOUND is returned. |
POST /ownership/initial-holding-ids | ceil(n / 5) × 10 where n is the number of deduplicated ids (max 200). |
POST /screener/initial-holdings | Dynamic per request, same formula as POST /screener/ownership (§6.7). Range 65–920. Debited even if results are empty. |
POST /ownership/institutional-holdings/manager-history | 30 per successful debit. Debited even if OWNERSHIP_MANAGER_NOT_FOUND is returned. |
POST /ownership/institutional-holdings/portfolio | 30 per page. Debited even if the manager or the quarter is not found. |
POST /ownership/institutional-holdings/security | 30 per page (flat mode); 40 flat with group_by_quarter=true. Debited even if OWNERSHIP_SECURITY_NOT_FOUND is returned. |
POST /screener/institutional-holdings | Dynamic per request: max(65, 200 + 40 × conditions − narrowWindowDiscount + noWindowSurcharge). Range 160–720. See §6.10 for the formula. Debited even if results are empty. |
GET /billing/balance | 0 — 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):
| Method | Path | Limit |
|---|---|---|
| POST | /data/filings | 120 |
| POST | /data/company | 120 |
| GET | /data/company/list | 120 |
| POST | /data/line-items | 100 |
| POST | /data/facts | 100 |
| POST | /data/statement | 120 |
| POST | /data/filing-statements | 120 |
| POST | /data/income-statement | 120 |
| POST | /data/comprehensive-income | 120 |
| POST | /data/balance-sheet | 120 |
| POST | /data/cash-flow-statement | 120 |
| POST | /data/equity-statement | 120 |
| POST | /data/facts/dimensional-breakdown | 60 |
| POST | /data/line-items/dimensional-breakdown | 60 |
| POST | /data/compare/line-items | 60 |
| POST | /data/compare/facts | 60 |
| GET | /data/filings/{filing_id}/excel | 20 |
| POST | /metric/filings | 100 |
| POST | /metric/all | 60 |
| POST | /metric/all/filing-date | 60 |
| POST | /metric/items | 60 |
| POST | /metric/profitability | 60 |
| POST | /metric/growth | 60 |
| POST | /metric/financial-health | 60 |
| POST | /metric/efficiency | 60 |
| POST | /metric/cash-flow | 60 |
| POST | /metric/valuation | 60 |
| POST | /metric/valuation/filing-date | 60 |
| POST | /metric/historical | 60 |
| POST | /screener/metrics | 10 |
| GET | /screener/metrics/filters | 60 |
| POST | /screener/ownership | 10 |
| POST | /ownership/transactions | 120 |
| POST | /ownership/stats | 120 |
| POST | /ownership/transaction-ids | 120 |
| GET | /ownership/tickers | 120 |
| POST | /ownership/names | 120 |
| GET | /ownership/transaction-types | 60 |
| POST | /ownership/initial-holdings | 120 |
| POST | /ownership/initial-holdings/stats | 120 |
| POST | /ownership/initial-holding-ids | 120 |
| POST | /screener/initial-holdings | 10 |
| POST | /ownership/institutional-holdings/manager-history | 120 |
| POST | /ownership/institutional-holdings/portfolio | 120 |
| POST | /ownership/institutional-holdings/security | 120 |
| POST | /screener/institutional-holdings | 10 |
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
caveatfield on the filing information and mirrored to the response's_warningslist. 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:
| Field | Type | Required | Notes |
|---|---|---|---|
ticker | string | Yes | 1–32 characters; matched case-insensitively. |
fiscal_year | integer | Yes | 1990–2100. |
form_type | string | No | Max 32 characters. US forms: 10-K, 10-Q. Foreign-issuer annual reports: 20-F (US-listed foreign companies), 40-F (Canadian filers). Korean (DART), Japanese (EDINET), European (ESEF) and China A-share 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. |
quarter | string | No | Max 4 characters (e.g. Q1). Use when you need a single quarterly filing among several. |
Response:
| Field | Meaning |
|---|---|
credits_used | Always 10 when successful. |
fiscal_year | Echo of request. |
form_type | Present only if you sent form_type. |
quarter | Present only if you sent quarter. |
company | Company profile (ticker, cik, legal_name) or null if unknown. |
filings | Array 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:
| HTTP | error_code | When |
|---|---|---|
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 422 | — | Validation (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:
| Field | Type | Required | Notes |
|---|---|---|---|
ticker | string | Conditional | Exactly one of ticker, cik, dart_corp_code, or edinet_code must be provided. 1–32 characters; case-insensitive. European tickers are the composite form <ticker>_<country> (e.g. VIRI_F); China A-share tickers are <6-digit code>_CN (e.g. 600519_CN). |
cik | string | Conditional | Numeric string; zero-padded to 10 digits on the server side. SEC-listed companies only. |
dart_corp_code | string | Conditional | Numeric string; zero-padded to 8 digits on the server side. Korean DART-listed companies only. |
edinet_code | string | Conditional | EDINET issuer code (E + 5 digits). Japanese EDINET-listed companies only. |
Response:
| Field | Meaning |
|---|---|
ticker, cik, dart_corp_code, edinet_code, lei, uscc, legal_name | Company 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, uscc (统一社会信用代码, 18 chars) for China A-share 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; "CN" for China A-share companies. |
sec_filings_url | EDGAR public browse URL for the company, derived from CIK. Omitted for companies with no CIK (e.g. Korean and Japanese companies). |
dart_filings_url | DART 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_url | EDINET 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_url | filings.xbrl.org public browse URL for the company, derived from lei. Omitted for companies with no LEI. |
cninfo_filings_url | cninfo (巨潮资讯) public browse URL for the company, derived from the 6-digit stock code. Omitted for non-A-share companies. |
filings_count | Total filings we hold for this company across all forms and years. |
coverage | Object keyed by filing-type name. US: SEC form names ("10-K", "10-Q", "20-F", "40-F"). KR / JP / EU / CN: 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_used | Always 8 when successful. |
Charging: A DATA_COMPANY_NOT_FOUND response is still charged 8 credits.
Errors:
| HTTP | error_code | When |
|---|---|---|
| 404 | DATA_COMPANY_NOT_FOUND | No company on file for the given identifier. Still debits 8 credits. |
| 403 | PLAN_TIER_INSUFFICIENT_COVERAGE | The requested company is outside your plan's coverage scope. |
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 422 | — | Validation (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:
| Query | Type | Default | Notes |
|---|---|---|---|
jurisdiction | string | (omitted) | Optional. "US", "KR", "JP", "EU", "CN", or "all". When omitted, returns everything your plan includes. |
Response:
| Field | Meaning |
|---|---|
companies | Array 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), lei (European), or uscc (China A-share); the others are omitted. All are omitted for the rare row whose identifier is not yet on file. |
companies[].classification | Industry classification block — Pro+ only, omitted otherwise. See §1.10. |
credits_used | Always 175 when successful. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 403 | PLAN_TIER_INSUFFICIENT_COVERAGE | The requested jurisdiction is outside your plan's coverage scope. |
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 400 | JURISDICTION_INVALID | jurisdiction is not one of US, KR, JP, EU, CN, all. |
| 422 | VALIDATION_ERROR | A query parameter other than jurisdiction was supplied. Not charged. |
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"},
{"ticker": "600519_CN", "jurisdiction": "CN", "uscc": "9152000071430580XT"}
],
"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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | 1–10⁹. If set, ticker/year fields are optional. |
ticker | string | Conditional | Required if filing_id omitted. 1–32 characters. |
form_type | string | No | Default 10-K, max 32. |
fiscal_year | integer | Conditional | Required if filing_id omitted. 1990–2100. |
quarter | string | No | Max 4 characters. |
line_items | array of string | Yes | Non-empty; max 50 entries; each entry max 256 characters. |
light_weight_mode | boolean | No | Default false. When true, each results[*].dimensional_breakdowns is set to null; saves context when you already know exactly what you need. 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 fields are mutually exclusive; each result row carries exactly one of them.
When one line-item name matches more than one concept, results come pre-ordered by Akkru smart ranking, and the multi-tag _warnings entry lists the matched concepts in that same order. The order is a recommendation only — review all returned results and judge which one you need.
Results are consolidated totals only. A value reported on a dimension (a single product line, segment, or region) is never returned by name, even when a printed statement row carries that name. Two ways to read slice values: POST /data/facts/dimensional-breakdown / POST /data/line-items/dimensional-breakdown starting from the total's fact_id, or POST /data/statement to read the full statement table.
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 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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | 1–10⁹. If set, ticker/year fields are optional. |
ticker | string | Conditional | Required if filing_id omitted. 1–32 characters. |
form_type | string | No | Default 10-K, max 32. |
fiscal_year | integer | Conditional | Required if filing_id omitted. 1990–2100. |
quarter | string | No | Max 4 characters. |
fact_ids | array of string | Yes | Non-empty; max 500 strings; each max 128 characters. |
light_weight_mode | boolean | No | Default false. Leaner response — see Light-weight mode below; saves context when you already know exactly what you need. Charged identically. |
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter | Filing identity. |
source_url_prefix | Source-document URL base for this filing on its regulator's platform (SEC viewer for US filings; DART, EDINET, filings.xbrl.org, cninfo for KR / JP / EU / CN). May be null. The API does not return full source URLs; callers concatenate source_url_prefix with each fact's source_locator. |
results | Array 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_used | ceil(deduped_fact_id_count / 5) × 10. |
amendment_context | Optional; same idea as under filings when applicable. |
_warnings | Optional 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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Several filings match without a quarter; message lists available quarters. |
| 404 | DATA_FILING_NOT_FOUND | No filing for the given id or identity. |
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 422 | — | Validation (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_labelmode — the filer's original XBRL role string (varies per filer; e.g."CONSOLIDATED STATEMENTS OF OPERATIONS"for Apple). Returns the one matched block.statement_typemode — the canonical statement name (e.g."Income Statement","Balance Sheet","Comprehensive Income","Stockholders Equity","Cash Flow Statement"). CallPOST /data/filing-statementsfor the valid values in a specific filing. Case-insensitive; trailing(N)suffix is ignored. Returns every matching block; a block that combines several statements matches each of its names. Available for SEC filings only; userole_labelmode for other jurisdictions.
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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | Same rules as facts. |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No | |
role_label | string | XOR statement_type | 1–4000 characters; original filer XBRL role string. |
statement_type | string | XOR role_label | 1–4000 characters; canonical statement-type label. |
light_weight_mode | boolean | No | Default false. Leaner response — see Light-weight mode below; saves context when you already know exactly what you need. Charged identically. |
Credits:
role_labelmode: tiered 28 / 48. 28 is debited before the filing is resolved (balance below 28 → HTTP 402); the extra 20 of the higher (48-credit) tier is debited after matching, up to your remaining balance.statement_typemode: 28 flat, debited before the filing is resolved (balance below 28 → HTTP 402).
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter | Filing identity. |
matches | Array of match objects (length 1 for role_label mode; length 1+ for statement_type mode). Each has block_index, role_label, statement_type (array of names; more than one when the block combines several statements), matched_via (describes how it was selected), and block (the full statement block content). |
credits_used | Number of credits deducted. |
amendment_context | Optional; restatement or amendment information. |
_correction | Optional; present on the 48-credit tier. |
_warnings | Optional; 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,formathtml_locator:xlsx_cell
A notice is appended to _warnings.
Errors:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Ambiguous quarterly filings (charged). |
| 404 | DATA_FILING_NOT_FOUND | Filing not found. Still charged 28 credits. |
| 404 | DATA_STATEMENT_ROLE_LABEL_UNRESOLVED | role_label mode: no block matched; charged for the match tier reached. |
| 404 | DATA_STATEMENT_NOT_AVAILABLE_IN_FILING | statement_type mode: no block has this statement_type (charged). |
| 400 | DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_KR | statement_type mode: Korean (DART) filings not yet supported — coming soon (charged). |
| 400 | DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_JP | statement_type mode: Japanese (EDINET) filings not yet supported — coming soon (charged). |
| 400 | DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_EU | statement_type mode: European (ESEF) filings not yet supported — coming soon (charged). |
| 400 | DATA_STATEMENT_TYPE_UNSUPPORTED_FOR_CN | statement_type mode: not available for China A-share filings; use role_label mode (charged). |
| 404 | DATA_STATEMENT_BLOCK_JSON_MISSING | Label matched but the block content is unavailable (charged). |
| 402 | CREDITS_INSUFFICIENT | Balance below 28. |
| 422 | — | Validation (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 (array of canonical statement-type labels; more than one when the block combines several statements; 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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No |
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter | Filing identity. |
statements | Array of {block_index, statement_type, role_label}, ordered by block_index. |
credits_used | Always 10 when successful. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Ambiguous quarterly filings. |
| 404 | DATA_FILING_NOT_FOUND | Filing not found. Still charged 10 credits (this matches /data/filings and /data/company — discovery endpoints charge to cover the lookup attempt). |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits. |
| 422 | — | Validation. |
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, debited before the filing is resolved (a missing filing or statement is still charged); rate limit 120/minute. Available for SEC filings only.
| Endpoint | Statement returned |
|---|---|
POST /data/income-statement | Income Statement |
POST /data/comprehensive-income | Statement of Comprehensive Income |
POST /data/balance-sheet | Balance Sheet |
POST /data/cash-flow-statement | Cash Flow Statement |
POST /data/equity-statement | Statement of Stockholders' / Shareholders' Equity |
Request body: same fields as POST /data/statement minus role_label and statement_type.
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No | |
light_weight_mode | boolean | No | Default false. Saves context when you already know exactly what you need. |
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:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No | |
fact_id | string | Yes | The fact_id of a consolidated fact. |
recursive | boolean | No | Default true. When false, only the immediate children are returned. |
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter, source_url_prefix | Filing identity. |
root | The 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. |
groups | Array 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[].groups | Present only when recursive=true. Same shape, nested per level. |
_warnings | Optional. |
credits_used | ceil((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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Ambiguous quarterly filings. |
| 404 | DATA_FILING_NOT_FOUND | Filing not found. |
| 404 | DATA_FACT_NOT_FOUND | fact_id is not present in this filing. Still charged 10 credits. |
| 402 | CREDITS_INSUFFICIENT | Not enough credits. |
| 422 | — | Validation. |
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. When the name matches more than one concept, matches come pre-ordered by Akkru smart ranking (same ordering as POST /data/line-items); the order is a recommendation only — review all matches and judge which one you need.
Filing selection: standard (filing_id or ticker + fiscal_year + form_type + optional quarter).
Request:
| Field | Type | Required | Notes |
|---|---|---|---|
filing_id | integer | Conditional | |
ticker | string | Conditional | |
form_type | string | No | Default 10-K. |
fiscal_year | integer | Conditional | |
quarter | string | No | |
line_item | string | Yes | A single line-item name (e.g. "revenue"). |
recursive | boolean | No | Default true. |
Response:
| Field | Meaning |
|---|---|
ticker, form_type, fiscal_year, quarter, source_url_prefix | Filing identity. |
matches | Array of {root, groups, duplicate_root_fact_ids?} entries. |
matches[].root | Same shape as root in POST /data/facts/dimensional-breakdown, plus metric (echoes the request line_item) and _resolution_level ("L0"–"L3"). |
matches[].groups | Same shape and ordering as groups in POST /data/facts/dimensional-breakdown. Each fact also carries metric and _resolution_level. |
matches[].duplicate_root_fact_ids | Optional. Other fact_id values that resolved to the same logical fact as root. |
_correction | Optional. Same shape as on POST /data/line-items. |
_warnings | Optional. |
credits_used | Resolver 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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | Ambiguous quarterly filings. |
| 404 | DATA_FILING_NOT_FOUND | Filing not found. |
| 402 | CREDITS_ZERO_BALANCE | Balance is zero. |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits. |
| 422 | — | Validation. |
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. Results are consolidated totals only, same as §4.4.
Request:
| Field | Type | Required | Notes |
|---|---|---|---|
filings | array | Yes | 1–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_items | array of string | Yes | Non-empty; max 50 strings; each max 256 chars. |
light_weight_mode | boolean | No | Default false. Leaner response — see Light-weight mode below; saves context when you already know exactly what you need. Charged identically. |
Response:
| Field | Meaning |
|---|---|
amendment_contexts | Array parallel to results; each entry is an object or null. |
results | Each 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_used | Per credit rules in Section 2. |
_correction, _warnings | Optional; same general meaning as POST /data/line-items. Multi-concept line items are ordered by Akkru smart ranking within each row's facts, same as POST /data/line-items (a recommendation only — review all results). A _warnings entry is appended when the compared filings' fiscal period end dates differ by more than 45 days. 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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | A row needs quarter to disambiguate. |
| 404 | DATA_FILING_NOT_FOUND | A row’s filing does not exist (message may reference row index). |
| 402 | CREDITS_ZERO_BALANCE | Zero balance. |
| 422 | — | Limits, 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:
| Field | Type | Required | Notes |
|---|---|---|---|
filings | array | Yes | 1–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_mode | boolean | No | Default false. Leaner response — see Light-weight mode below; saves context when you already know exactly what you need. Charged identically. |
Response: Same shape as POST /data/compare/line-items. A _warnings entry is appended when the compared filings' fiscal period end dates differ by more than 45 days.
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:
| HTTP | error_code | When |
|---|---|---|
| 400 | DATA_FILING_QUARTER_REQUIRED | A row needs quarter to disambiguate. |
| 404 | DATA_FILING_NOT_FOUND | A row’s filing does not exist. |
| 402 | CREDITS_INSUFFICIENT | Balance is zero. |
| 422 | — | Limits, 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:
| Field | Meaning |
|---|---|
ticker, fiscal_year | Filing identity. |
download_url | The time-limited URL to download the Excel file. |
expires_in | Expiration time of the URL in seconds (e.g., 3600). |
credits_used | Always 300 when successful. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 404 | DATA_FILING_NOT_FOUND | Unknown filing_id. |
| 404 | DATA_EXCEL_NOT_AVAILABLE_FOR_FILING | No Excel attachment on file. |
| 404 | DATA_EXCEL_OBJECT_NOT_IN_STORAGE | The Excel file is not available. |
| 503 | DATA_EXCEL_PUBLIC_URL_UNAVAILABLE | A download URL cannot be provided for this request. |
| 402 | CREDITS_INSUFFICIENT | Insufficient 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
| Value | Meaning |
|---|---|
ok | Metric was computed; value is set. |
not_applicable | Metric does not apply to this filing. Carries a reason string; value is null. |
missing_input | A required XBRL fact is missing. Carries a missing_symbols list; value is null. |
needs_price_data | Price-sensitive metric called without current_price. value is null; pass current_price to upgrade to ok. |
needs_user_formula | The 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_history | A prior-period value is required (e.g. growth rates) but is not available from this filing's payload. value is null. |
divide_by_zero | Denominator was zero. value is null. |
eval_error | Formula 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
| Value | Meaning |
|---|---|
derived | Computed from multiple XBRL facts via the standard formula. |
as_reported | Single XBRL fact taken at face value, no formula run. |
composite | Built from multiple non-standard concepts (e.g. REIT CapEx = REInvestment + Maintenance). |
segment_sum | No consolidated total in the filing; summed across segment members. |
class_sum | Summed across asset / liability class members. |
company_override | A company-specific override rule produced the value. |
proxy_substituted | A proxy fact was used in place of the primary one (most often on ADR / foreign-issuer price-sensitive metrics). |
TTM_rollforward | On 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_accepted | Result of accept_suggested_formula=true — the engine's own suggested_formula was applied. |
user_formula_custom | Result of a caller-supplied formula_override. |
user_must_compute | Companion to status="needs_user_formula". Engine cannot compute automatically. |
not_applicable | Companion 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:
| Field | Meaning |
|---|---|
unit | Display unit. Either a currency code (usd, eur, twd, …) for absolute monetary metrics, or ratio / percent / days / shares etc. for non-monetary metrics. |
currency | Source currency for absolute monetary metrics. Absent on ratio / percent / unitless metrics. |
fx_required | true 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:
| Subfield | Meaning |
|---|---|
close | The price actually used in the formula (in the filer's reporting currency). |
date | Date of close. |
source | Identifier for the source of the price used. |
original_adr_price_usd | The USD ADR price supplied (or filing-date USD price). |
adr_ratio | ADR ratio (number of common shares per ADR). |
fx_rate_local_per_usd | Conversion factor used for the period. |
reporting_ccy | Filer'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:
| Field | Removed 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)
| Name | Unit | Formula |
|---|---|---|
gross_margin | ratio | (Revenue - CostOfRevenue) / Revenue |
operating_margin | ratio | OperatingIncome / Revenue |
net_margin | ratio | NetIncome / Revenue |
ebitda_margin | ratio | (OperatingIncome + DepreciationAndAmortization) / Revenue |
Returns (4)
| Name | Unit | Formula |
|---|---|---|
return_on_equity | ratio | NetIncome / ((Equity + EquityPrior) / 2) |
return_on_assets | ratio | NetIncome / ((Assets + AssetsPrior) / 2) |
return_on_invested_capital | ratio | NetIncome / (((Equity + LongTermDebt + ShortTermDebt) + (EquityPrior + LongTermDebtPrior + ShortTermDebtPrior)) / 2) |
return_on_tangible_equity | ratio | NetIncome / (((Equity - Goodwill - Intangibles) + (EquityPrior - GoodwillPrior - IntangiblesPrior)) / 2) |
Leverage (4)
| Name | Unit | Formula |
|---|---|---|
debt_to_equity | ratio | (LongTermDebt + ShortTermDebt) / Equity |
debt_to_assets | ratio | (LongTermDebt + ShortTermDebt) / Assets |
debt_to_ebitda | ratio | (LongTermDebt + ShortTermDebt) / (OperatingIncome + DepreciationAndAmortization) |
interest_coverage | ratio | OperatingIncome / InterestExpense |
Liquidity (3)
| Name | Unit | Formula |
|---|---|---|
current_ratio | ratio | CurrentAssets / CurrentLiabilities |
quick_ratio | ratio | (CurrentAssets - Inventory) / CurrentLiabilities |
cash_ratio | ratio | Cash / CurrentLiabilities |
Efficiency / activity (7)
| Name | Unit | Formula |
|---|---|---|
asset_turnover | ratio | Revenue / ((Assets + AssetsPrior) / 2) |
inventory_turnover | ratio | CostOfRevenue / Inventory |
receivables_turnover | ratio | Revenue / AccountsReceivable |
days_inventory | days | PeriodDays * Inventory / CostOfRevenue |
days_receivable | days | PeriodDays * AccountsReceivable / Revenue |
days_payable | days | PeriodDays * AccountsPayable / CostOfRevenue |
cash_conversion_cycle | days | days_inventory + days_receivable − days_payable |
Cash flow & shareholder returns (3)
| Name | Unit | Formula |
|---|---|---|
free_cash_flow | reporting currency | CFO - Capex |
fcf_margin | ratio | (CFO - Capex) / Revenue |
payout_ratio | ratio | Dividends / 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_pricefrom any realtime quote source (e.g. Finnhub, Alpha Vantage, yfinance).
| Name | Unit | Formula |
|---|---|---|
market_cap ★ | reporting currency | SharesOutstanding * Price |
enterprise_value ★ | reporting currency | MarketCap + LongTermDebt + ShortTermDebt - Cash |
pe_ratio ★ | ratio | Price / EPS |
price_to_book ★ | ratio | MarketCap / Equity |
price_to_sales ★ | ratio | MarketCap / Revenue |
price_to_cash_flow ★ | ratio | MarketCap / CFO |
ev_to_ebitda ★ | ratio | EnterpriseValue / (OperatingIncome + DepreciationAndAmortization) |
ev_to_revenue ★ | ratio | EnterpriseValue / Revenue |
ev_to_fcf ★ | ratio | EnterpriseValue / (CFO - Capex) |
fcf_yield ★ | ratio | (CFO - Capex) / MarketCap |
dividend_yield ★ | ratio | DividendsPerShare / Price |
buyback_yield ★ | ratio | StockRepurchases / 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.
| Name | Unit | Formula |
|---|---|---|
revenue_growth_yoy | ratio | (Revenue_t - Revenue_{t-4Q}) / Revenue_{t-4Q} |
revenue_growth_qoq | ratio | (Revenue_t - Revenue_{t-1Q}) / Revenue_{t-1Q} |
revenue_growth_qoq_single_quarter | ratio | (Revenue_Qn_single - Revenue_Q(n-1)_single) / Revenue_Q(n-1)_single |
eps_growth_yoy | ratio | (EPS_t - EPS_{t-4Q}) / EPS_{t-4Q} |
net_income_growth_yoy | ratio | (NI_t - NI_{t-4Q}) / NI_{t-4Q} |
fcf_growth_yoy | ratio | (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_currencyis e.g.brl,eur) reportfree_cash_flowandmarket_cap/enterprise_valuein their local currency; the per-metricunitfield 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:
| Field | Type | Required | Notes |
|---|---|---|---|
ticker | string | Yes | 1–32 characters. |
fiscal_year | integer | Conditional | 1990–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_types | array of string | No | Max 8 entries; each max 32 characters. |
quarter | string | No | Max 4 characters. |
as_of_date | string | No | If non-empty and invalid, it is echoed as "error" in the response and ignored for filtering; a warning may be returned. |
Response:
| Field | Meaning |
|---|---|
credits_used | Always 10 when successful. |
fiscal_year | Echo of request. |
as_of_date | Echo of request (or "error" if invalid). |
company | Company profile (ticker, cik, legal_name) or null. |
metric_groups | Array of objects; each includes metric_group_id, filing identity fields, dates, reporting currency, and optional amendment flags. |
form_types, quarter | Present only if you sent them in the request. |
_warnings | Optional; present when dates exclude all rows or are invalid. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 400 | METRICS_UNSUPPORTED_FOR_KR | Korean (DART) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_JP | Japanese (EDINET) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_EU | European (ESEF) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_CN | Computed metrics are not available for China A-share filings (not charged). |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits. |
| 422 | — | Validation (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:
| Field | Type | Default | Notes |
|---|---|---|---|
metric_group_id | integer | — | Required. 1–10⁹. From POST /metric/filings. |
as_of_date | string | null | YYYY-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_formula | boolean | false | When true, applies suggested formula hints included with the filing’s metrics (if any). |
formula_override | object | null | Per-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_price | number | null | USD 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_rate | number | null | Optional fallback FX rate (units of the filing's reporting_currency per 1 USD), used only when an up-to-date conversion rate 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_mode | boolean | false | When true, strips per-metric audit fields from every entry. A notice is appended to _warnings. Charged identically. See Light-weight mode. |
Response:
| Field | Meaning |
|---|---|
credits_used | Always 148 when successful. |
metric_group_id | The metric group ID actually used (may be null if excluded by as_of_date). |
valuation_context | Echo of flags and formula inputs. |
ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, source_url_prefix | Filing 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. |
segments | Array of segment data. |
price_insensitive_metrics | Object 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_metrics | Object 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_context | Present 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 an up-to-date conversion rate 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 an up-to-date rate was unavailable. mode is always present; on the two non-ok statuses a message states what to send. |
ttm_composite, dei_corrected | Optional root fields, present if they exist in the payload. |
amended | Present and true only when this filing had a later amendment merged in. The returned metric values are already the amended figures. |
corporate_actions | Optional root field, present when the ticker has corporate action events in the lookback window. Contains events_in_lookback and events_after_period_end (relative to this filing's period end); each event carries ex_date, ratio, type (forward / reverse), event_type (e.g. stock_split, stock_dividend), affects_total_shares, affects_holder_share_count, and relevant_to_metrics. Also carries adjustment_factor_to_today (factor converting this filing's per-share basis to the current basis), adjustment_factor_anchor (the date the factor is anchored on), and adjustment_factor_anchor_basis (how the anchor is chosen; period_end). When adjustment_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. Tickers with no events in the window omit the field entirely. |
reporting_currency | The 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. |
_warnings | Optional; warnings about amendments, formulas, or invalid dates. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 404 | METRIC_GROUP_NOT_FOUND | Unknown metric_group_id. |
| 404 | METRIC_SUMMARY_NOT_FOUND | Filing has no metrics summary. |
| 404 | METRIC_SUMMARY_OBJECT_MISSING | The metrics summary could not be retrieved. |
| 500 | METRIC_SUMMARY_INVALID_FORMAT | The metrics summary data is invalid. |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits. |
| 409 | METRIC_FORMULA_OVERRIDE_INVALID | Invalid formula_override. |
| 422 | METRIC_FORMULA_APPLY_FAILED | Formula application failed. |
| 422 | VALIDATION_ERROR | current_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": {
"events_after_period_end": [
{ "ex_date": "2024-06-10", "ratio": 10.0, "type": "forward", "event_type": "stock_split",
"affects_total_shares": true, "affects_holder_share_count": true, "relevant_to_metrics": true }
],
"events_in_lookback": [
{ "ex_date": "2021-07-20", "ratio": 4.0, "type": "forward", "event_type": "stock_split",
"affects_total_shares": true, "affects_holder_share_count": true, "relevant_to_metrics": true },
{ "ex_date": "2024-06-10", "ratio": 10.0, "type": "forward", "event_type": "stock_split",
"affects_total_shares": true, "affects_holder_share_count": true, "relevant_to_metrics": true }
],
"adjustment_factor_to_today": 10.0,
"adjustment_factor_anchor": "2024-04-28",
"adjustment_factor_anchor_basis": "period_end"
},
"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.
| Field | Type | Default | Notes |
|---|---|---|---|
metric_group_id | integer | — | Required. 1–10⁹. From POST /metric/filings. |
as_of_date | string | null | Same as POST /metric/all. |
accept_suggested_formula | boolean | false | Same as POST /metric/all. |
formula_override | object | null | Same as POST /metric/all. |
light_weight_mode | boolean | false | Same 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:
| Field | Type | Required | Notes |
|---|---|---|---|
metric_names | array of string | Yes | 1–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_mode | boolean | No | Same as POST /metric/all. See Light-weight mode. |
Credits: 148 per successful debit.
Response:
| Field | Meaning |
|---|---|
credits_used | Always 148 when successful. |
metric_group_id | The metric group ID actually used. |
valuation_context | Echo of flags, formula inputs, and requested metric_names. |
ticker, form_type, fiscal_year, quarter, cik, source_accession, primary_document, source_url_prefix | Filing 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_metrics | Object containing the requested price-insensitive metrics. Nested fact_refs / components entries with fact_id also expose source_locator (may be null). |
price_sensitive_metrics | Object 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_context | Present whenever the response would include a realtime block (same shape as in POST /metric/all). |
segments | Array of segment data. |
ttm_composite, dei_corrected | Optional root fields, present if they exist in the payload. |
corporate_actions | Optional 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. |
_warnings | Optional; warnings about amendments, formulas, or invalid dates. |
Errors: Same classes as POST /metric/all, plus:
| HTTP | error_code | When |
|---|---|---|
| 400 | METRIC_INVALID_METRIC_NAME | Unknown name or name not in this filing’s payload. |
| 402 | CREDITS_INSUFFICIENT | Insufficient 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:
| Field | Type | Default | Notes |
|---|---|---|---|
ticker | string | — | Required. 1–32 characters (returned uppercased). |
period_type | string | quarterly | Either 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). |
start_period_start | string | null | Optional filter: period start ISO date (YYYY-MM-DD). Invalid values echo as "error" in query_context and are ignored for filtering. |
end_period_end | string | null | Optional filter: same date rules. |
metric_names | array | null | If 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_date | string | null | Same meaning as /metric/all. |
accept_suggested_formula | boolean | false | |
formula_override | object | null | Same structure rules as /metric/all (including ≤ 50 concepts per metric). |
sort | string | period_end_asc | period_end_asc or period_end_desc. |
page | integer | 1 | Page index, 1–10⁶. |
page_size | integer | 3 | 1–5 (maximum page size). |
light_weight_mode | boolean | false | Same 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:
| Field | Meaning |
|---|---|
page_info | Object with pagination details (current_page, total_pages, page_size, total_items, next_page_hint). |
credits_used | Number of credits deducted for this request. |
ticker | Echo of request. |
query_context | Echo of the request parameters used for the query. |
periods | Array 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. |
_warnings | Optional; warnings about amendments, formulas, or invalid dates. |
Errors:
| HTTP | error_code | When |
|---|---|---|
| 400 | METRIC_INVALID_METRIC_NAME | Invalid or missing names in a period when metric_names is set. |
| 400 | METRICS_UNSUPPORTED_FOR_KR | Korean (DART) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_JP | Japanese (EDINET) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_EU | European (ESEF) metrics not yet supported — coming soon (not charged). |
| 400 | METRICS_UNSUPPORTED_FOR_CN | Computed metrics are not available for China A-share filings (not charged). |
| 402 | CREDITS_INSUFFICIENT | Insufficient credits for base or per-row charges. |
| 409 | METRIC_FORMULA_OVERRIDE_INVALID | Invalid formula_override. |
| 422 | METRIC_FORMULA_APPLY_FAILED | Formula 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.
| Endpoint | Metrics returned |
|---|---|
POST /metric/profitability | gross_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/growth | revenue_growth_yoy, revenue_growth_qoq, revenue_growth_qoq_single_quarter, eps_growth_yoy, net_income_growth_yoy, fcf_growth_yoy (6) |
POST /metric/financial-health | debt_to_equity, debt_to_assets, debt_to_ebitda, interest_coverage, current_ratio, quick_ratio, cash_ratio (7) |
POST /metric/efficiency | asset_turnover, inventory_turnover, receivables_turnover, days_inventory, days_receivable, days_payable, cash_conversion_cycle (7) |
POST /metric/cash-flow | free_cash_flow, fcf_margin, payout_ratio (3 — fcf_margin also in /metric/profitability) |
POST /metric/valuation | All 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-date | Same 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.
Example MCP tool call:
get_profitability_metrics(metric_group_id=46)
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. §6.9 screens institutional 13F filings; its rows use the snapshot object, also 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, callPOST /metric/allper ticker with a commoncurrent_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"):
| Field | Type | Default | Notes |
|---|---|---|---|
as_of_date | ISO date | today (UTC) | Must be ≤ today. Filings with filing_date > as_of_date are excluded (avoids backtest leakage). |
lookback | int 1–120 | 1 | Most recent N filings per ticker within scope. |
include_quarterly | bool | false | false → annual only (10-K / 20-F / 40-F). true adds 10-Q. |
tickers | string[] | omitted | Whitelist, max 100. Case-insensitive (normalized to upper). Empty or omitted = full universe. |
exclude_tickers | string[] | [] | Blacklist, max 100. |
usd_only | bool | false | When true, exclude foreign-currency reporters. |
sectors | string[] | omitted | Restrict the universe to these canonical sector buckets (the 12 in §1.10). Omitted = no sector restriction. |
where.filter | DSL tree | (required) | See §6.3. Leaf count 1–10, nesting depth ≤ 4. |
where.sort_by | string | see §6.3 | Metric name, "ticker", "period_end", "filing_date", or "match_count". |
where.sort_order | "asc" | "desc" | "asc" | |
include_metrics_using_filing_date_price | bool | true | false rejects price-sensitive metrics in filter / sort_by / include_metrics. |
exclude_derivations | string[] | [] | Subset of derived, as_reported, composite, class_sum, segment_sum, company_override, proxy_substituted, TTM_rollforward. |
include_metrics | string[] | [] | Extra metric names (≤ 10) to include in the response beyond filter-referenced ones. |
group_by_ticker | bool | true | true → grouped by ticker with nested filings[]. false → flat per-filing rows. |
page | int ≥ 1 | 1 | 1-indexed. |
page_size | int 1–100 | 50 | Counts 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 30-second server timeout (the request is charged; tighten filters and retry).
Example MCP tool call:
search_stocks(lookback=5, include_quarterly=False,
where={"filter": {"metric": "return_on_equity", "op": ">", "value": 0.2, "for_latest": 5}},
page_size=10)
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).
Example MCP tool call:
list_screener_filters()
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>}
| Operator | Value shape | Notes |
|---|---|---|
>, >=, <, <= | 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)
| Modifier | Meaning |
|---|---|
| (none) | Latest filing in lookback must satisfy. Equivalent to for_latest: 1. |
for_latest: N | Most recent N filings (right-anchored) all satisfy. |
for_consecutive: N | Some N adjacent filings within lookback all satisfy (sliding window over filing_date). |
for_at_least: N | At 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_metricslength: ≤ 10tickers,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:
| Scenario | Credits |
|---|---|
| 1 ticker, lookback=1, annual only, 1 leaf (best case) | 89 |
| Whole universe, lookback=30, quarterly+annual, 1 leaf | 425 |
2 tickers, lookback=5, annual, 2 leaves, 1 for_latest, 2 extra include_metrics | 242 |
Whole universe, lookback=120, 10 leaves all for_consecutive, 10 extra include_metrics | 1825 (worst case) |
Charge applies even when results is empty, and on 504 QUERY_TIMEOUT. 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:
| Field | Type | Default | Notes |
|---|---|---|---|
start_date, as_of_date | ISO date | — | as_of_date ≤ today; start_date ≤ as_of_date. |
tickers, exclude_tickers | string[] | omitted | ≤ 100 each. |
sectors | string[] | omitted | The 12 canonical buckets (§1.10). |
trade_filters | object | omitted | See §6.6. |
aggregate_filters | object[] | omitted | ≤ 8. Company-level gates — see §6.6. |
group_by_ticker | bool | true | true → grouped by ticker. false → flat rows. |
sort_by | string | — | Grouped: 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" | |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 |
Pagination cap: page × page_size ≤ 500 (422).
Response:
| Field | Meaning |
|---|---|
page, page_size, has_more, next_page | Pagination. |
as_of_date_applied, start_date_applied | Window actually used. |
results | group_by_ticker=true. Each entry: ticker, issuer, issuer_cik, txn_count (the company's full hit count, not the page's), transactions. |
transactions | group_by_ticker=false. Flat rows, each additionally carrying ticker, issuer, and issuer_cik. |
anomalies_excluded_count | Transactions excluded by the consistency checks; 0 when trade_filters.include_anomalies=true. |
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 30-second server timeout (charged).
Example MCP tool call:
search_insider_trades(start_date="2026-04-01", tickers=["AAPL"],
trade_filters={"transaction_code": ["P", "S"]}, page_size=10)
6.6 Filters (/screener/ownership)
trade_filters:
| Field | Type | Notes |
|---|---|---|
transaction_code | string[] | ≤ 20. Unknown codes dropped with a warning. |
relationship | string[] | is_director, is_officer, is_ten_percent_owner, is_other. OR semantics. |
is_derivative | bool | |
principal_amount_not_shares | bool | Omit for no filter, true for debt-principal rows only, false to exclude them. |
include_anomalies | bool | Default false. |
exclude_likely_merged | bool | Default false. |
include_unresolved_amendments | bool | Default false. |
conditions | object[] | ≤ 8. {field, op, value}. field ∈ transaction_value, price_per_share, shares, own_pct_change, split_adjusted_shares, split_adjusted_price. |
aggregate_filters: {metric, op, value}, metric ∈ value_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).
6.8 POST /screener/initial-holdings
Purpose: Full-library screening of initial holdings (Form 3). Holding-level conditions plus company-level aggregate gates; returns the matching holdings. Requires Pro or higher.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
start_date, as_of_date | ISO date | — | Window on filing_date. as_of_date ≤ today; start_date ≤ as_of_date. |
tickers, exclude_tickers | string[] | omitted | ≤ 100 each. |
sectors | string[] | omitted | The 12 canonical buckets (§1.10). |
holding_filters | object | omitted | See below. |
aggregate_filters | object[] | omitted | ≤ 8. Company-level gates — see below. |
group_by_ticker | bool | true | true → grouped by ticker. false → flat rows. |
sort_by | string | — | Grouped: ticker, holdings_count, shares_owned_total. Flat: filing_date, shares_owned, split_adjusted_shares_owned, underlying_security_shares, conversion_or_exercise_price. |
sort_order | "desc" | "asc" | "desc" | |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 |
Pagination cap: page × page_size ≤ 500 (422).
holding_filters:
| Field | Type | Notes |
|---|---|---|
relationship | string[] | is_director, is_officer, is_ten_percent_owner, is_other. OR semantics. |
is_derivative | bool | |
direct_or_indirect | "D" | "I" | |
include_anomalies | bool | Default false. |
exclude_likely_merged | bool | Default false. |
include_unresolved_amendments | bool | Default false. |
conditions | object[] | ≤ 8. {field, op, value}. field ∈ shares_owned, split_adjusted_shares_owned, underlying_security_shares, split_adjusted_underlying_security_shares, conversion_or_exercise_price. |
aggregate_filters: {metric, op, value}, metric ∈ filing_count, no_securities_filing_count, distinct_insiders, holdings_count, shares_owned_total. filing_count and no_securities_filing_count count filings, including filings that report no holdings; holdings_count and shares_owned_total are measured on the matching holdings.
Operators (both filter types): >, >=, <, <=, between ([lo, hi], lo ≤ hi).
Response:
| Field | Meaning |
|---|---|
page, page_size, has_more, next_page | Pagination. |
as_of_date_applied, start_date_applied | Window actually used. |
results | group_by_ticker=true. Each entry: ticker, issuer, issuer_cik, holdings_count and shares_owned_total (the company's full hit values, not the page's), holdings. |
holdings | group_by_ticker=false. Flat rows, each additionally carrying ticker, issuer, and issuer_cik. |
anomalies_excluded_count | Holdings excluded by the consistency checks; 0 when holding_filters.include_anomalies=true. |
credits_used, _warnings |
Every row carries accession_number, filing_date, period_of_report, no_securities_owned, source_url_prefix, insiders, and the holding object.
Credits: the §6.7 formula, with conditions = holding conditions + aggregate filters. Range 65–920.
Errors: 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, 403 PLAN_TIER_INSUFFICIENT below Pro, 504 QUERY_TIMEOUT at the 30-second server timeout (charged).
Example MCP tool call:
search_initial_holdings(tickers=["TSLA"], holding_filters={"is_derivative": False}, page_size=10)
6.9 POST /screener/institutional-holdings
Purpose: Screen SEC Form 13F institutional filings across the whole library. One row = one manager-quarter, carrying that quarter's headline numbers (the snapshot object defined in §7, plus the manager's cik and name). An empty body is the full listing, ordered by total_positions_value descending. Requires Pro or higher.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
start_date, end_date | ISO date | omitted | Bound the calendar quarter end: quarters whose period end falls inside the range participate. Give one date to bound one side only; omit both to scan every quarter. |
conditions | object[] | omitted | ≤ 8 of {field, op, value} — see below. |
is_amended | bool | omitted | true → only quarters with merged amendments; false → only quarters without. |
confidential | bool | omitted | Filter on the confidential-treatment flag. |
is_combination_report | bool | omitted | true → 13F COMBINATION REPORT quarters (the filer also reports holdings managed by other managers); false → 13F HOLDINGS REPORT quarters. |
sort_by | string | total_positions_value | One of total_positions_value, positions_count, derivatives_count, total_derivatives_notional, portfolio_value_qoq_pct, top1_security_pct, top10_security_pct, est_turnover, period, filing_date. |
sort_order | "desc" | "asc" | "desc" | |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 |
Pagination cap: page × page_size ≤ 500 (422).
conditions: each is {field, op, value} with op ∈ >, >=, <, <=, between ([lo, hi], lo ≤ hi, inclusive on both ends). field is one of total_positions_value, positions_count, derivatives_count, total_derivatives_notional, portfolio_value_qoq_pct, top1_security_pct, top10_security_pct, est_turnover, cover_table_value, new_count, add_count, reduce_count, hold_count, sold_out_count (the five counters read the quarter's activity_counts), or filing_date (values as ISO date strings).
A quarter where the compared field is null never matches. In particular, each manager's earliest quarter in the data window has null portfolio_value_qoq_pct, est_turnover and activity_counts (no prior quarter to compare against), so conditions on those fields never match it.
Response: matches (snapshot rows with cik / name), total_matches, page, page_size, credits_used, and — exactly when the returned rows cover more than one quarter — a _warnings entry saying the rows span quarters and the same manager can appear once per quarter.
Errors: 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT, 403 PLAN_TIER_INSUFFICIENT below Pro (all rejected before any deduction), 504 QUERY_TIMEOUT at the 30-second server timeout (charged).
Example MCP tool call:
search_institutional_holdings(start_date="2026-01-01", end_date="2026-03-31",
conditions=[{"field": "total_positions_value", "op": ">=", "value": 100000000000}],
page_size=10)
6.10 Credit formula (/screener/institutional-holdings)
POST /screener/institutional-holdings charges per call (paginate ⇒ each page bills independently):
credits = max(65, 200
+ 40 × conditions // numeric conditions + boolean filters actually passed
− narrowWindowDiscount // 40 when both dates are given and span ≤ 184 days (at most two quarters)
+ noWindowSurcharge) // 80 when neither date is given
Range 160–720.
| Scenario | Credits |
|---|---|
| Empty body (full listing) | 280 |
One quarter (start_date = end_date), 1 condition | 200 |
1 condition + is_amended, no dates | 360 |
Charged even when matches 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 (Form 4), initial beneficial-ownership statements (Form 3), and institutional holdings reports (Form 13F) reported to the SEC. US filings only. For the Form 4 / Form 3 endpoints, the plan coverage scope (§1.9) and history window (§1.8) apply as they do elsewhere, on the filing's filing_date; the 13F endpoints are organized by the filing manager (institution), not by company. The endpoints in this section are available on every plan; full-library screening is POST /screener/ownership, POST /screener/initial-holdings and POST /screener/institutional-holdings in Section 6, which require 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.
| Field | Meaning |
|---|---|
id | Transaction id. Pass to POST /ownership/transaction-ids. |
is_derivative | Derivative table row (true) or non-derivative (false). |
transaction_form_type | "4" or "5". |
transaction_date, transaction_code | As filed. |
transaction_type | Official SEC name for transaction_code. |
transaction_type_group | One 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_following | As filed. transaction_value may be null or 0. |
transaction_note | Filer-side note explaining a null / 0 value. null when absent. |
principal_amount_not_shares | true when shares holds a debt principal amount, not a share count. |
security_title, direct_or_indirect, nature_of_ownership | As filed. |
footnote_refs | Footnote ids for this transaction. Resolve against the filing's footnotes map. |
source_locator | Combine with the filing's source_url_prefix to build the SEC URL. |
restated | null, "cancelled", "modified", or "added" — set when an amendment changed this transaction. |
prior | Present only when restated is set. The pre-amendment values. |
split_adjusted | Present only when the filed values are not on the current per-share basis. See below. |
data_quality_flags | Present 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, manual_flags.
Rows flagged manual_flags also carry a manual_flags array of {code, note} entries describing the issue.
Flagged rows are excluded from POST /ownership/transactions, POST /ownership/stats and POST /screener/ownership unless include_anomalies=true (trade_filters.include_anomalies on the screener). Each endpoint reports how many it withheld: the listing in anomalies_excluded_on_page (this page only), stats and the screener in anomalies_excluded_count (the whole requested range).
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:
| Field | Type | Default | Notes |
|---|---|---|---|
ticker | string | — | Uppercased automatically. |
insider_cik | string | — | Digits only, ≤ 10; left-padded to 10. |
transaction_code | string[] | omitted | ≤ 20 entries. Unknown codes are dropped with a _warnings entry. |
transaction_form_type | "4" | "5" | omitted | |
relationship | string[] | omitted | Any of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing. |
include_unresolved_amendments | bool | false | |
exclude_likely_merged | bool | false | |
include_anomalies | bool | false | |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 | Counts filings. |
At least one of ticker / insider_cik is required (422 otherwise).
Response:
| Field | Meaning |
|---|---|
page, page_size, has_more, next_page | Pagination. |
anomalies_excluded_on_page | How many transactions on this page were withheld because they failed a consistency check. 0 when include_anomalies=true. Page-scoped: it counts only the rows hidden inside the filings this page returned, and is independent of the whole-range anomalies_excluded_count on POST /ownership/stats. |
filings | Array. 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_cik | The 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[].insiders | cik, name, is_director, is_officer, is_ten_percent_owner, is_other, officer_title, other_text. |
filings[].footnotes | Map of footnote id → text for this filing. |
_warnings | Optional. |
credits_used | Always 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.
Example MCP tool call:
list_insider_transactions(ticker="AAPL", transaction_code=["P", "S"], page_size=5)
7.2 POST /ownership/stats
Purpose: Aggregate statistics over one company and/or one insider, plus the ids of every transaction that contributed.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
ticker | string | — | |
insider_cik | string | — | |
start_date, as_of_date | ISO date | — | as_of_date ≤ today; start_date ≤ as_of_date. |
transaction_code | string[] | 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_anomalies | bool | false | |
relationship | string[] | omitted | Any of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing. |
is_derivative | bool | omitted | |
exclude_likely_merged | bool | false | |
include_unresolved_amendments | bool | false | |
ids_page | int ≥ 1 | 1 | Paginates transaction_ids only. |
ids_page_size | int 1–1000 | 200 |
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 field | Meaning |
|---|---|
value_acquired, value_disposed, net_value | Cash value totals. Transactions with no cash value contribute 0. |
shares_acquired, shares_disposed, net_shares | Share totals on the split-adjusted basis, excluding rows where principal_amount_not_shares is true. |
avg_price_acquired, avg_price_disposed | Total 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_disposed | Counts. |
txn_count_with_value | Transactions carrying a non-zero cash value. |
no_value_txn_count | Transactions with no cash value. |
ad_code_missing_count | Transactions counted in neither direction. |
principal_amount_txn_count | Debt-principal rows excluded from shares_* and avg_price_*. |
distinct_insiders | Distinct reporting owners in scope. |
filings_with_multiple_filers | Joint filings in scope. |
max_txn_value_acquired, max_txn_value_disposed | Largest single transaction per side. null when the side is empty. |
avg_value_per_txn_acquired, avg_value_per_txn_disposed | Mean over transactions that have a cash value. |
earliest_transaction_date, latest_transaction_date | Range actually covered. |
corporate_action_crossing | true when the window spans a corporate action. |
corporate_actions is present only when the request is anchored on a ticker that has corporate actions on file: an array of {ex_date, ratio, type, event_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.
Example MCP tool call:
get_insider_stats(ticker="AAPL", start_date="2025-01-01", method="ad")
7.3 POST /ownership/transaction-ids
Purpose: Fetch transactions by id — the detail companion to the transaction_ids returned by §7.2.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
transaction_ids | int[] | — | Required. 1–100 positive integers. Duplicates are removed with a _warnings entry. |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 100 | Counts 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.
Example MCP tool call:
get_insider_transactions_by_id(transaction_ids=[123456, 123457])
7.4 GET /ownership/tickers
Purpose: Discovery — every ticker with insider-trade or initial-holdings coverage. Unpaginated; cache the result.
Response: tickers (array of {ticker, jurisdiction, cik, forms}), credits_used, and optional _warnings. forms lists what the ticker has on file: "4" insider transactions, "3" initial holdings.
Credits: 175.
Errors: 402 CREDITS_INSUFFICIENT.
Example MCP tool call:
list_insider_tickers()
7.5 POST /ownership/names
Purpose: All insiders of one company, aggregated per CIK across its Form 4 and Form 3 filings.
Request:
| Field | Type | Notes |
|---|---|---|
ticker | string | Required. |
relationship | string[] | 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:
| Field | Meaning |
|---|---|
owner_cik, owner_name | Spelling from this insider's most recent filing. |
name_changed | true when earlier filings spelled the name differently. |
caveat | Present only when name_changed is true. |
ever_director, ever_officer, ever_ten_percent_owner, ever_other | true when any filing reported that role. |
latest_officer_title | Most recent non-null officer title. null when never reported. |
officer_title_as_of | Filing date latest_officer_title came from. |
filing_count | Filings of this company naming this insider, Form 4 and Form 3 together. |
form4_filing_count, form3_filing_count | The same count per form. |
earliest_filing_date, latest_filing_date | Range. |
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).
Example MCP tool call:
list_company_insiders(ticker="AAPL", relationship=["ever_officer"])
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.
Example MCP tool call:
list_insider_transaction_types()
Holding object
Returned by POST /ownership/initial-holdings, POST /ownership/initial-holding-ids, and POST /screener/initial-holdings. A Form 3 reports positions held on becoming an insider, so a holding has no transaction date, code, price, or direction.
| Field | Meaning |
|---|---|
id | Holding id. Pass to POST /ownership/initial-holding-ids. |
is_derivative | Derivative table row (true) or non-derivative (false). |
security_title, direct_or_indirect, nature_of_ownership | As filed. |
shares_owned | Amount of securities beneficially owned, as filed. null on derivative rows (the form has no such column for them) and on cancelled rows. |
footnote_refs | Footnote ids for this holding. Resolve against the filing's footnotes map. |
source_locator | Combine with the filing's source_url_prefix to build the SEC URL. |
restated | null, "cancelled", "modified", or "added" — set when an amendment changed this holding. |
prior | Present only when restated is set. The pre-amendment values. |
split_adjusted | Present only when the filed values are not on the current per-share basis. See below. |
data_quality_flags | Present 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, and underlying_security_value.
split_adjusted
Same meaning and presence rule as on the transaction object: present only when the filed values are not on the current per-share basis.
"split_adjusted": {
"shares_owned": 4000.0,
"underlying_security_shares": null,
"conversion_or_exercise_price": null,
"split_adjustment_factor": 4.0,
"comparable_to_post_split_basis": false
}
data_quality_flags
Rows that fail a consistency check carry one or more of:
missing_shares_owned, missing_underlying_amount, derivative_date_order, negative_shares_owned, negative_underlying_security_shares, negative_underlying_security_value, negative_conversion_or_exercise_price, manual_flags.
Rows flagged manual_flags also carry a manual_flags array of {code, note} entries describing the issue.
Flagged rows are excluded from POST /ownership/initial-holdings, POST /ownership/initial-holdings/stats and POST /screener/initial-holdings unless include_anomalies=true (holding_filters.include_anomalies on the screener). Each endpoint reports how many it withheld: the listing in anomalies_excluded_on_page (this page only), stats and the screener in anomalies_excluded_count (the whole requested range).
7.7 POST /ownership/initial-holdings
Purpose: Anchored listing of initial beneficial-ownership filings (Form 3) and their holdings. Requires ticker and/or insider_cik; unanchored queries belong to §6.8.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
ticker | string | — | Uppercased automatically. |
insider_cik | string | — | Digits only, ≤ 10; left-padded to 10. |
relationship | string[] | omitted | Any of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing. |
no_securities_owned | bool | omitted | true → only filings that report no holdings; false → only filings with holdings; omitted → both. |
include_unresolved_amendments | bool | false | |
exclude_likely_merged | bool | false | |
include_anomalies | bool | false | |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 | Counts filings. |
At least one of ticker / insider_cik is required (422 otherwise).
Response:
| Field | Meaning |
|---|---|
page, page_size, has_more, next_page | Pagination. |
anomalies_excluded_on_page | How many holdings on this page were withheld because they failed a consistency check. 0 when include_anomalies=true. Page-scoped, independent of the whole-range anomalies_excluded_count on POST /ownership/initial-holdings/stats. |
filings | Array. Each carries id, ticker, issuer, issuer_cik, accession_number, form_type, filing_date, period_of_report, date_of_original_submission, merge_status, remarks, no_securities_owned, source_url_prefix, insiders, footnotes, holdings, and amendments (present only when amendments were merged). |
filings[].no_securities_owned | true when the filer reported holding no securities; such filings have an empty holdings array. |
filings[].insiders | cik, name, is_director, is_officer, is_ten_percent_owner, is_other, officer_title, other_text. |
filings[].footnotes | Map of footnote id → text for this filing. |
_warnings | Optional. |
credits_used | Always 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.
Example MCP tool call:
list_initial_holdings(ticker="TSLA", page_size=5)
7.8 POST /ownership/initial-holdings/stats
Purpose: Aggregate statistics over the Form 3 filings of one company and/or one insider, plus the ids of every holding that contributed.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
ticker | string | — | |
insider_cik | string | — | |
start_date, as_of_date | ISO date | — | Window on filing_date. as_of_date ≤ today; start_date ≤ as_of_date. |
include_anomalies | bool | false | |
relationship | string[] | omitted | Any of is_director, is_officer, is_ten_percent_owner, is_other. OR semantics, evaluated per filing. |
is_derivative | bool | omitted | Restricts the holding totals; filing counts are unaffected. |
exclude_likely_merged | bool | false | |
include_unresolved_amendments | bool | false | |
ids_page | int ≥ 1 | 1 | Paginates holding_ids only. |
ids_page_size | int 1–1000 | 200 |
At least one of ticker / insider_cik is required.
Response: stats, 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, holding_ids.
stats field | Meaning |
|---|---|
filing_count | Form 3 filings in scope. |
no_securities_filing_count | Of those, filings that report no holdings. |
distinct_insiders | Distinct reporting owners in scope. |
filings_with_multiple_filers | Joint filings in scope. |
holdings_count, holdings_count_non_derivative, holdings_count_derivative | Holding rows in scope. |
shares_owned_total | Sum of shares_owned over non-derivative rows, on the split-adjusted basis. |
underlying_shares_total | Sum of underlying_security_shares over derivative rows, on the split-adjusted basis. |
earliest_filing_date, latest_filing_date | Range actually covered. |
corporate_action_crossing | true when the window spans a corporate action. |
corporate_actions is present only when the request is anchored on a ticker that has corporate actions on file: an array of {ex_date, ratio, type, event_type}.
_warnings names the count and the parameter that changes it whenever holdings were excluded.
Credits: 40 base, plus ceil(n / 1000) × 5 where n is the number of participating holdings. 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.
Example MCP tool call:
get_initial_holding_stats(ticker="TSLA", start_date="2020-01-01")
7.9 POST /ownership/initial-holding-ids
Purpose: Fetch holdings by id — the detail companion to the holding_ids returned by §7.8.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
holding_ids | int[] | — | Required. 1–100 positive integers. Duplicates are removed with a _warnings entry. |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 100 | Counts filings. |
Response: same envelope as §7.7, 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_HOLDING_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.
Example MCP tool call:
get_initial_holdings_by_id(holding_ids=[1234, 1235])
Snapshot object
Returned by POST /screener/institutional-holdings (as matches[], with cik and name) and POST /ownership/institutional-holdings/manager-history (as quarters[], without them — the manager identity sits once at the top of that response). One row = one manager × one calendar quarter, after amendments are merged.
| Field | Meaning |
|---|---|
cik, name | The filing manager. Screener rows only. |
period | Calendar quarter end the report covers. |
filing_date, accession | The filing this quarter's data comes from. |
is_combination_report | true = 13F COMBINATION REPORT (the filer also reports holdings managed by other managers), false = 13F HOLDINGS REPORT. |
confidential | The quarter carries confidential-treatment holdings. |
is_amended | Amendments were merged into this quarter. The full archive is on the portfolio endpoint's quarter header. |
unit_multiplier | 1, or the whole-quarter unit-correction multiplier applied to the filed values. When it is not 1, unit_multiplier_reason (corrected_error or pre2023_rule) is present; the key is omitted when null. |
total_positions_value | Total value of the stock holdings, USD. |
total_derivatives_notional | Total notional of the option holdings, USD. |
cover_table_value | The cover-page total as filed, verbatim. |
positions_count, derivatives_count | Live stock / option rows in the quarter. |
portfolio_value_qoq_pct | Quarter-over-quarter change of total_positions_value, percent. |
top1_security_pct, top10_security_pct | Portfolio share of the largest / ten largest stock holdings, percent (stock holdings only). |
est_turnover | Estimated traded value versus the prior quarter, USD. |
activity_counts | Map of row activity → count: NEW, ADD, REDUCE, HOLD, SOLD_OUT, CUSIP_CHANGE. |
sec_url | The URL opens the filing's EDGAR index page; see the files listed there for full details. |
Each manager's earliest quarter in the data window has no prior quarter to compare against: its portfolio_value_qoq_pct, est_turnover and activity_counts are null and must not be read as everything being new.
Institutional holding object
Returned by POST /ownership/institutional-holdings/portfolio and POST /ownership/institutional-holdings/security (flat mode) as transactions[]. Security rows additionally carry manager_cik / manager_name. Three row kinds, told apart by type:
positions— a stock holding.derivatives— an option holding (put_callsays which side).exited— a position closed out this quarter: identity plus the closing deltas only (d_shares, andd_valueord_notional_value_usd).
| Field | Meaning |
|---|---|
type, period | Row kind and calendar quarter end. |
cusip, ticker, ticker_status, issuer, issuer_norm, class, security_type | Security identity. issuer is the name as filed, issuer_norm the normalized name, class the share-class text as filed. ticker_status is us_listing, when_issued, non_us_listing, none (no matching listed ticker), or null. |
put_call | "Put" / "Call" on option rows; null on stock rows. When the row kinds are mixed it is one of the fields telling them apart. |
shares_or_principal_amount | SH = the row's shares is a share count; PRN = a principal amount in USD (debt securities), not a share count; null = a row cancelled by an amendment, or missing in the original filing. |
shares | Share count or principal amount, per the previous field. |
vote_sole, vote_shared, vote_none | Voting-authority split as filed. |
discretion | Investment discretion as filed (SOLE, DFND, OTR and combinations). |
source_accessions | The amendment filings this row's current values come from; null = the quarter's main filing. |
activity | NEW / ADD / REDUCE / HOLD / CUSIP_CHANGE versus the prior quarter. Null on each manager's earliest data-window quarter. Exited rows carry no activity label — the exit is the row itself. |
predecessor_cusip | On CUSIP_CHANGE rows: the CUSIP this security was held under in the prior quarter. |
shares_before_cusip_change | Shares held under the predecessor CUSIP; present only when non-null, directly after predecessor_cusip. |
d_pct | Share change versus the prior quarter, percent (d_shares is the absolute change). |
unit_multiplier | Row-level unit-correction multiplier (can be fractional, e.g. 0.001); present when this row's filed value was individually corrected. |
restated | added / modified / cancelled when an amendment changed this row; null otherwise. A cancelled row is a tombstone: its current-value fields are null and the old values sit in prior_versions. |
prior_versions | Pre-amendment field values, newest first. |
submgr_breakdown | Sub-manager split of the position: {submgr_index, submgr_name, shares, pct_of_position}. |
Stock rows additionally carry value (USD), weight (this holding's share of the quarter's total_positions_value — a percent string with two decimals, e.g. "61.88%"; null on cancelled rows), rank (1 = the quarter's largest stock holding), avg_price, and d_value. Option rows carry notional_value_usd, underlying_price_implied, and d_notional_value_usd.
Warnings (_warnings, present only when non-empty) on the portfolio / security endpoints flag:
- an amendment whose claimed action type differs from its actual action (portfolio only — see the
claimed_typeandactionfields inquarter.amendments_merged); - unit-correction multipliers in the returned result, whole-quarter or row-level — see the
unit_multiplierfields; CUSIP_CHANGErows in the returned result — see each row'spredecessor_cusip;- a manager's earliest data-window quarter in the returned result —
activity,d_shares,d_value,d_pctand the quarter'sest_turnover,portfolio_value_qoq_pct,activity_countsare null there and must not be read as everything being new.
7.10 POST /ownership/institutional-holdings/manager-history
Purpose: One manager's 13F history — one snapshot object per quarter filed, newest first by default.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
cik | string | — | 13F filer CIK, digits verbatim (not zero-padded). Provide exactly one of cik / name. |
name | string | — | Manager name, filed or normalized spelling. Whitespace and case are ignored; otherwise the match is exact. |
sort_order | "desc" | "asc" | "desc" | By period. |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 | Counts quarters. |
Response: manager (cik, name, sec_url_prefix — the manager's EDGAR directory prefix), quarters (snapshot rows), total_quarters, page, page_size, credits_used.
Credits: 30.
Errors: 404 OWNERSHIP_MANAGER_NOT_FOUND when no single manager matches (charged) — several managers can file under the same or a similar name; query by CIK instead. 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.
Example MCP tool call:
get_institutional_manager_history(cik="1000097", page_size=8)
7.11 POST /ownership/institutional-holdings/portfolio
Purpose: One manager × one quarter — the holdings detail as institutional holding objects, under a quarter header that repeats the snapshot numbers and carries the amendment archive.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
cik / name | string | — | Exactly one, as in §7.10. |
quarter | string | — | Required. Calendar quarter label YYYYQn, e.g. 2026Q1 (Q1 = Mar 31, Q2 = Jun 30, Q3 = Sep 30, Q4 = Dec 31). |
type | string | omitted | positions / derivatives / exited. Omitted = all three; each row carries its own type. The response echoes the filter as types. |
activity | string[] | omitted | ≤ 6 of NEW, ADD, REDUCE, HOLD, CUSIP_CHANGE. Unknown values are dropped with a _warnings entry. Exited rows carry no activity label, so combined with type="exited" the filter matches nothing (a warning says so). |
restated | string[] | omitted | ≤ 3 of added, modified, cancelled. |
cusip | string | omitted | 9 characters; pins one security inside the quarter. Give cusip or ticker, not both. |
ticker | string | omitted | Uppercased automatically. |
sort_by | string | omitted | period, d_shares, ticker, issuer_norm, type (row kind as text, alphabetical: derivatives < exited < positions). Omitted = the filed row order. |
sort_order | "desc" | "asc" | "desc" | |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 | Counts rows after filtering, all kinds together. |
Response: manager (as in §7.10); quarter — a snapshot object plus accessions (every filing applied to the quarter, in order), sec_locators (accession → EDGAR index-page path; combine with the manager's sec_url_prefix), amendments_merged (see below) and prior_versions (superseded cover pages); then types, transactions, total_transactions, page, page_size, credits_used, and _warnings (see the institutional holding object).
amendments_merged — one entry per amendment applied to the quarter: accession, filing_date, claimed_type (the type the amendment declared for itself, or null), action (what it actually did: REPLACE / MERGE_ADD / DUPLICATE_SUPERSEDED / REJECTED), cover_total, confidential, and positions_added / positions_restated / positions_cancelled.
Credits: 30 per page.
Errors: 404 OWNERSHIP_MANAGER_NOT_FOUND (charged); 404 OWNERSHIP_MANAGER_QUARTER_NOT_FOUND when the manager exists but no 13F data was found for that quarter (charged); 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.
Example MCP tool call:
get_institutional_portfolio(cik="1000097", quarter="2026Q1", type="positions", page_size=50)
7.12 POST /ownership/institutional-holdings/security
Purpose: One security's holder rows across managers — who holds it, quarter by quarter. Flat mode returns institutional holding objects with manager_cik / manager_name on each row; group_by_quarter=true switches to one aggregate row per quarter.
Request:
| Field | Type | Default | Notes |
|---|---|---|---|
cusip | string | — | 9 characters. Provide exactly one of cusip / ticker. |
ticker | string | — | Uppercased automatically. A ticker can match several CUSIPs (share classes, renumberings); rows for all of them are included, securities lists each one, and a _warnings entry says how many matched. |
quarter | string | omitted | YYYYQn. Omitted = every quarter, newest first. |
type | string | omitted | As in §7.11. |
activity | string[] | omitted | As in §7.11. |
group_by_quarter | bool | false | true → one aggregate row per quarter (period, holders, total_shares, total_value, computed over live stock rows), unpaged; type / activity / sort_by / page are ignored with a warning. |
sort_by | string | omitted | period, d_shares, ticker, issuer_norm, type. Omitted = newest quarter first. |
sort_order | "desc" | "asc" | "desc" | |
page | int ≥ 1 | 1 | |
page_size | int 1–100 | 50 |
Response: securities — one entry per matched CUSIP: cusip, ticker, ticker_status, issuer_norm, security_type, first_seen / last_seen (first / latest quarter end the security appears in), latest_holders (holder count at last_seen); then group_by_quarter, credits_used, and either the flat fields (types, transactions, total_transactions, page, page_size) or the grouped ones (transactions, total_transactions — no paging fields).
Credits: 30 per page (flat mode); 40 flat (group_by_quarter=true, unpaged).
Errors: 404 OWNERSHIP_SECURITY_NOT_FOUND (charged), 422 VALIDATION_ERROR, 402 CREDITS_INSUFFICIENT.
Example MCP tool call:
get_institutional_security_holders(ticker="AAPL", quarter="2026Q1", page_size=50)
8. API key, account, and plan errors
| HTTP | When |
|---|---|
| 401 | AUTH_API_KEY_MISSING — no X-API-Key header and no bearer token. |
| 403 | AUTH_API_KEY_INVALID — unknown or inactive key. |
| 403 | AUTH_USER_INACTIVE — the key's account is inactive or deleted. |
| 403 | AUTH_EMAIL_NOT_VERIFIED — the key's account has not verified its email. |
| 403 | AUTH_API_KEY_EXPIRED — key past its expiry. |
| 403 | AUTH_API_KEY_INACTIVE — key disabled by inactivity policy. |
| 403 | PLAN_TIER_INSUFFICIENT — the endpoint is not available on the caller's current plan. |
| 403 | PLAN_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. |
| 403 | PLAN_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. |
| 403 | PLAN_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):
| Limit | Value |
|---|---|
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 request | 25 |
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 size | 5 |
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. A tool call that includes an argument the tool does not declare is rejected before it runs and is not charged.
10.1 Connect via OAuth (recommended for AI assistants)
For AI clients with built-in MCP support (Claude Desktop, Claude Web, etc.):
- In your AI client, add
https://api.akkrudata.ai/mcpas a custom MCP connector. - Click Connect. Your browser will open an AkkruData sign-in page.
- Sign in with the same credentials you use for the dashboard (email/password, Google, or GitHub).
- Review the connecting AI client's reported identity, then click Authorize.
- 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
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.