{"openapi":"3.1.0","info":{"title":"May6 API","version":"v1","summary":"Multi-source financial-data aggregator with BYO-key passthrough","description":"May6 unifies Layer 1 (owned aggregation: OpenFIGI, EDGAR, MIC, FRED, ECB) and Layer 2 (BYO-key passthrough: Twelve Data, Polygon, FMP, Tiingo, …) behind a single agentic-friendly REST surface. Every response is wrapped in a consistent { data, meta, links } envelope; every error follows { error, meta, links }.\n\n## Authentication\n\nAuthenticate by sending `Authorization: Bearer m6_live_<your_key>` with each request. Create a key at https://may6.vercel.app/dashboard/api-keys after signing up at https://may6.vercel.app/sign-up. Anonymous requests (no Authorization header) are accepted but heavily rate-limited (10/min, 100/day) — use them only for one-off exploration, not for production traffic.\n\n## Tiers and rate limits\n\nLimits are applied per-minute on the customer-id key derived from your Bearer token (or globally for anonymous traffic).\n\n| Tier        | Per minute | Per day  | Status                |\n| ----------- | ---------- | -------- | --------------------- |\n| Anonymous   |   10       |   100    | Always available      |\n| Free        |   60       | 1,000    | Free, available today |\n| Starter     |  300       | 10,000   | $79/mo — V1.P7b       |\n| Pro         | 1,200      | 100,000  | $299/mo — V1.P7b      |\n| Enterprise  | 6,000      | 1,000,000| Sales-led — V1.P7b/c  |\n\nBoth per-minute and per-day limits are enforced. Rate limits are keyed to your plan slug (`free`, `starter`, `pro`, `enterprise`) synced from Clerk Billing; see /pricing for current plans. BYO-key passthrough (`X-Provider-Key-*` headers) requires a paid plan — free-plan and anonymous requests that include one are rejected with HTTP 403 `byo_key_not_allowed`. Hitting the limit returns HTTP 429 with `error.code = \"rate_limited\"` and a `Retry-After: 60` header.\n\n## Identity model — FIGI-first\n\nMay6 uses Bloomberg's Open Symbology (FIGI) as the canonical persistent identifier for instruments. Every instrument record carries a `share_class_figi`, every listing carries a venue-level `figi` and a country-composite `composite_figi`, and the per-listing Bloomberg ticker conventions (`bbg_ticker`, `bbg_composite_ticker`) are derived deterministically from this graph. ISIN, CUSIP, and SEDOL are sourced opportunistically — present for the curated starter pack and any instrument we've cross-referenced from a paid dataset, absent on the long tail. For comprehensive ISIN coverage on instruments outside that set, supply your own provider key once a Layer 2 source with ISIN coverage is wired up (V1.P6+).\n\n## Caching\n\nResponses are served from a Redis edge cache when available. `meta.source` is set to `\"redis\"` and `meta.cache_hit` to `true` when the response is served from cache; the original upstream attribution is preserved in `meta.source_attribution` so display attribution stays correct.\n\nTTLs:\n- `/instruments/{ticker}` — 1 hour (Layer 1 origin in Postgres)\n- `/prices/{ticker}/eod` — 1 hour (cron refreshes daily; this is the staleness ceiling)\n- `/fundamentals/{ticker}` — 24 hours (EDGAR filings are stable once filed)\n\nKnown limitation: a cron-triggered refresh of Layer 1 data does not invalidate the cache; up to 1 hour of staleness can occur on prices after a cron run completes.\n\n## BYO-key per-customer cache isolation\n\nLayer 2 endpoints (currently `/prices/{ticker}/eod`) accept per-request provider keys via `X-Provider-Key-{Source}` headers (e.g. `X-Provider-Key-Twelve-Data: <key>`). When a BYO-key header is present the cache key is namespaced with a SHA-256-derived hash of that key, so customer A never reads customer B's cached upstream data. Provider keys are never persisted — they flow through to upstream and are discarded after the request completes. See https://may6.vercel.app for the project overview.","contact":{"name":"May6","url":"https://may6.vercel.app"},"license":{"name":"Proprietary","identifier":"LicenseRef-May6-v1"}},"servers":[{"url":"https://may6.vercel.app/api/v1","description":"Production"}],"tags":[{"name":"instruments","description":"Resolve a security to its canonical instrument graph (identifiers + listings)."},{"name":"prices","description":"Daily end-of-day OHLCV price history. Layer 1 (cron-populated via Twelve Data) with optional Layer 2 BYO-key fallback."},{"name":"fundamentals","description":"Per-issuer financial fundamentals from SEC EDGAR XBRL filings. US-listed issuers only (CIK required)."}],"paths":{"/instruments":{"get":{"tags":["instruments"],"summary":"Search instruments by free-text query","description":"Free-text identifier search powered by OpenFIGI's `/v3/filter` + share-class FIGI fan-out. Use this when you don't have an exact ticker yet — \"apple\", \"alphabet\", \"sap\" all surface their canonical primary listings ahead of obscure cross-listings or leveraged ETPs.\n\nResults are cache-first: a Redis hit returns immediately with `meta.source = \"redis\"` and `meta.cache_hit = true`. On a cache miss, OpenFIGI is queried and the response is also written through to `instrument` / `instrument_listing` / `instrument_identifier` so subsequent ticker-keyed reads at `/instruments/{ticker}` are served from Postgres without a fresh OpenFIGI round-trip.\n\nSearch is Layer 1 only — no `X-Provider-Key-*` header is honored, since OpenFIGI is owned aggregation served by the May6 server key.","operationId":"searchInstruments","parameters":[{"name":"q","in":"query","required":true,"description":"Free-text query (company name, ticker, partial name). Case-insensitive; trimmed; 1–100 characters.","schema":{"type":"string","minLength":1,"maxLength":100},"example":"apple"},{"name":"limit","in":"query","required":false,"description":"Max matches to return after ranking + optional exchange filter. 1–100; defaults to 25. Pagination beyond `limit` is not supported today.","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"example":25},{"name":"exchange","in":"query","required":false,"description":"Optional ISO 10383 MIC filter (e.g. XNAS, XLON, XETR). Returned matches will all carry an `exchange.mic` equal to this value; matches with no mappable MIC (composite-tape codes like \"US\") are excluded when this filter is set. An unknown MIC simply produces zero matches.","schema":{"type":"string","minLength":4,"maxLength":4},"example":"XNAS"}],"responses":{"200":{"description":"Match list for the query. Empty `data.matches` means no instrument satisfied the (q, limit, exchange) combination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstrumentsSearchEnvelope"}}}},"400":{"description":"Invalid request (missing q, q too long, limit out of range, …).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Bearer header present but malformed or referring to an unknown / revoked key (`error.code = \"auth_invalid\"`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — a BYO-key (`X-Provider-Key-*`) header was supplied by a free-plan or anonymous caller. BYO-key passthrough requires a paid plan; `error.code = \"byo_key_not_allowed\"`. (Search itself is Layer-1 only and ignores BYO-key headers, but the gate applies uniformly across /api/v1/*.)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Customer or anonymous tier rate limit exceeded (`error.code = \"rate_limited\"`), OR upstream provider quota exhausted. The `Retry-After` header carries the wait time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"OpenFIGI returned an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/instruments/{ticker}":{"get":{"tags":["instruments"],"summary":"Look up instrument by ticker","description":"Returns the canonical Instrument for the given ticker, including all known identifiers (CUSIP, ISIN, SEDOL, FIGI variants, CIK, …) and all known cross-listings. Ticker matching is case-insensitive against the canonical ticker identifier; ambiguous tickers (e.g. 'MSFT' as both Microsoft on Nasdaq and an OTC ADR) resolve to the first match — use `?exchange=` to disambiguate cross-listings.","operationId":"getInstrumentByTicker","parameters":[{"name":"ticker","in":"path","required":true,"description":"Local ticker symbol, case-insensitive (e.g. AAPL, SAP, NESN).","schema":{"type":"string","minLength":1,"maxLength":32},"example":"AAPL"},{"name":"exchange","in":"query","required":false,"description":"ISO 10383 MIC code to restrict the `listings` array to a single venue (e.g. XNAS, XLON, XETR). The instrument record itself is unchanged; only the embedded listings are filtered. If no listings match, returns 200 with an empty listings array.","schema":{"type":"string","minLength":4,"maxLength":4},"example":"XNAS"},{"name":"identifiers","in":"query","required":false,"description":"Filter the `data.identifiers` array. Three modes:\n- omitted (default): every identifier known for the instrument, including the full V1.P2 share-class FIGI fan-out — Apple alone has ~220 rows.\n- `primary`: canonical-only set (composite_figi, share_class_figi, ticker, isin, cik, lei) restricted to currently-effective rows. Use this for chat-tool / agent responses where the full dump is too verbose.\n- `none`: empty array. Use when the caller only wants instrument metadata + listings.","schema":{"type":"string","enum":["primary","none"]},"example":"primary"}],"responses":{"200":{"description":"Instrument found. The `data.listings` array may be empty if `?exchange=` was passed and no listing matched.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstrumentEnvelope"}}}},"400":{"description":"Invalid request (missing or malformed parameters).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Bearer header present but malformed or referring to an unknown / revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — a BYO-key (`X-Provider-Key-*`) header was supplied by a free-plan or anonymous caller. BYO-key passthrough requires a paid plan; `error.code = \"byo_key_not_allowed\"`. Upgrade at /pricing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"No instrument matches the supplied ticker. Body uses error.code = 'not_found'.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"405":{"description":"Method not allowed; this endpoint only supports GET.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Customer or anonymous tier rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/prices/{ticker}/eod":{"get":{"tags":["prices"],"summary":"Daily EOD prices for a ticker","description":"Returns daily open / high / low / close / volume rows for the resolved listing. Reads cache → Postgres (Layer 1, cron-populated) → optional Layer 2 BYO-key upstream call.\n\n- `meta.source = \"may6\"` when served from Postgres.\n- `meta.source = \"twelve_data\"` when served from a fresh Layer 2 upstream call.\n- `meta.source = \"redis\"` when served from cache; `meta.cache_hit = true`.\n\n`?exchange=` defaults to the instrument's primary listing. `?from=` defaults to today minus 365 days; `?to=` defaults to today. Both must be ISO YYYY-MM-DD.\n\nIf no Layer 1 rows exist for the resolved listing AND no `X-Provider-Key-Twelve-Data` header was supplied, returns 404 with a hint pointing to the BYO-key flow.","operationId":"getPricesEod","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":32},"example":"AAPL"},{"name":"exchange","in":"query","required":false,"description":"ISO 10383 MIC code (e.g. XNAS, XLON). Defaults to the instrument's primary listing.","schema":{"type":"string","minLength":4,"maxLength":4},"example":"XNAS"},{"name":"from","in":"query","required":false,"description":"Inclusive start date, ISO YYYY-MM-DD. Defaults to today minus 365 days.","schema":{"type":"string","format":"date"},"example":"2025-12-01"},{"name":"to","in":"query","required":false,"description":"Inclusive end date, ISO YYYY-MM-DD. Defaults to today.","schema":{"type":"string","format":"date"},"example":"2025-12-31"},{"name":"X-Provider-Key-Twelve-Data","in":"header","required":false,"description":"Layer 2 BYO-key for Twelve Data. When supplied, fallbacks to the upstream API on Layer 1 cache miss; when omitted, Layer 1 misses return 404. The key is never persisted; cache entries are namespaced by a 64-bit hash of this value to isolate customer slices.","schema":{"type":"string"}}],"responses":{"200":{"description":"Price rows found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricesEodEnvelope"}}}},"400":{"description":"Invalid date or other request shape.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Bearer header present but malformed or referring to an unknown / revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — a BYO-key (`X-Provider-Key-Twelve-Data`) header was supplied by a free-plan or anonymous caller. BYO-key passthrough requires a paid plan; `error.code = \"byo_key_not_allowed\"`. Upgrade at /pricing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"No instrument or no Layer 1 prices in range (and no BYO-key supplied for Layer 2 fallback).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Customer/anonymous tier rate limit, OR Layer 2 upstream rate-limited the request. `Retry-After` header set; `error.retry_after_seconds` carries the same value as JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"502":{"description":"Layer 2 upstream returned an error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/fundamentals/{ticker}":{"get":{"tags":["fundamentals"],"summary":"EDGAR XBRL fundamentals for a ticker","description":"Returns financial fundamentals (Revenues, NetIncomeLoss, Assets, …) for the issuer behind the supplied ticker. Sourced from SEC EDGAR XBRL company-facts and refreshed nightly by cron. Only US-listed issuers (CIK required) are covered today; non-US issuers return 404.\n\n`?concept=` filters to a single XBRL concept name (case-sensitive); omit to receive all rows for the issuer.\n\n`meta.source = \"may6\"` on Postgres hit, `\"redis\"` on cache hit.","operationId":"getFundamentals","parameters":[{"name":"ticker","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":32},"example":"AAPL"},{"name":"concept","in":"query","required":false,"description":"Optional XBRL concept filter (case-sensitive, namespaced as ingested from EDGAR — e.g. `us-gaap:Revenues`, `us-gaap:NetIncomeLoss`, `us-gaap:Assets`).","schema":{"type":"string","minLength":1,"maxLength":128},"example":"us-gaap:Revenues"}],"responses":{"200":{"description":"Fundamentals found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FundamentalsEnvelope"}}}},"401":{"description":"Bearer header present but malformed or referring to an unknown / revoked key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Forbidden — a BYO-key (`X-Provider-Key-*`) header was supplied by a free-plan or anonymous caller. BYO-key passthrough requires a paid plan; `error.code = \"byo_key_not_allowed\"`. Upgrade at /pricing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"No instrument with this ticker, no CIK on file (non-US issuer), or no fundamentals matching the optional concept filter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Customer or anonymous tier rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}},"security":[{"bearerAuth":[]},{}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"m6_live_<32 url-safe chars>","description":"Send `Authorization: Bearer m6_live_<your_key>`. Create keys at https://may6.vercel.app/dashboard/api-keys. Requests without this header are accepted but share a single anonymous bucket of 10 req/min — sign up for a free Hobby key to lift that ceiling."}},"schemas":{"AssetClass":{"type":"string","enum":["equity_common","equity_preferred","etf","etn","mutual_fund","other"]},"IdentifierType":{"type":"string","enum":["cusip","isin","sedol","figi","composite_figi","share_class_figi","ticker","cik","lei","ric","bbg_ticker"]},"Identifier":{"type":"object","required":["type","value","effective_from"],"properties":{"type":{"$ref":"#/components/schemas/IdentifierType"},"value":{"type":"string"},"effective_from":{"type":"string","format":"date"},"effective_to":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]}}},"Listing":{"type":"object","description":"A single venue listing for an instrument, augmented with Bloomberg-symbology display fields derived from existing data. Per-listing vs composite Bloomberg tickers:\n- `bbg_ticker` is the venue-specific Bloomberg ticker. Format: `<local_ticker> <openfigi_exch_code> <yellow_key>`. Example: \"AAPL UW Equity\" (NASDAQ Global Select). Disambiguates exchange — useful for execution and per-venue analytics.\n- `bbg_composite_ticker` is the country composite Bloomberg ticker. Format: `<local_ticker> <country_composite_code> <yellow_key>`. Example: \"AAPL US Equity\" (US composite tape — covers NYSE/NASDAQ/ARCA combined). Useful when venue specificity isn't needed.\n\nBoth are derived display formats, not globally unique persistent identifiers. Corporate actions, ticker recycling, or relisting may cause the same value to refer to different historical instruments. For canonical persistent identity, use `share_class_figi` or `composite_figi`.","required":["id","exchange_mic","local_ticker","local_currency","is_primary_listing"],"properties":{"id":{"type":"integer"},"exchange_mic":{"type":"string","description":"ISO 10383 MIC code","minLength":4,"maxLength":4},"exchange_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"country_code":{"anyOf":[{"type":"string","minLength":2,"maxLength":2},{"type":"null"}]},"local_ticker":{"type":"string"},"local_currency":{"type":"string","description":"ISO 4217 currency code","minLength":3,"maxLength":3},"figi":{"anyOf":[{"type":"string","minLength":12,"maxLength":12},{"type":"null"}]},"composite_figi":{"anyOf":[{"type":"string","minLength":12,"maxLength":12},{"type":"null"}]},"is_primary_listing":{"type":"boolean"},"openfigi_exch_code":{"anyOf":[{"type":"string","minLength":2,"maxLength":2},{"type":"null"}],"description":"OpenFIGI 2-letter exchange code (UW=Nasdaq Global Select, UN=NYSE, UP=NYSE Arca, LN=LSE, GY=Xetra, …). Null when the listing's MIC has no mapping in the Bloomberg exchCode table."},"bbg_ticker":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Per-listing Bloomberg ticker — `<local_ticker> <openfigi_exch_code> <yellow_key>`. Null when `openfigi_exch_code` is null."},"bbg_composite_ticker":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country-composite Bloomberg ticker — `<local_ticker> <country_composite_code> <yellow_key>`. Null when the listing's country has no composite mapping (only US/GB/DE/CH/NL/FR/BE/IT/ES/SE wired today)."}}},"Instrument":{"type":"object","required":["id","name","asset_class","is_active","identifiers","listings"],"properties":{"id":{"type":"integer"},"share_class_figi":{"anyOf":[{"type":"string","minLength":12,"maxLength":12},{"type":"null"}]},"name":{"type":"string"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"asset_class":{"$ref":"#/components/schemas/AssetClass"},"country_of_incorporation":{"anyOf":[{"type":"string","minLength":2,"maxLength":2},{"type":"null"}]},"currency_principal":{"anyOf":[{"type":"string","minLength":3,"maxLength":3},{"type":"null"}]},"is_active":{"type":"boolean"},"identifiers":{"type":"array","items":{"$ref":"#/components/schemas/Identifier"}},"listings":{"type":"array","items":{"$ref":"#/components/schemas/Listing"}}}},"V1Meta":{"type":"object","required":["fetched_at","request_id"],"properties":{"source":{"type":"string","description":"Where this response was assembled from. `\"may6\"` = Postgres origin (Layer 1). `\"twelve_data\"` (and similar) = fresh Layer 2 upstream call. `\"redis\"` = served from edge cache (regardless of which layer originally populated it)."},"source_attribution":{"type":"string","description":"Human-readable attribution string. On a cache hit, the original upstream attribution is preserved here so display attribution stays correct even when `source = \"redis\"`."},"fetched_at":{"type":"string","format":"date-time","description":"ISO-8601 timestamp when this response was assembled (NOT when the underlying data was last refreshed)."},"cache_hit":{"type":"boolean","description":"True only when the response was served from Redis. A Postgres origin read does NOT count as a cache hit."},"request_id":{"type":"string","description":"Per-request UUID — quote this in support tickets."}},"example":{"source":"may6","source_attribution":"May6 instrument graph (built from OpenFIGI + EDGAR + Twelve Data)","fetched_at":"2026-05-04T12:34:56.789Z","cache_hit":false,"request_id":"f1ada693-3f28-4a06-b79f-611f3724ecba"}},"V1Links":{"type":"object","required":["self"],"properties":{"self":{"type":"string"},"next":{"type":"string"},"prev":{"type":"string"},"documentation":{"type":"string"}}},"InstrumentEnvelope":{"type":"object","required":["data","meta","links"],"properties":{"data":{"$ref":"#/components/schemas/Instrument"},"meta":{"$ref":"#/components/schemas/V1Meta"},"links":{"$ref":"#/components/schemas/V1Links"}},"example":{"data":{"id":1,"share_class_figi":"BBG001S5N8V8","name":"APPLE INC","display_name":null,"asset_class":"equity_common","country_of_incorporation":"US","currency_principal":"USD","is_active":true,"identifiers":[{"type":"composite_figi","value":"BBG000B9XRY4","effective_from":"1900-01-01","effective_to":null},{"type":"share_class_figi","value":"BBG001S5N8V8","effective_from":"1900-01-01","effective_to":null},{"type":"isin","value":"US0378331005","effective_from":"1900-01-01","effective_to":null},{"type":"cik","value":"0000320193","effective_from":"1900-01-01","effective_to":null},{"type":"ticker","value":"AAPL","effective_from":"1900-01-01","effective_to":null}],"listings":[{"id":8,"exchange_mic":"XNAS","exchange_name":"Nasdaq Stock Market","country_code":"US","local_ticker":"AAPL","local_currency":"USD","figi":"BBG000B9Y5X2","composite_figi":"BBG000B9XRY4","is_primary_listing":true,"openfigi_exch_code":"UW","bbg_ticker":"AAPL UW Equity","bbg_composite_ticker":"AAPL US Equity"}]},"meta":{"source":"may6","source_attribution":"May6 instrument graph (built from OpenFIGI + EDGAR + Twelve Data)","fetched_at":"2026-05-04T12:34:56.789Z","cache_hit":false,"request_id":"f1ada693-3f28-4a06-b79f-611f3724ecba"},"links":{"self":"/api/v1/instruments/AAPL?identifiers=primary","documentation":"/api/v1/openapi.json"}}},"SearchMatchExchange":{"type":"object","required":["mic","currency"],"properties":{"mic":{"type":"string","minLength":4,"maxLength":4},"country_code":{"anyOf":[{"type":"string","minLength":2,"maxLength":2},{"type":"null"}]},"currency":{"type":"string","minLength":3,"maxLength":3}}},"SearchMatch":{"type":"object","description":"A single OpenFIGI match. Bloomberg-symbology display fields follow the same rules as `Listing` — see that schema's description for the full caveat. For composite-tape exchCodes (\"US\", \"GR\") `bbg_ticker` is null since they don't identify a single venue, but `bbg_composite_ticker` may still resolve from a known country.","required":["ticker","name","composite_figi","share_class_figi","exchange","security_type"],"properties":{"ticker":{"anyOf":[{"type":"string"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"composite_figi":{"anyOf":[{"type":"string","minLength":12,"maxLength":12},{"type":"null"}]},"share_class_figi":{"anyOf":[{"type":"string","minLength":12,"maxLength":12},{"type":"null"}]},"exchange":{"anyOf":[{"$ref":"#/components/schemas/SearchMatchExchange"},{"type":"null"}],"description":"Resolved venue metadata, or null when OpenFIGI's exchCode is a composite-tape code (e.g. \"US\") that doesn't map to a single MIC."},"security_type":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"OpenFIGI's `securityType` (e.g. \"Common Stock\", \"ETP\")."},"openfigi_exch_code":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"OpenFIGI's raw exchange code (per-listing: UW/UN/LN/GY/…; composite tape: US/GR/…)."},"bbg_ticker":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Per-listing Bloomberg ticker. Null when `openfigi_exch_code` is a composite-tape code or doesn't map to a venue MIC."},"bbg_composite_ticker":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Country-composite Bloomberg ticker derived from `exchange.country_code`. Null when no exchange/country mapping is available."}}},"InstrumentsSearch":{"type":"object","required":["query","limit","matches"],"properties":{"query":{"type":"string"},"limit":{"type":"integer"},"matches":{"type":"array","items":{"$ref":"#/components/schemas/SearchMatch"}}}},"InstrumentsSearchEnvelope":{"type":"object","required":["data","meta","links"],"properties":{"data":{"$ref":"#/components/schemas/InstrumentsSearch"},"meta":{"$ref":"#/components/schemas/V1Meta"},"links":{"$ref":"#/components/schemas/V1Links"}},"example":{"data":{"query":"apple","limit":25,"matches":[{"ticker":"AAPL","name":"APPLE INC","composite_figi":"BBG000B9XRY4","share_class_figi":"BBG001S5N8V8","exchange":{"mic":"XNAS","country_code":"US","currency":"USD"},"security_type":"Common Stock","openfigi_exch_code":"UW","bbg_ticker":"AAPL UW Equity","bbg_composite_ticker":"AAPL US Equity"},{"ticker":"0R2V","name":"APPLE INC","composite_figi":"BBG000B9XRY4","share_class_figi":"BBG001S5N8V8","exchange":{"mic":"XLON","country_code":"GB","currency":"GBP"},"security_type":"Common Stock","openfigi_exch_code":"LN","bbg_ticker":"0R2V LN Equity","bbg_composite_ticker":"0R2V LN Equity"}]},"meta":{"source":"openfigi","source_attribution":"Identifier mapping powered by OpenFIGI","fetched_at":"2026-05-04T12:34:56.789Z","cache_hit":false,"request_id":"abcdef01-2345-6789-abcd-ef0123456789"},"links":{"self":"/api/v1/instruments?q=apple&limit=25","documentation":"/api/v1/openapi.json"}}},"EodRow":{"type":"object","required":["date","close"],"properties":{"date":{"type":"string","format":"date"},"open":{"anyOf":[{"type":"number"},{"type":"null"}]},"high":{"anyOf":[{"type":"number"},{"type":"null"}]},"low":{"anyOf":[{"type":"number"},{"type":"null"}]},"close":{"anyOf":[{"type":"number"},{"type":"null"}]},"volume":{"anyOf":[{"type":"number"},{"type":"null"}]}}},"PricesEod":{"type":"object","required":["ticker","exchange","currency","type","rows"],"properties":{"ticker":{"type":"string"},"exchange":{"type":"string","description":"ISO 10383 MIC code of the resolved listing.","minLength":4,"maxLength":4},"currency":{"type":"string","description":"ISO 4217 currency code of the price values.","minLength":3,"maxLength":3},"type":{"type":"string","enum":["eod"]},"rows":{"type":"array","items":{"$ref":"#/components/schemas/EodRow"}}}},"PricesEodEnvelope":{"type":"object","required":["data","meta","links"],"properties":{"data":{"$ref":"#/components/schemas/PricesEod"},"meta":{"$ref":"#/components/schemas/V1Meta"},"links":{"$ref":"#/components/schemas/V1Links"}},"example":{"data":{"ticker":"AAPL","exchange":"XNAS","currency":"USD","type":"eod","rows":[{"date":"2025-12-30","open":252.55,"high":253.5,"low":250.7,"close":252.2,"volume":35200000},{"date":"2025-12-31","open":252.7,"high":254.1,"low":251.6,"close":253.55,"volume":28100000}]},"meta":{"source":"may6","source_attribution":"Daily EOD prices via Twelve Data","fetched_at":"2026-05-04T12:34:56.789Z","cache_hit":false,"request_id":"9f1d2c3b-4a5e-6f78-9a01-2b3c4d5e6f70"},"links":{"self":"/api/v1/prices/AAPL/eod?from=2025-12-01&to=2025-12-31","documentation":"/api/v1/openapi.json"}}},"FundamentalRow":{"type":"object","required":["concept","period_type","period_end_date","value"],"properties":{"concept":{"type":"string","description":"XBRL concept name (e.g. 'Revenues', 'NetIncomeLoss')."},"fiscal_year":{"anyOf":[{"type":"integer"},{"type":"null"}]},"fiscal_period":{"anyOf":[{"type":"string","enum":["FY","Q1","Q2","Q3","Q4"]},{"type":"null"}]},"period_type":{"type":"string","enum":["annual","quarterly","instant"]},"period_start_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]},"period_end_date":{"type":"string","format":"date"},"value":{"type":"number"},"unit":{"anyOf":[{"type":"string"},{"type":"null"}]},"filed":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]}}},"Fundamentals":{"type":"object","required":["ticker","cik","rows"],"properties":{"ticker":{"type":"string"},"cik":{"type":"string","description":"10-digit zero-padded SEC Central Index Key."},"rows":{"type":"array","items":{"$ref":"#/components/schemas/FundamentalRow"}}}},"FundamentalsEnvelope":{"type":"object","required":["data","meta","links"],"properties":{"data":{"$ref":"#/components/schemas/Fundamentals"},"meta":{"$ref":"#/components/schemas/V1Meta"},"links":{"$ref":"#/components/schemas/V1Links"}},"example":{"data":{"ticker":"AAPL","cik":"0000320193","rows":[{"concept":"us-gaap:Revenues","fiscal_year":2024,"fiscal_period":"FY","period_type":"annual","period_start_date":"2023-10-01","period_end_date":"2024-09-28","value":391035000000,"unit":"USD","filed":"2024-11-01"},{"concept":"us-gaap:Revenues","fiscal_year":2023,"fiscal_period":"FY","period_type":"annual","period_start_date":"2022-10-02","period_end_date":"2023-09-30","value":383285000000,"unit":"USD","filed":"2023-11-03"}]},"meta":{"source":"may6","source_attribution":"Fundamentals from SEC EDGAR XBRL filings","fetched_at":"2026-05-04T12:34:56.789Z","cache_hit":false,"request_id":"abcdef01-2345-6789-abcd-ef0123456789"},"links":{"self":"/api/v1/fundamentals/AAPL?concept=us-gaap:Revenues","documentation":"/api/v1/openapi.json"}}},"ErrorCode":{"type":"string","enum":["not_found","invalid_request","auth_missing","auth_invalid","rate_limited","paywall","upstream_error","schema_violation","not_implemented","internal_error"]},"ErrorEnvelope":{"type":"object","required":["error","meta","links"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true},"retry_after_seconds":{"type":"integer","minimum":0}}},"meta":{"$ref":"#/components/schemas/V1Meta"},"links":{"type":"object","required":["self"],"properties":{"self":{"type":"string"},"documentation":{"type":"string"}}}},"example":{"error":{"code":"not_found","message":"No instrument found with ticker \"NONEXISTENT\""},"meta":{"fetched_at":"2026-05-04T12:34:56.789Z","request_id":"6f883e05-e5c5-4751-a522-4fbf4f22ecd7"},"links":{"self":"/api/v1/instruments/NONEXISTENT","documentation":"/api/v1/openapi.json"}}}}}}