{"id":"b4ade6d3-ff9b-4524-aa31-82a994646bf3","entityType":"agent","slug":"clawhub-thesentitrader-sentisense","name":"sentisense","canonicalUrl":"https://www.xpersona.co/agent/clawhub-thesentitrader-sentisense","canonicalPath":"/agent/clawhub-thesentitrader-sentisense","generatedAt":"2026-10-09T13:58:06.138Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-09T05:52:46.030Z","emptyReason":null},"description":"US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers every endpoint. Use for stock sentiment API, stock market API, stock rating API, stock letter grade, insider trading data, congress stock trades, 13F holdings, options flow, earnings calendar, stock price API, market data for AI agents. Read-only. No trading, no purchases, no write operations, no wallet access. Skill: sentisense Owner: thesentitrader Summary: US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers ev","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 4.2K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s171aan38r2dn7ew5hddyscf1983x1h9:sentisense","sourceUrl":"https://clawhub.ai/thesentitrader/sentisense","homepage":"https://clawhub.ai/thesentitrader/skills/sentisense","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/thesentitrader/sentisense","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/thesentitrader/skills/sentisense","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":44,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades,"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T05:52:46.030Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T05:52:46.030Z","emptyReason":null},"stars":null,"forks":null,"downloads":4200,"packageName":null,"latestVersion":"2.21.2","tractionLabel":"4.2K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T05:52:46.030Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T05:52:46.030Z","lastCrawledAt":"2026-10-09T05:52:46.030Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T05:52:46.030Z","lastVerifiedAt":null,"highlights":[{"version":"2.21.2","createdAt":"2026-10-04T03:50:45.985Z","changelog":"The ai-summary deep report 429 now documents its message field, which says when the monthly allowance resets and links PRO, and notes the response carries no Retry-After header.","fileCount":3,"zipByteSize":73479},{"version":"2.21.1","createdAt":"2026-10-01T23:12:15.426Z","changelog":"Free earnings preview: guidance flag now also reflects the earnings call, new optional guidanceSource field, topic fields described as topic labels.","fileCount":3,"zipByteSize":73592},{"version":"2.21.0","createdAt":"2026-10-01T18:44:56.760Z","changelog":"Documents free-tier preview shapes and how to read a partial slice, the one-week free earnings calendar, the $100,000 premium floor for the options interest score, how limit behaves on documents/source, the trailing-ratio valuation snapshot, omitted null fields, and the sentiment leaderboard and movers trackers.","fileCount":3,"zipByteSize":73590},{"version":"2.20.1","createdAt":"2026-10-01T03:12:54.573Z","changelog":"Options section: ETF coverage, null handling, Radar score eligibility, refresh timing, history depth (2+ years from July 2024), the Radar includes ETFs, and preview and error shapes.","fileCount":3,"zipByteSize":69077},{"version":"2.20.0","createdAt":"2026-09-30T17:50:14.164Z","changelog":"Documents the preIpoFiling marker on pre-IPO quarters in fundamentals history, adds week=last to the earnings calendar, and updates options stock coverage to about 1,040 names.","fileCount":3,"zipByteSize":68392},{"version":"2.19.0","createdAt":"2026-09-29T06:51:05.266Z","changelog":"Names the Pro Max and Data License plan rates, documents the ticker_is_index error, and clarifies that an empty bull or bear side in story detail means no case, never null.","fileCount":3,"zipByteSize":68291},{"version":"2.18.0","createdAt":"2026-09-24T16:43:47.118Z","changelog":"Options: documents the evening refresh, the open-interest follow-up fields on unusual contracts (oiPrior, oiNext, oiChange, oiConfirmation, oiObservedAt, oiVintage) and the session highlights on /options/overview. Metrics: maxDataPoints on the time series returns at most N original points evenly spaced back from the latest; distribution/{metricType} is documented as a percentage share.","fileCount":3,"zipByteSize":67783},{"version":"2.17.1","createdAt":"2026-09-23T15:57:40.186Z","changelog":"Documents the bull, bear and directional counts on every SentiSense Score point: how to read direction from them instead of mention volume, and that the last daily point is the current day so far.","fileCount":3,"zipByteSize":66885}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s171aan38r2dn7ew5hddyscf1983x1h9:sentisense","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T13:58:06.135Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-thesentitrader-sentisense/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-09T05:52:46.030Z","emptyReason":null},"readme":"Skill: sentisense\n\nOwner: thesentitrader\n\nSummary: US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers every endpoint. Use for stock sentiment API, stock market API, stock rating API, stock letter grade, insider trading data, congress stock trades, 13F holdings, options flow, earnings calendar, stock price API, market data for AI agents. Read-only. No trading, no purchases, no write operations, no wallet access.\n\nTags: latest:2.21.2\n\nVersion history:\n\nv2.21.2 | 2026-10-04T03:50:45.985Z | user\n\nThe ai-summary deep report 429 now documents its message field, which says when the monthly allowance resets and links PRO, and notes the response carries no Retry-After header.\n\nv2.21.1 | 2026-10-01T23:12:15.426Z | user\n\nFree earnings preview: guidance flag now also reflects the earnings call, new optional guidanceSource field, topic fields described as topic labels.\n\nv2.21.0 | 2026-10-01T18:44:56.760Z | user\n\nDocuments free-tier preview shapes and how to read a partial slice, the one-week free earnings calendar, the $100,000 premium floor for the options interest score, how limit behaves on documents/source, the trailing-ratio valuation snapshot, omitted null fields, and the sentiment leaderboard and movers trackers.\n\nv2.20.1 | 2026-10-01T03:12:54.573Z | user\n\nOptions section: ETF coverage, null handling, Radar score eligibility, refresh timing, history depth (2+ years from July 2024), the Radar includes ETFs, and preview and error shapes.\n\nv2.20.0 | 2026-09-30T17:50:14.164Z | user\n\nDocuments the preIpoFiling marker on pre-IPO quarters in fundamentals history, adds week=last to the earnings calendar, and updates options stock coverage to about 1,040 names.\n\nv2.19.0 | 2026-09-29T06:51:05.266Z | user\n\nNames the Pro Max and Data License plan rates, documents the ticker_is_index error, and clarifies that an empty bull or bear side in story detail means no case, never null.\n\nv2.18.0 | 2026-09-24T16:43:47.118Z | user\n\nOptions: documents the evening refresh, the open-interest follow-up fields on unusual contracts (oiPrior, oiNext, oiChange, oiConfirmation, oiObservedAt, oiVintage) and the session highlights on /options/overview. Metrics: maxDataPoints on the time series returns at most N original points evenly spaced back from the latest; distribution/{metricType} is documented as a percentage share.\n\nv2.17.1 | 2026-09-23T15:57:40.186Z | user\n\nDocuments the bull, bear and directional counts on every SentiSense Score point: how to read direction from them instead of mention volume, and that the last daily point is the current day so far.\n\nv2.17.0 | 2026-09-21T15:42:18.642Z | user\n\nFundamentals rows can carry an epsBasisRepair marker: for a short list of named issuers whose provider restated share counts for a split but left older EPS on the pre-split basis, the EPS is restated and the row names the fields, multiplier and split dates; null means no repair was applied. Chart bars now carry adjusted: true, with the price basis per range spelled out.\n\nv2.16.0 | 2026-09-20T07:41:15.517Z | user\n\nDocuments the story search endpoint: one call searches curated stories by ticker or by theme over up to 30 days, reading entities in the query first and leftover words as keywords, with its parameters and response shape. Also states the document search lookback as 1 to 14 days.\n\nv2.15.0 | 2026-09-19T02:01:31.272Z | user\n\nSentiSense Rating methodology 2026.09-v5: small_market_cap is now a graded log-scale charge (0 points at 50B+, 10 at 10B, 12 at 2B and below, keeping sub-10B out of the A band), plus a technicals volatility/momentum rebalance.\n\nv2.14.0 | 2026-09-18T08:03:37.057Z | user\n\nSentiSense Rating public Beta: betaNotice field, twelve risk conditions including rich_valuation, durability in fundamentals, methodology 2026.09-v4. Also carries two already-committed fixes since 2.13.0: the earnings share-count fields (weighted-average basic/diluted, sharesOutstanding deprecated) and two-sided confirmed semantics on the earnings calendar.\n\nv2.13.0 | 2026-09-14T08:55:48.489Z | user\n\nDocuments GET /api/v1/stocks/{ticker}/graph, the typed company knowledge graph behind the flat /entities list: params, slug-keyed response shape, edge vocabulary, and the 404 contrast against /entities. Metrics and documents paths document urlSlug as the only public handle.\n\nv2.12.22 | 2026-09-11T22:42:12.880Z | user\n\nMetrics: the workflow examples now use the SentiSense Score series (metric/sentisense) for bullish-or-bearish reads, with the reason stated once; the unweighted sentiment series stays documented as raw tone. Adds the stock-ontology skill to the collection.\n\nv2.12.21 | 2026-09-11T05:59:17.059Z | user\n\nDocuments afterHoursReactionPct on the ranked earnings rows: the after-hours reading that stands in on the evening a company reports after the close, before the reacting session opens. Corrects the extendedHours contract on the quote endpoints, which previously claimed the field is present only between 16:00 and 20:00 ET. The last after-hours print is now carried overnight and through the weekend until the next pre-market session opens, so session stays post while it is held.\n\nv2.12.20 | 2026-09-10T01:13:25.285Z | user\n\nAnalyst Ratings: consensus/history (daily observations of the target band and rating counts, PRO full, FREE last 30 days) and called-it (recorded large moves with the firms that had revised targets beforehand)\n\nv2.12.19 | 2026-09-10T01:09:47.843Z | user\n\nKPI coverage note corrected to 900+ tickers; handoff to the new company-kpi-tracker skill; analyst consensus history and who-called-it endpoints; earnings ranked, statistics and reactions.\n\nv2.12.18 | 2026-09-08T07:41:02.920Z | user\n\nCorrects the Rating metric series: the stored value is the daily score, not the percentile, and notes that chart volume is adjusted on the same basis as price; removes the npx execution path and declares permissions.\n\nv2.12.17 | 2026-09-06T05:17:38.436Z | user\n\nDocuments the six expected-move fields now on the options daily aggregate: expectedMove1d/5d/20d, a 90 percent range whose scale is calibrated on SentiSense's own stored option history, and expectedMove1s1d/5d/20d, the one-sigma convention. Both families are fractions of price over 1, 5 and 20 trading sessions. The free headline preview of the options dossier now carries expectedMove1d, and the earnings reactions section names the field to pair it with.\n\nv2.12.16 | 2026-09-05T04:00:16.033Z | user\n\nAdds the app_review_count and app_rating metric series to the metrics reference (Free tier, products with a tracked iOS app), notes that from 2026-09-05 the root mentions series no longer includes App Store reviews, and documents the story provenance fields storySource, isLive and timeline.\n\nv2.12.15 | 2026-09-04T22:48:51.710Z | user\n\nPer-ticker 404 bodies now say why: entity_not_found (with up to three suggestions) for a symbol SentiSense does not track, no_coverage for a tracked symbol with no analyst or sentiment record. institutional/holders/{ticker} no longer requires reportDate; omit it and the response resolves the latest settled quarter and echoes it. stocks/{ticker}/quote on an ETF returns the ticker_is_etf error with a seeInstead pointer to the ETF quote endpoint. Consensus counts documented as a broker survey panel revised in batches through the month.\n\nv2.12.14 | 2026-09-04T02:36:00.646Z | user\n\nAnalyst ratings: ratingBuckets on coverage (whole-book Buy/Hold/Sell counts, identical on free and PRO), grades stored in one canonical spelling per rating, initiations never carry a prior grade, actionType agrees with the grade pair, corrected refresh-cadence note, CLI pinned to sentisense 0.51.0.\n\nv2.12.13 | 2026-09-02T07:07:43.953Z | user\n\nDocuments the new market-heatmap tracker (GET /api/v1/trackers/market-heatmap?scope=sp500|nasdaq100|popular): every row on every tier, the four proprietary overlays PRO with meta.previewWithheld naming what was withheld, totalCount on every tracker response, 400 invalid_scope.\n\nv2.12.12 | 2026-09-02T02:59:12.252Z | user\n\nAnalyst consensus: updatedAt is now a UTC instant with a Z suffix (it was a naive US/Eastern wall clock), and updatedAtEpoch (epoch seconds) is added alongside it. Both fields are present on the free-tier preview.\n\nv2.12.11 | 2026-09-01T23:05:03.619Z | user\n\nAnalyst coverage: a firm that rated a stock without publishing a price target now appears as a rating-only row (noteCount 0, firmRating set) instead of being missing, and the response carries ratingOnlyFirmCount so firmCount can be read correctly. Firm ratings now match across vendor spellings of the same firm.\n\nv2.12.10 | 2026-09-01T03:57:19.746Z | user\n\nRestores the three analyst identity endpoints: who covers a ticker and what each firm most recently said (/analyst/{ticker}/coverage), one analyst's profile and coverage book (/analyst/people/{slug}), and their full price-target history with a source URL on every call (/analyst/people/{slug}/calls). Every field, param cap and error code re-verified against the live API. Documents four traps: totalCount is present only on a truncated free response, latestNote.analyst is an object rather than a string, firmRating is often null, and about half of price-target notes name no individual analyst with the share varying from 11% to 64% by ticker. Also adds the coverage and analyst views to the get_analyst_ratings MCP tool.\n\nv2.12.9 | 2026-09-01T02:18:32.328Z | user\n\nSupersedes 2.12.8: removes three endpoint sections that are not serving yet (they returned 404). Keeps the analyst refresh-timing correction, the actionType-is-provider-supplied caveat, and the corrected daily rating-action volume.\n\nv2.12.8 | 2026-09-01T02:17:10.543Z | user\n\nCorrect the analyst refresh-timing docs (the sweep is not pre-market anchored and updatedAt is stamped at sweep end), document that actionType is provider-supplied and not cross-checked against fromGrade/toGrade, and fix the daily rating-action volume figure to the measured 70-110.\n\nv2.12.7 | 2026-08-23T23:45:36.069Z | user\n\nDocs accuracy: FREE holders preview field exception documented; CLI pin bumped to 0.47.1 (health output no longer echoes key material)\n\nv2.12.6 | 2026-08-23T00:12:54.086Z | user\n\nFix the ETF screener worked example, which matched zero funds: expense ratio is percent-scale and the Score threshold sat above the universe maximum. Document GET /politicians/directory. Correct the access label on the per-stock sentiment endpoint, which answers without a key.\n\nv2.12.5 | 2026-08-22T22:21:30.100Z | user\n\nRestores the full Earnings Analysis section to this listing (a build had omitted it here) and documents the new earnings reactions endpoint: the last twelve close-to-close earnings moves per ticker, the AMC and BMO session rule, and how that timing vocabulary maps to the earnings calendar.\n\nv2.12.4 | 2026-08-21T01:13:42.444Z | user\n\nCLI one-liners pin 0.46.0.\n\nv2.12.3 | 2026-08-21T00:33:38.441Z | user\n\nInsider activity docs: sells exclude tax withholding server-side; per-row trades endpoint unchanged.\n\nv2.12.2 | 2026-08-20T21:54:02.330Z | user\n\nInsider section: exclude code F tax withholding from sell tallies and sanity-check reported dollar values.\n\nv2.12.1 | 2026-08-20T09:13:27.055Z | user\n\nPin the CLI to an immutable published version; clarify local key storage is optional and removable\n\nv2.12.0 | 2026-08-20T09:01:30.397Z | user\n\nPer-endpoint CLI equivalents, sentiment endpoint wrapper correction, market sentiment endpoints documented, screener validation docs\n\nv2.11.0 | 2026-08-20T07:01:59.030Z | user\n\nAdd optional CLI quickstart (npx sentisense) with caller identity, and document screener plan validation (unknown fields now 400 with guidance)\n\nv2.10.0 | 2026-08-15T21:30:00.156Z | user\n\nCorrect the Market Mood history note: the options flow signal is backfilled, so optionsFlow is never null on older rows. Document the delisting fields on the price response. Add client identification guidance.\n\nv2.9.0 | 2026-08-13T20:53:48.810Z | user\n\nIndexes API documented; prices stated as 15-minute delayed with the new priceAsOf freshness field; filterHours is the real stories lookback; congressional recent-trades paging and totalCount; depth=basic now returns sections so branch on reportType\n\nv2.8.3 | 2026-08-03T03:50:33.317Z | user\n\nDescription now carries the trigger phrases callers actually search for.\n\nv2.8.2 | 2026-08-03T00:57:43.258Z | user\n\nCorrects the sentiment tracker descriptions: the leaderboard and movers rank tone, not the SentiSense Score.\n\nv2.8.1 | 2026-08-02T22:17:48.729Z | user\n\nDocuments the units on the per-stock sentiment response: mentionShare is a whole-number percent that sums to 100 across sources, while socialDominance is a fraction.\n\nv2.8.0 | 2026-08-02T19:41:28.048Z | user\n\nAdds the per-stock sentiment endpoint (SentiSense Score, 30-day direction, per-source tone, story drivers), the sector and breadth sentiment endpoints, deep chart timeframes 5Y/10Y/MAX, and reporting-currency semantics on fundamentals.\n\nv2.7.2 | 2026-07-24T16:57:55.752Z | user\n\nAdd Entities API: entity search and popular endpoints, urlSlug support in metrics\n\nv2.7.1 | 2026-07-24T16:57:04.050Z | user\n\nAdd Entities API: entity search and popular endpoints, urlSlug support in metrics\n\nv2.7.0 | 2026-07-24T16:47:47.469Z | user\n\nAdd Entities API: entity search and popular endpoints, urlSlug support in metrics\n\nv2.6.0 | 2026-07-24T05:25:54.650Z | user\n\nScore wording refresh; drop the unpopulated market-summary fields; add fundamentals history and the MCP connector reference.\n\nv2.5.0 | 2026-07-19T21:28:10.304Z | user\n\nAdded the Options Intelligence API (market radar, per-stock dossier, and history) with IV rank, put/call percentile, 25-delta skew, open-interest walls, max pain, and unusual contracts, each ranked against the stock's own history; documented ETF options coverage; corrected 6 fundamentals/short-interest/float endpoints that require a ticker parameter; fixed Python examples that crashed on copy-paste; clarified free vs PRO gating; institutional flows reportDate is now optional.\n\nv2.4.0 | 2026-07-19T07:22:29.973Z | user\n\nAdd Options Intelligence API: end-of-day IV rank, put/call percentile, 25-delta skew, open-interest walls, max pain, and unusual-by-volume contracts via /options/overview and /stocks/{ticker}/options/summary and /history, with the FREE/PRO tiering documented. Plus assorted docs-accuracy fixes.\n\nv2.3.3 | 2026-07-18T07:25:21.281Z | user\n\nFix Python examples to use .data attribute access; the SDK auto-unwraps the preview envelope.\n\nArchive index:\n\nArchive v2.21.2: 3 files, 73479 bytes\n\nFiles: skill-card.md (1956b), SKILL.md (206464b), _meta.json (130b)\n\nFile v2.21.2:SKILL.md\n\n---\nname: sentisense\ndescription: \"US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers every endpoint. Use for stock sentiment API, stock market API, stock rating API, stock letter grade, insider trading data, congress stock trades, 13F holdings, options flow, earnings calendar, stock price API, market data for AI agents. Read-only. No trading, no purchases, no write operations, no wallet access.\"\nhomepage: https://sentisense.ai\nrequires:\n  env:\n    - SENTISENSE_API_KEY\nprimaryEnv: SENTISENSE_API_KEY\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - SENTISENSE_API_KEY\n    primaryEnv: SENTISENSE_API_KEY\n---\n\n# SentiSense API - Skill File for AI Agents\n\n> **SentiSense** is a read-only financial intelligence API: stock prices, insider/politician trading, institutional flows, AI insights, and news sentiment. No trading, no purchases, no write operations. Free tier available.\n\n**Base URL:** `https://app.sentisense.ai`\n**Website:** https://sentisense.ai\n**ClawHub Skill:** [clawhub.ai/TheSentiTrader/sentisense](https://clawhub.ai/TheSentiTrader/sentisense)\n**API Docs:** https://sentisense.ai/docs/api/\n**Authentication:** API key via `X-SentiSense-API-Key` header. Get a free key at https://app.sentisense.ai/get-api-key\n**SDKs (optional):** [Python](https://github.com/SentiSenseApp/sentisense) | [Node.js](https://github.com/SentiSenseApp/sentisense-node) -- source on GitHub. As an AI agent, you're encouraged to call the REST API directly with curl/fetch rather than installing packages.\n\n---\n\n## Use & Disclaimer\n\nThis skill is an **educational data interface** to SentiSense's read-only Data API. Output is informational only. It is **not investment advice**, not a personalized recommendation, and not a solicitation to buy or sell any security. The user is responsible for their own decisions. Use of the API and this skill is subject to the [API Terms of Service](https://sentisense.ai/agreement/API-Terms-of-Service.pdf) and [Terms of Service](https://sentisense.ai/agreement/Terms-of-Service.pdf).\n\n---\n\n## Authentication\n\n```bash\n# Include API key in header\ncurl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\\n  \"https://app.sentisense.ai/api/v1/...\"\n```\n\n**Identify your client.** Send a `User-Agent` naming your agent runtime and this skill, for\nexample `OpenClaw/1.4 (sentisense)` or `ClaudeCode/2.1 (sentisense)`. Substitute your own runtime and\nversion if neither matches. You can also volunteer what your agent is called by adding an\n`agent/<your-agent-name>` token inside the same parentheses, as in\n`OpenClaw/1.4 (sentisense; agent/research-desk)`. All of it is optional, and it is what tells\nus this skill has real integrations behind it, so it gets prioritized and you get notice before it\nchanges.\n\n```python\nimport os\nfrom sentisense import SentiSenseClient\nclient = SentiSenseClient(api_key=os.environ[\"SENTISENSE_API_KEY\"])\n```\n\nAll API endpoints require an API key. Get one free at https://app.sentisense.ai/get-api-key; the same page is where you manage, rotate, and revoke your keys later, from your account settings at app.sentisense.ai.\n\n## Permissions\n\n- Network: HTTPS to app.sentisense.ai only.\n- Credentials: SENTISENSE_API_KEY from the environment.\n- Shell: none required.\n- Files: none.\n\n### Command-line client\n\nThe REST recipe in this file is the primary path. A maintained command-line client is available as the separate `sentisense-cli` skill for hosts that prefer one.\n\n### Access Tiers\n\n| Badge | Meaning |\n|-------|---------|\n| **Public** | Available on all tiers (Free and PRO) |\n| **Public (preview)** | Free gets limited preview; PRO gets full data |\n| **Quota-gated** | Consumes monthly quota (Free: limited, PRO: unlimited) |\n| **Discovery (no quota cost)** | API key required (identity/abuse tracking), but the call does not burn your monthly quota. Rate-limit-per-minute still applies. Used for lightweight metadata endpoints like `/stocks/with-kpis` and `/stocks/{ticker}/kpis/types`. |\n| **PRO only** | Requires PRO subscription |\n\n### Rate Limits\n\n| Tier | Requests/Month | Rate |\n|------|----------------|------|\n| Free | 1,000 | 30 requests/minute |\n| PRO ($15/mo) | Unlimited | 300 requests/minute |\n| Pro Max | Unlimited | 1,500 requests/minute |\n| Data License (Essentials, Premium) | Unlimited | 2,000 requests/minute |\n\nPro Max and the Data License plans include every PRO feature; the API reports their tier as `PRO`.\n\n### Ticker Symbols\n\nEndpoints that take a `{ticker}` path parameter accept the canonical primary ticker for each company. For dual-class share companies, the API also accepts the secondary class as an alias and resolves it server-side, so you can pass whichever ticker your data source provides.\n\n| You pass | Resolves to | Reason |\n|----------|-------------|--------|\n| `GOOG` | `GOOGL` | Alphabet Class C resolves to Class A |\n| `BRK.A`, `BRK-A`, `BRKA` | `BRK.B` | Berkshire Class A resolves to Class B |\n| `BRK-B`, `BRKB` | `BRK.B` | Punctuation variants normalized |\n\nAliasing applies to research endpoints (analyst, KPIs, insights, insider, institutional holders, politicians filings, options). Quote and chart endpoints leave the ticker as-is, since market-data providers handle their own symbology. Tickers are case-insensitive. News Corp (`NWSA`/`NWS`) and Fox (`FOXA`/`FOX`) are NOT aliased to each other (each class is tracked separately).\n\n---\n\n## What You Can Build\n\n### Smart Money Tracker\nCross-reference insider trading, institutional flows, and politician trades to follow where the smart money is moving. High-conviction signals come from convergence across all three.\n- `GET /api/v1/insider/activity` for market-wide insider buying/selling\n- `GET /api/v1/institutional/flows` for quarterly institutional positioning (optional `reportDate`; omit for the latest quarter)\n- `GET /api/v1/politicians/activity` for congressional STOCK Act trades\n- `GET /api/v1/insights/stock/{ticker}` for AI signals that combine these data sources\n\n### Sentiment-Driven Watchlist\nAlert when sentiment shifts for your stocks. Track news volume, social mentions, and baseline deviations.\n- `GET /api/v2/metrics/entity/{ticker}/metric/sentisense` for the SentiSense Score time series (prefer it over `sentiment`; see the metric notes below)\n- `GET /api/v2/metrics/entity/{ticker}/baselines/sentiment` for anomaly detection against historical and peer baselines\n- `GET /api/v1/documents/ticker/{ticker}` for the underlying news and social posts driving the shift\n\n### Congressional Trade Monitor\nTrack what Congress is buying before it moves. Filter by party, chamber, or individual politician. Check if corporate insiders agree.\n- `GET /api/v1/politicians/activity` for recent congressional trades across all members\n- `GET /api/v1/politicians/member/{slug}` for individual politician profiles and trade history\n- `GET /api/v1/insider/trades/{ticker}` to cross-reference with corporate insider activity on the same stock\n\n### AI Research Assistant\nGenerate stock research reports by combining multiple data signals into a single analysis.\n- `GET /api/v1/stocks/{ticker}/ai-summary?depth=deep` for the full AI analysis report\n- `GET /api/v1/insights/stock/{ticker}` for AI-generated stock signals\n- `GET /api/v1/stocks/fundamentals?ticker={ticker}` for a single period of financial statement data\n- `GET /api/v1/stocks/fundamentals/history?ticker={ticker}&timeframe=annual&limit=10` for multi-year revenue, margin, and free-cash-flow trend to support valuation work\n- `GET /api/v1/documents/ticker/{ticker}` for recent news context\n\n### Earnings Calendar Monitor\nPosition ahead of earnings instead of reacting to them. Pull the forward calendar, intersect it with a watchlist, and pre-load sentiment and smart-money context for the companies reporting soon.\n- `GET /api/v1/calendar/earnings?week=next` for who reports next week (or `?from=&to=` for a custom window)\n- `GET /api/v1/calendar/earnings?ticker={ticker}` for a single name's next report date and consensus EPS (on a FREE key this searches only the current Monday-to-Sunday week; see the Calendar section)\n- `GET /api/v2/metrics/entity/{ticker}/metric/sentisense` to gauge positioning into the print\n- `GET /api/v1/insider/trades/{ticker}` to see if insiders moved ahead of the date\n\n### Market Dashboard\nMarket overview combining prices, sentiment, and top signals.\n- `GET /api/v1/stocks/market-status` to check if the market is open\n- `GET /api/v1/market-summary` for AI-generated market headline and analysis\n- `GET /api/v1/insights/market` for the top market-moving signals right now\n- `GET /api/v1/stocks/prices?tickers=SPY,QQQ,IWM,DIA` for index tracking\n\n### Cross-Signal Stock Screener\nFilter the whole tracked universe on the SentiSense Score and attention in the same query as analyst consensus, technicals and price. The differentiated screens are the disagreements: crowd bullish where the street is not, price below its 200-day while the Score is rising.\n- `GET /api/v1/screener/fields` once at startup for the filterable field catalog (stock and ETF), then build filters from it\n- `GET /api/v1/screener/screens` for 28 curated screens, each with a plan you can execute as-is\n- `POST /api/v1/screener/execute` to run a plan against the stock universe (or a `tickers` watchlist)\n- `POST /api/v1/screener/etfs/execute` for the same against the ETF universe\n\n### Market Sentiment Structure\nWhich way the market's tone leans, and how widely it's shared. Daily snapshots.\n- `GET /api/v1/sentiment/sectors` for the 11 GICS sectors vs the market's own tone (`consensusVsMarket` + \"Hotter/Cooler than market\" labels; market-relative because news tone skews positive as a genre)\n- `GET /api/v1/sentiment/breadth` for the bullish/neutral/bearish share of ~1,000 covered stocks (the sentiment advance/decline line; `netBreadth` in points, stock- and mention-weighted)\n- `GET /api/v1/trackers/sentiment-leaderboard` for the most bullish and bearish stocks ranked by their 30-day SentiSense Score, with a minimum-mention confidence floor (each row also carries the 7-day Score and raw tone polarity, which do not set the order)\n- `GET /api/v1/trackers/sentiment-movers` for the biggest SentiSense Score shifts, improving and deteriorating, ranked by the 7-day average Score minus the 30-day average (a row with no Score change falls back to its tone change)\n\n---\n\n## Agent Tips\n\n### Workflow Pattern\n1. Call `GET /api/v1/stocks/market-status` first to check if the market is open\n2. Call `GET /api/v1/institutional/quarters` before the institutional endpoints that need a `reportDate` to get valid values (`/flows` does not need one; omit it for the latest quarter)\n3. All PRO-gated endpoints return `{isPreview, previewReason, data}`. Always access `response[\"data\"]` (or `response.data`). On a preview (FREE) list response a `totalCount` field is also present: the number of items in the full PRO dataset, so you can show \"showing N of totalCount\". **A preview is a slice, not the window.** When `isPreview` is `true` and `totalCount` is larger than the rows returned, those rows are the newest or top N only: label them (\"newest 5 of 61 trades, free preview\") and never infer absence from them. No \"zero insider buying\", \"no congressional activity\", \"not scheduled\" or \"no unusual contracts\" from a slice\n4. Use `lookbackDays` (1-365) on insider and politician endpoints to control the time window\n\n### Common Mistakes\n- **Do NOT hardcode `reportDate`** for institutional endpoints. When you pass one, fetch it from `/quarters` first; quarters change as new SEC filings come in. (`/flows` does not require one: omit it for the latest quarter, or pass one for a specific quarter.)\n- **Do NOT iterate the response directly.** Unwrap `response[\"data\"]` first. All PRO-gated endpoints use the `{isPreview, previewReason, data}` wrapper, and some Free ones do too (`/stocks/{ticker}/sentiment` wraps on every tier), so let each endpoint's own Response line decide rather than inferring the shape from the tier\n- **Do NOT use `/api/v1/entity-metrics/*`** for metrics. These are RETIRED (return 410 Gone). Use `/api/v2/metrics/` instead\n- **The `source` parameter is case-insensitive.** `news`, `NEWS`, `News` all work\n\n### Endpoints That Do NOT Exist\nDo not hallucinate these. They are not part of the SentiSense API:\n- `/api/v1/options/flow` or `/api/v1/dark-pool`: these exact paths do not exist. For end-of-day options analytics (IV rank, put/call percentile, 25-delta skew, open-interest walls, max pain, unusual-by-volume contracts) use the Options Intelligence endpoints instead: `/api/v1/options/overview` and `/api/v1/stocks/{ticker}/options/summary`. We do not attribute tick-level order flow (no buy/sell aggressor tagging) and we have no dark-pool data\n- `/api/v1/earnings` as a root: the only paths under it are `/api/v1/earnings/recent` (which covered companies already reported in a recent window), `/api/v1/earnings/ranked` (the importance-ranked view of recent reporters and upcoming reports) and `/api/v1/earnings/statistics` (market-wide beat rate joined to what the market did next). For the forward calendar use `/api/v1/calendar/earnings`; for a company's per-quarter earnings analysis report use `/api/v1/stocks/{ticker}/earnings-summaries`; for reported financials use `/api/v1/stocks/fundamentals` (single period) or `/api/v1/stocks/fundamentals/history` (multi-period trend, up to 40 quarters or 20 years)\n- `/api/v1/alerts` or `/api/v1/notifications`: alerts are user-facing only, not available via API\n- `/api/v1/chat` or `/api/v1/ask`: the AI chat is not accessible via API\n- `/api/v2/sentiment`: the correct path is `/api/v2/metrics/entity/{id}/metric/sentiment`\n- `/api/v1/congress` or `/api/v1/congressional`: the correct path is `/api/v1/politicians`\n- `/api/v1/screener/plan` and `/api/v1/screener/plans`: there is no natural-language screen planner and no saved-screen store on the public API. Build the plan object yourself and post it to `/api/v1/screener/execute`, or execute one of the curated plans from `/api/v1/screener/screens`\n\n---\n\n## Stocks API (`/api/v1/stocks`)\n\n### GET /api/v1/stocks/price\nLatest stock price, 15-minute delayed. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker (e.g., `AAPL`) |\n\n```bash\ncurl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\\n  \"https://app.sentisense.ai/api/v1/stocks/price?ticker=AAPL\"\n```\n\nResponse: `{ ticker, currentPrice, change, changePercent, previousClose, volume, timestamp, priceAsOf?, expiresEpochSecond, extendedHours?, listingStatus?, delistedDate?, delistingReason? }`.\n\n**A delisted symbol returns its last trade price, not an error, and `listingStatus` is what marks that price as frozen.** The three listing fields are present only when the symbol is delisted or pending delisting, and absent otherwise. `listingStatus` is `\"DELISTED\"` or `\"PENDING_DELISTING\"`; `delistedDate` is the ISO date trading stopped; `delistingReason` is one of `acquired`, `take_private`, `bankruptcy`, `exchange_rule`, `merged`. On a `\"DELISTED\"` symbol the price, change, and change percent never advance again, so do not render them as a current tick.\n\n**Prices are delayed 15 minutes.** This applies to every price on this API, in every session, including the `extendedHours` values below. Do not present these quotes as live, and do not use them for execution or for any decision that turns on the current tick.\n\nRead **`priceAsOf`** for freshness: it is when the market data behind `currentPrice` is actually from, in epoch milliseconds. Do not use `timestamp` for this. `timestamp` is when the response was served, so it tracks the current clock no matter how old the value is. `priceAsOf` is omitted outside regular hours and whenever the upstream data carries no time of its own, so treat an absent `priceAsOf` as unknown age, not as fresh, and fall back to assuming the 15 minutes.\n\n`currentPrice` is always the regular-session price: the most recent regular-session value during RTH (09:30 to 16:00 ET), and the most recent regular-session close otherwise. The optional `extendedHours` field is present whenever there is an extended-hours price to show, which is pre-market (from 04:00 ET) and from the 16:00 ET close until the next pre-market opens, weekends included: once after-hours trading stops at 20:00 ET the last print is carried forward rather than dropped. It is absent during regular hours and for a ticker that did not trade outside them. It carries `{ session: \"pre\" | \"post\", price, change, changePercent }`, where `change` / `changePercent` are computed vs `currentPrice`.\n\n### GET /api/v1/stocks/prices\nBatch latest prices, 15-minute delayed (see `/price` above). **Public.** Returns a JSON array; each element has the same shape as `/price` (including a `ticker` field, an optional `extendedHours` object, and the optional `listingStatus` / `delistedDate` / `delistingReason` fields), so check each element for a frozen price rather than assuming a batch is uniformly live.\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `tickers` | string | Yes | Comma-separated (e.g., `AAPL,TSLA,NVDA`) |\n\n### GET /api/v1/stocks/chart\nHistorical OHLCV chart data. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n| `timeframe` | string | No | `1D`, `5D`, `1W`, `1M`, `3M`, `6M`, `1Y`, `5Y`, `10Y`, `MAX` (default: `1M`) |\n\n`MAX` returns a stock's full available history, up to 26 years (AAPL: 320 monthly bars back to\n1999). Granularity scales with the range: intraday for `1D` through `1M` (5-minute for `1D`,\n15-minute for `5D`, 30-minute for `1W`, hourly for `1M`), daily for `3M` through `1Y`, weekly for\n`5Y`/`10Y`, monthly for `MAX`. Ranges of `10Y` and `MAX` are adjusted for both splits and\ndividends so the series is comparable end to end; shorter ranges (through `5Y`) are split-adjusted\nonly, so the two bases differ on the same historical date by roughly the dividends paid since.\n`volume` is on the same adjusted basis as the prices in every range (pre-split bars report shares\nin today's share count), so the volume series has no split cliff either. Every bar carries\n`adjusted: true` to mark that basis. Expect an old bar on a heavily-split stock to report a much\nlarger share count than a recent one: AAPL has split 28-for-1 since 2013, so one share of 2008 is\n28 shares now and its raw turnover is counted 28 times over. On the monthly series that puts a 2008\nbar near 24 billion shares against roughly 1 billion for a recent month. That is the restatement,\nnot an error.\n\n`10Y` and `MAX` may answer `202 Accepted` with an empty array and a `Retry-After` header, meaning\nthat stock's deep history is still being assembled; retry and you get the full series. A `200`\nalways carries the range you asked for, never a silently shortened one. An unrecognized\n`timeframe` value answers `400` with an `invalid_timeframe` error naming the valid values.\n\nEach bar includes `timestamp` (Unix ms), `date`, `open`, `high`, `low`, `close`, `volume`, `adjusted` (always `true`), and `session`. The `session` field is `pre` (04:00 to 09:30 ET), `regular` (09:30 to 16:00 ET), or `post` (16:00 to 20:00 ET) for intraday timeframes (`1D`, `5D`, `1W`, `1M`); it is `null` for daily, weekly, and monthly bars (`3M` and longer) that span whole sessions. The `1M` timeframe is filtered to `regular`-session bars only.\n\n### GET /api/v1/stocks\nList all tracked ticker symbols. **Public.**\n\n### GET /api/v1/stocks/detailed\nAll stocks with company name, KB entity ID, URL slug, and precomputed `socialDominance` (`{ value, rank, percentile }`, daily refresh, null when no signal). **Public.**\n\n**Example:** sort the universe by share of voice without any second request, or filter by `socialDominance.rank <= 50` for the top-50 most discussed names.\n\n### GET /api/v1/stocks/popular\nPopular stock tickers. **Public.**\n\n### GET /api/v1/stocks/popular/detailed\nPopular stocks with company details. **Public.** Rows carry the same keys as `/detailed`. Check `socialDominance` before you sort or filter this list by share of voice: where it is `null` on a row, read it from `/detailed` by `ticker`.\n\n### GET /api/v1/stocks/images\nCompany logo URLs. **Public.** `GET` a returned URL to receive the image bytes; no API key is needed for the image fetch itself. Treat the URLs as refreshable rather than permanent: brand assets are periodically refreshed, so re-read them from this endpoint instead of storing them long term.\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `tickers` | string | Yes | Comma-separated tickers (max 600) |\n\n### GET /api/v1/stocks/descriptions\nCompany profiles with branding, industry, and market cap; `sector` when available (often absent). **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `tickers` | string | Yes | Comma-separated tickers |\n\n### GET /api/v1/stocks/{ticker}/profile\nCompany profile (CEO, sector, industry). **Public.**\n\nAlso carries `listingStatus`, `delistedDate` and `delistingReason` when the symbol is delisted or pending delisting. All three are absent for a normally listed symbol. Values match `/price` above: `listingStatus` is `\"DELISTED\"` or `\"PENDING_DELISTING\"`, `delistedDate` is the ISO date trading stopped, `delistingReason` is one of `acquired`, `take_private`, `bankruptcy`, `exchange_rule`, `merged`.\n\nFor a tracked ETF ticker, the profile may also carry `imageUrl`, a square presentation image for the fund. It is the issuer's mark rather than the individual fund's, so every fund in a family shares one image, and it matches the `imageUrl` returned by the `/etfs` endpoints. It is square like `logoUrl` and `iconUrl`, so the same avatar slot renders a stock and an ETF, but it is a first-party asset rather than a vendor branding mark and is returned as a direct URL. It is absent for issuers we hold no image for.\n\n### GET /api/v1/stocks/{ticker}/similar\nPeer/similar stocks. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `limit` | int | No | 5 | Max results |\n\nResponse: bare array of `{ symbol, name, price, changePercent }`. The key is `symbol`, not `ticker`, and the array can hold fewer than `limit` entries.\n\n### GET /api/v1/stocks/{ticker}/sentiment\nOne-call sentiment picture for a stock: the SentiSense Score with its 30-day regime, where the conversation is happening by source, and what is driving it. **Public.** **Quota-gated** when called with a key.\n\nThis endpoint also answers without an API key, and returns the same full payload either way. The tradeoff is real in both directions: a keyed call is attributed to your account but spends monthly quota and per-minute rate limit, while a keyless call costs you neither and is not attributed. Send the key when you want the usage on your account; either way the data is identical.\n\nResponse: `{ isPreview, previewReason, data }`. Everything below lives under `data`, which carries `ticker`, `companyName`, `asOf`, then the fields in the table. This endpoint is Free but still uses the wrapper (`isPreview` is `false` and `previewReason` is `null` on every tier), so unwrap first: reading `sentisenseScore` off the root returns nothing, and the full path is `data.sentisenseScore`.\n\n| Field (under `data`) | Type | Description |\n|-------|------|-------------|\n| `sentisenseScore` | number or null | Today's Score (0-centered composite of sentiment and mentions, unbounded). Null until today's reading lands, see the note below |\n| `sentisenseScoreAvg30d` | number | 30-day average, the stable regime figure |\n| `sentisenseScoreDelta30d` | number | Change over 30 days |\n| `scoreLabel` | string | Seven-band label of the 30-day average |\n| `direction` | string | `Bullish`, `Neutral` or `Bearish`, from the 30-day average |\n| `latestDirection` | string or null | Same three bands, from today's read. Null in lockstep with `sentisenseScore` |\n| `trend` | string | `UP`, `DOWN` or `FLAT` |\n| `scoreSparkline` | number[] | Daily Score series |\n| `mentions` / `mentionsAvg30d` | number | Mention volume of the latest New York daily bucket with data (today's once it lands, otherwise an earlier day; `narrative` names which), and the 30-day daily average |\n| `socialDominance` | number | Latest share of voice, as a fraction (`0.021` = 2.1%) |\n| `bySource[]` | array | Per-source tone, loudest first: `source` (`News`, `Reddit`, `X`, `YouTube`, `Hacker News`, `Substack`), `direction`, `mentionShare` (whole-number percent; rounding can make the array sum to 99 or 101 rather than exactly 100), `value` (per-source polarity, -1 to +1) |\n| `relatedTickers[]` | array | Curated peers: `ticker`, `name` |\n| `drivers[]` | array | Top story drivers: `title`, `tone` (-1 to +1) |\n| `narrative` | string | Plain-language summary of why the Score sits where it does |\n| `faq[]` | array | `question` / `answer` pairs for the common asks on this ticker |\n\nUse this when you want the headline read in one call. Use `GET /api/v2/metrics/entity/{ticker}/metric/sentisense` instead when you need the Score as a time series over a specific window. Returns `404` when the ticker has no sentiment coverage.\n\n**`sentisenseScore` and `latestDirection` are today's reading, and are `null` until the day's first analytics run lands** (mid-morning ET, later at weekends). Poll before that and every ticker returns null for these two, which is a timing state and not an outage. The rest of the response is unaffected: `scoreLabel`, `direction` and `sentisenseScoreAvg30d` are all computed from the 30-day average, so prefer those when you need a headline that is always present. A null here means \"no reading yet\", never a Score of zero. A measured 0.0 is served as `0.0`, so do not coerce null to 0, and do not infer absence by thresholding the 30-day average, which would suppress genuine neutrals.\n\nAggregate metrics such as sentiment and mention counts incorporate signals from sources that are not individually retrievable as documents, so document counts from the Documents API are not a complete audit trail of a score.\n\n> Via the MCP connector this same picture comes back from the `get_stock_snapshot` tool rather than a separate sentiment tool.\n\n\n### GET /api/v1/stocks/{ticker}/entities\nRelated ontology entities (CEO, products, partners). **Public.** Each entry carries a `urlSlug` (e.g. `Tim-Cook`) that plugs into the Metrics API `{entityId}` parameter. It is a flat list: for the relationship behind each link, use the graph endpoint below.\n\n### GET /api/v1/stocks/{ticker}/graph\nOne company's neighborhood in the SentiSense ontology as a typed graph: the people, products, product families, peer companies and organizations the knowledge base connects to that ticker, plus the named relationship between each pair. **Public** (API key required). One ticker per call; there is no listing or enumeration form.\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `depth` | integer | No | `1` | `1` or `2`. `1` returns the company's own people, products and peers; `2` walks one hop further, which is how an organization behind a person appears. Anything else returns `400 invalid_depth`. Send it explicitly so the walk you describe is the walk you asked for |\n| `cap` | integer | No | `75` | `1` to `200`, the maximum number of non-root nodes returned. Anything else returns `400 invalid_cap`. Send it explicitly for the same reason |\n\nResponse: a flat object, no `{isPreview, data}` wrapper.\n\n| Field | Type | Notes |\n|-------|------|-------|\n| `ticker` | string | The normalized ticker |\n| `root` | string | The root company's slug. The root is also the first entry in `nodes` |\n| `depth`, `cap` | integer | The values the walk was asked for, echoed back. `depth` is what you requested, not how far the walk reached |\n| `truncated` | boolean | `true` when `cap` cut the walk short. The survivors are ordered by node type then name, not by importance, so a truncated response can drop people and products while keeping peers |\n| `counts` | object | `{nodes, edges, byType}`, where `byType` maps a node type to how many of it came back |\n| `omitted` | integer | Nodes left out for carrying no slug, and so not addressable. Normally `0` |\n| `groups` | object | `people`, `products`, `productFamilies`, `peers`, `organizations`, `publishers`, `topics`. Every one is a list of **slugs** except `productFamilies`, which is a list of `{family, members}`. A slug is the same handle the Metrics API takes, so you can query one straight from `groups`; join it to `nodes` when you need its `displayName` or `type` |\n| `nodes` | array | `{slug, displayName, type}`. `type` is uppercase (`COMPANY`, `PERSON`, `PRODUCT_OR_SERVICE`, `ORGANIZATION`, `PUBLISHER`, `TOPIC`), and `slug` is the Metrics API `{entityId}` handle |\n| `edges` | array | `{source, target, type, direction, properties}`, both ends slugs. `type` is one of `LEADS`, `FOUNDED`, `PRODUCT_OF`, `VARIANT_OF`, `PEER`, `OWNS`, `SUBSIDIARY_OF`, `SUBTOPIC_OF`, `BELONGS_TO`, `AFFILIATED_WITH`. `direction` is `DIRECTED` or `BIDIRECTIONAL`; on a `BIDIRECTIONAL` edge the order carries no meaning. `properties` is a flat string map and is often empty |\n\nAn unknown or unlisted ticker returns `404 entity_not_found` with up to three `suggestions`, which is a different answer from `/entities`, where an unknown ticker returns `200 []`. The response carries no sentiment, Score or mention counts: fetch those per handle from the Metrics API.\n\n`publishers` and `topics` are part of the response shape but are not reachable from a company root today, so treat an empty list there as the expected state rather than as missing theme coverage.\n\n### GET /api/v1/stocks/{ticker}/ai-summary\nAI-generated stock analysis report. **PRO** (Free: `depth=basic` unlimited, `depth=deep` limited to 10/month). `depth=basic` returns a preheader summary. `depth=deep` returns a full multi-section report. Exhausting the `depth=deep` monthly view allowance returns `429` with `{error: \"quota_exceeded\", message, ...}`, the same contract as every other quota-gated endpoint: `message` says when the allowance resets (the start of next month) and links PRO, and the response has no `Retry-After` header.\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `depth` | string | No | `basic` | `basic` or `deep` |\n\nResponse: flat object (no `{isPreview, data}` wrapper).\n\n| Field | Type | Notes |\n|-------|------|-------|\n| `ticker` | string | |\n| `companyName` | string | |\n| `status` | string | `READY`, `NOT_AVAILABLE`, or `ERROR` |\n| `statusReason` | string or null | Present on `NOT_AVAILABLE` / `ERROR` only |\n| `reportType` | string | `SUMMARY` for `depth=basic`, `FULL` for `depth=deep` |\n| `version` | integer | Report date encoded as yymmdd (e.g. 260520) |\n| `lastUpdated` | long | Epoch milliseconds |\n| `sections` | object | Section name to `{content, directives}`. Present on both depths: `depth=basic` returns a single `Executive Summary` section, `depth=deep` returns the full set. |\n| `sectionOrder` | string[] | Ordered section keys for rendering. Present on both depths; `[\"Executive Summary\"]` on `depth=basic`. |\n| `fromCache` | boolean | Whether this response was served from the report cache. `false` also covers a report served straight from the packaged knowledge base, so it does not mean the report was regenerated for your call: read freshness from `lastUpdated`. |\n| `moatRating` | integer or null | Proprietary moat quality score 0-10 (network effects, switching costs, intangibles, cost advantages, efficient scale). Present on `depth=deep` only. Null if not yet assessed for this ticker. |\n| `aiDisruptionRisk` | string or null | `Low`, `Medium`, `High`, or `Critical`. Measures AI revenue-displacement exposure. Present on `depth=deep` only. Null if not yet assessed. |\n\n**Do not test for the presence of `sections` to detect a deep report:** both depths return it. Branch on `reportType` (`SUMMARY` vs `FULL`) instead.\n\n### GET /api/v1/stocks/{ticker}/metrics/{metricType}/breakdown\nSentiment or mention metrics breakdown by sub-entities. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `metricType` | path | Yes | `sentiment` or `mentions` |\n| `startTime` | long | Yes | Start time in epoch ms |\n| `endTime` | long | Yes | End time in epoch ms |\n\n### GET /api/v1/stocks/market-status\nCurrent market open/closed status. **API key required.**\n\nResponse: `{ status: \"open\" | \"closed\", timestamp: <epoch_ms> }`. The `timestamp` is a numeric epoch milliseconds value (not a string).\n\n### GET /api/v1/stocks/fundamentals\nFinancial statement data. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `timeframe` | string | No | `quarterly` | `quarterly` or `annual` |\n| `fiscalPeriod` | string | No | - | e.g., `Q4` |\n| `fiscalYear` | int | No | - | e.g., `2024` |\n\n**Reporting currency (applies to every fundamentals endpoint):** figures are as reported by the\nfiler, in the filer's own currency, never converted to USD. Foreign ADR filers report in home\ncurrency (SK hynix: KRW, Toyota: JPY, ASML: EUR). The optional `reportedCurrency` field (\"USD\",\n\"KRW\", ...) on the response (and on each `/fundamentals/history` row) names it; when absent the\ncurrency is unknown, not implicitly USD. Never mix these figures with the share price: the price\nis the USD ADR price, so for non-USD filers `peRatio` / `psRatio` / `pbRatio` are served as\n`null` on purpose, and you should not recompute them. Same-currency ratios (margins, ROE, ROA,\ncurrent ratio, debt/equity) stay valid for all filers.\n\n### GET /api/v1/stocks/fundamentals/current\nTrailing-twelve-month valuation snapshot against the latest price. **Public.** It is not a statement snapshot: for income-statement, balance-sheet and cash-flow lines use `/fundamentals` or `/fundamentals/history`.\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n\nResponse (flat): `{ ticker, currentPrice, peTTM, psTTM, epsTTM, revenueTTM, quartersIncluded, available, reason, fetchedAt, reportedCurrency? }`. `peTTM` and `psTTM` are the latest price over trailing EPS and over trailing revenue per share; `quartersIncluded` is how many quarters the trailing figures sum (normally 4); `fetchedAt` is epoch seconds. When `available` is `false`, `reason` says why (no current price, or no trailing earnings data) and the TTM fields are null. `reportedCurrency` names the currency of `epsTTM` and `revenueTTM` (`currentPrice` stays USD) and is omitted when unknown; for a non-USD filer `peTTM` and `psTTM` are `null` by design, the same cross-currency rule as above.\n\n### GET /api/v1/stocks/fundamentals/history\nMulti-period history of full financial statements (income statement, balance sheet, cash flow), one\nentry per fiscal quarter or year, newest first. Use for margin trends, multi-year comparisons, or as\nthe input to a valuation model. Not the same endpoint as `/fundamentals` (single period) or\n`/fundamentals/historical/revenue` (income-statement lines only, no balance sheet or cash flow). **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `timeframe` | string | No | `quarterly` | `quarterly` or `annual` |\n| `limit` | int | No | 12 quarterly / 10 annual | Periods to return, capped at 40 quarterly / 20 annual |\n\nResponse includes `count` (periods actually returned, can be less than `limit`), `reason`\n(non-null only when `periods` is empty, e.g. a recent listing), and `dataSource` (deprecated:\nalways an empty string, kept for response-shape compatibility, slated for removal).\n\n**Earnings and share-count fields** (same on `/fundamentals`). These are reported independently by\nthe data provider. They are NOT derived from one another and will NOT reconcile arithmetically:\n`netIncome / weightedAverageSharesDiluted` does not reproduce any EPS field, because the provider\ncomputes EPS from its own numerator on its own share basis. Do not \"check\" our data by dividing\nthese, and do not present a computed per-share figure as if it were the reported one.\n\n| Field | Meaning |\n|---|---|\n| `epsBasic` | Basic EPS. Always basic, on every source. |\n| `epsDiluted` | Diluted EPS. Null when the provider reports no diluted figure. |\n| `eps` | EPS as the provider reports it, usually basic. Prefer `epsBasic`/`epsDiluted`, which name their basis. |\n| `netIncome` | Consolidated net income. Not the EPS numerator. |\n| `bottomLineNetIncome` | The provider's bottom-line income line, which can differ from `netIncome` in size and in sign. Null means the line was not supplied for that period, not that it equals `netIncome`. |\n| `weightedAverageSharesBasic` | Basic weighted-average shares for the period. Null when not reported. |\n| `weightedAverageSharesDiluted` | Diluted weighted-average shares for the period. Null when not reported. |\n| `sharesOutstanding` | **Deprecated, stops being populated 2026-12-15.** Not a period-end count despite the name. Use the weighted-average fields. |\n\nBoth share fields are averages ACROSS the period, not counts at period end, so neither is a correct\ninput to a market capitalisation or a book value per share; a share field is null when the provider\nreports no count on that basis or a count of zero or below. Income fields are in the filer's reporting\ncurrency (see `reportedCurrency`), EPS is that currency per share, share fields are a number of\nshares. Per-period EPS is served as the provider reports it, and we restate it for a small list of named issuers and nowhere else: where a provider restated a company's share counts for a split but left older rows' EPS on the pre-split basis, and that has been checked against the company's own filing, we divide the EPS on the affected rows by the split ratio and mark each one with `epsBasisRepair` (`fields`, `multiplier`, `splitExecutionDates`). Share counts and net income are never changed. `epsBasisRepair` is null on almost every row, and null means we applied no EPS repair to that row: it is NOT a statement that the row's EPS and share count are on the same basis, since an unlisted issuer, a row that did not qualify, and a row whose split history we could not read all carry null. `epsBasisRepair` describes per-period EPS only: this repair never changes `epsTTM` or the other trailing-twelve-month figures, and the marker never describes a trailing adjustment. Trailing figures are assembled separately and whether they carry a split adjustment of their own depends on which source served them. For a small list of recently listed companies, quarterly history also includes a pre-IPO quarter the company filed only as the prior-year comparison column of a later filing, usually its first 10-Q: that row carries `preIpoFiling` (`form`, `accession`, `filedDate`, `note`) naming the filing, holds the income-statement lines only, and gives way to the provider's own row for the same period once one exists. `preIpoFiling` is null on every other row.\n\n### GET /api/v1/stocks/fundamentals/periods\nAvailable fiscal periods. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n\n### GET /api/v1/stocks/fundamentals/historical/revenue\nHistorical income-statement lines per period: revenue, gross profit, operating income, net income,\nand EPS. Response wraps them in `dataPoints` (not `periods` like `/fundamentals/history`), plus\n`count`, `dataSource`, and `reason`. For full statements including balance sheet and cash flow,\nuse `/fundamentals/history` instead. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `timeframe` | string | No | `quarterly` | `quarterly` or `annual` |\n\n### GET /api/v1/stocks/short-interest\nShort interest data from FINRA. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `limit` | int | No | 24 | Max data points |\n\n### GET /api/v1/stocks/float\nFloat information (shares outstanding, public float). **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n\n### GET /api/v1/stocks/short-volume\nShort volume trading data. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `limit` | int | No | 90 | Max data points |\n\n### GET /api/v1/stocks/{ticker}/quote\nAggregate quote snapshot: latest price (15-minute delayed), today OHLC, 52-week range, market cap, P/E, EPS TTM, dividend yield, 200-day moving average. Single call for detail pages. **API key required.**\n\nResponse: `{ ticker, currentPrice, change, changePercent, volume, open, dayHigh, dayLow, previousClose, week52High, week52Low, marketCap, peRatio, epsTTM, dividendYield, movingAverage200Day, reportedCurrency, timestamp, extendedHours?, listingStatus?, delistedDate?, delistingReason? }` -- all fields except `ticker` are nullable. `currentPrice` is always the regular-session price; the optional `extendedHours` object (`{ session, price, change, changePercent }`) is present outside regular hours whenever an extended-hours price exists, and `session` stays `\"post\"` while the last after-hours print is carried overnight and through the weekend. `movingAverage200Day` is `null` when fewer than 200 trading days of history exist. `reportedCurrency` (\"USD\", \"EUR\", \"KRW\", ...) names the currency `epsTTM` is reported in, matching the fundamentals endpoints. Responses carry a private 15 s `max-age`; the server's own price cache is 30 s, per process.\n\n**Null fields are omitted, and foreign filers omit `peRatio`.** A null field is left out of the JSON entirely rather than serialized as `null`, so do not assume a key is present: read defensively. On foreign ADR filers such as `ASML` and `TM`, `peRatio` is absent, while `epsTTM` is served in the filer's home currency and `reportedCurrency` names that currency (`EUR` for ASML, `JPY` for TM, whose `epsTTM` reads in the thousands beside a USD price near 200). Price fields and `dividendYield` are served normally. This is the same cross-currency rule as the fundamentals endpoints: the price is the USD ADR price and the filer's earnings are in home currency, so `peRatio` is withheld rather than computed across two currencies. Always check `reportedCurrency` before using `epsTTM`, and do not divide `currentPrice` by a non-USD `epsTTM` to fill the gap yourself.\n\n**Delisted symbols keep quoting their last trade.** `listingStatus`, `delistedDate` and `delistingReason` are present only when the symbol is delisted or pending delisting, and absent otherwise, with the same values as `/price`. When `listingStatus` reads `\"DELISTED\"`, every price field in this payload is frozen at the last trade before `delistedDate` and nothing else in the response says so.\n\nETF tickers (e.g. `VTI`, `SPY`) return `400 ticker_is_etf` from this endpoint. Use `GET /api/v1/etfs/{ticker}/quote` instead, which returns AUM, expense ratio, NAV, and inception date rather than market cap, P/E, and EPS.\n\n\n### GET /api/v1/stocks/{ticker}/kpis\nCompany-specific KPI time-series. Curated GAAP and non-GAAP metrics from earnings filings: iPhone unit sales, Tesla deliveries, AWS revenue, Netflix paid net adds, etc. **PRO (preview)** -- Free: metadata only with empty `kpis` list, PRO: full series. Returns 404 for tickers without curated coverage.\n\nCoverage today: near-complete for the S&P 500 plus an extended universe of 900+ US-listed companies (970 tickers as of 2026-09-09). Use `GET /api/v1/stocks/with-kpis` to enumerate.\n\nResponse wrapper: `{ isPreview, previewReason, data: CompanyKpis }`.\n\n`CompanyKpis` shape: `{ ticker, companyName, cik, lastUpdated, kpis: KpiSeries[] }`.\n\n`KpiSeries` shape: `{ id, name, category, unit, displayFormat, chartType, values: KpiDataPoint[], sourceRef, discontinued, discontinuedNote }`. `id` is a stable per-ticker identifier (e.g. `iphone_revenue`). `category` is one of `product_revenue`, `segment_revenue`, `unit_economics`, etc. `chartType` is `bar` or `line`.\n\n`KpiDataPoint` shape: `{ period, date, value, isEstimate }`. `period` is the fiscal label (e.g. `Q2 FY2026`); `date` is the ISO close date.\n\nPass ticker, selected KPI IDs and any fetched response to the `company-kpi-tracker` skill; return a dated card with matched deltas and source and estimate flags.\n\n### GET /api/v1/stocks/with-kpis\nList every ticker with curated KPI coverage. Sorted alphabetically. Builder discovery: render a supported-tickers page or seed a watchlist without 404-probing one ticker at a time. **Discovery (no quota cost)** -- API key required for identity/abuse tracking, but the call does not consume your monthly quota. Rate-limit-per-minute still applies.\n\nResponse: `{ count, tickers: KpiCoverageEntry[] }` where each entry is `{ ticker, companyName, lastUpdated, kpiCount }`.\n\n```python\nclient = SentiSenseClient(api_key=os.environ[\"SENTISENSE_API_KEY\"])\ncoverage = client.list_kpi_coverage()\nprint(f\"{coverage.count} tickers covered\")\nfor entry in coverage.tickers[:5]:\n    print(f\"  {entry.ticker}: {entry.kpiCount} KPIs (refreshed {entry.lastUpdated})\")\n```\n\n### GET /api/v1/stocks/{ticker}/kpis/types\nLightweight KPI metadata tuples for a ticker, without the full series payload. Mirrors `/api/v1/insights/stock/{ticker}/types`. Useful for letting an agent or UI decide what to fetch before committing to the heavy data call. **Discovery (no quota cost)** -- API key required, no quota burn.\n\nResponse: bare array of `{ id, name, category, chartType }`. Returns 404 if the ticker has no curated KPIs.\n\n```python\ntypes = client.get_kpi_types(\"AAPL\")\nfor t in types:\n    print(f\"  {t.id} ({t.chartType}): {t.name}\")\n```\n\n---\n\n## Entities API (`/api/v1/kb`)\n\n### GET /api/v1/kb/entities/search\nSearch the SentiSense ontology for the people, companies, products, and organizations SentiSense tracks, and get the handle to query their metrics. **Public** (API key required).\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `q` | string | Yes | - | Name, alias, ticker, or slug fragment (case-insensitive, minimum 2 characters) |\n| `type` | string | No | all | `company`, `country`, `etf`, `organization`, `person`, `product`, `topic` |\n| `limit` | int | No | 10 | Max results (capped at 25) |\n\n**Response:** array of `{name, urlSlug, type, ticker}` matches, best first. `ticker` is null for entities without one. Feed the `urlSlug` (or `ticker`) into the Metrics API `{entityId}` parameter:\n\n```\nGET /api/v1/kb/entities/search?q=pelosi -> [{\"name\": \"Nancy Pelosi\", \"urlSlug\": \"Nancy-Pelosi\", \"type\": \"person\", \"ticker\": null}]\nGET /api/v2/metrics/entity/Nancy-Pelosi/metric/sentisense\n```\n\nPeople, products, and organizations have the same metrics surface as stocks, so this unlocks queries like a politician's mention volume, a CEO's SentiSense Score (`.../entity/Jensen-Huang/metric/sentisense`), or crowd sentiment on a product versus its parent ticker.\n\n### GET /api/v1/kb/entities/popular\nCurated list of high-profile tracked entities (major CEOs, political figures, the Federal Reserve). **Public** (API key required). Returns `{displayName, type, urlSlug, relatedStock}` entries; use as an autocomplete seed list without issuing a search.\n\n## Metrics API (`/api/v2/metrics`)\n\nTime series metrics for stocks and entities: mentions, sentiment, social dominance, and more. The `{entityId}` path segment accepts a stock ticker (e.g. `AAPL`) or an entity `urlSlug` (e.g. `Nancy-Pelosi`); both are case-insensitive, and a ticker-shaped identifier always means the listed company. Discover handles with `GET /api/v1/kb/entities/search?q=` or `GET /api/v1/stocks/{ticker}/entities`. An unknown identifier returns `404 entity_not_found` with up to three `suggestions`.\n\nWhich handle to store: the `urlSlug`, or the ticker for a listed company. It is the only identifier these paths accept. Internal KB ids, in any spelling (`kb/person/65`, `kb-person-65`, `p65`), are not part of the public API and resolve to nothing. If a rename ever breaks a stored handle, find the entity again by name with `GET /api/v1/kb/entities/search?q=`.\n\nEvery metric type (`mentions`, `sentiment`, `sentisense`, `social_dominance`, `sentisense_rating`, `app_review_count`, `app_rating`) is available on the Free tier: no PRO subscription needed. All metrics endpoints are **Quota-gated**: an API key is required and each request counts against your monthly quota (Free: 1,000 requests/month; PRO: no monthly cap). Per-minute rate limits apply on every tier.\n\n### GET /api/v2/metrics/entity/{entityId}/metric/{metricType}\nTime series metric data for a stock or entity. **Quota-gated** -- all metric types (`mentions`, `sentiment`, `sentisense`, `social_dominance`, `sentisense_rating`, `app_review_count`, `app_rating`) are available on the Free tier. `sentisense_rating` is stocks-only and its `value` is the daily Rating score, 0 to 100, which is the number the letter is banded from and not\n\nFile v2.21.2:_meta.json\n\n{\n  \"ownerId\": \"kn71ca3nrt3w6w0v3nhv3c4tan82x1ym\",\n  \"slug\": \"sentisense\",\n  \"version\": \"2.21.2\",\n  \"publishedAt\": 1791085845985\n}\n\nFile v2.21.2:skill-card.md\n\n## Description:\n\nProvides agents with read-only US stock-market data, sentiment, ratings, filings, institutional activity, and AI-generated insights through the SentiSense API.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[thesentitrader](https://clawhub.ai/user/thesentitrader)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nAgents and developers use this skill to research US stocks, monitor market sentiment and disclosed trading activity, and summarize market data without placing trades.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The service can associate market-data requests, tickers, searches, watchlists, and screener filters with an API key.\n\nMitigation: Use an appropriately scoped account, avoid sharing sensitive research queries, and keep the API key private.\n\nRisk: Market data and AI-generated insights can be incomplete, delayed, or mistaken for investment advice.\n\nMitigation: Check coverage and timestamps, corroborate consequential findings, and treat results as informational rather than trading instructions.\n\n## Reference(s):\n\n- [SentiSense API documentation](https://sentisense.ai/docs/api/)\n- [SentiSense ClawHub release](https://clawhub.ai/thesentitrader/skills/sentisense)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Analysis, API calls, Shell commands]\n\n**Output Format:** [Natural-language market summaries and optional API request examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires a SentiSense API key; API results depend on coverage, subscription tier, and rate limits.]\n\n## Skill Version(s):\n\n2.21.2 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v2.21.1: 3 files, 73592 bytes\n\nFiles: skill-card.md (2292b), SKILL.md (206327b), _meta.json (130b)\n\nFile v2.21.1:SKILL.md\n\n---\nname: sentisense\ndescription: \"US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers every endpoint. Use for stock sentiment API, stock market API, stock rating API, stock letter grade, insider trading data, congress stock trades, 13F holdings, options flow, earnings calendar, stock price API, market data for AI agents. Read-only. No trading, no purchases, no write operations, no wallet access.\"\nhomepage: https://sentisense.ai\nrequires:\n  env:\n    - SENTISENSE_API_KEY\nprimaryEnv: SENTISENSE_API_KEY\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - SENTISENSE_API_KEY\n    primaryEnv: SENTISENSE_API_KEY\n---\n\n# SentiSense API - Skill File for AI Agents\n\n> **SentiSense** is a read-only financial intelligence API: stock prices, insider/politician trading, institutional flows, AI insights, and news sentiment. No trading, no purchases, no write operations. Free tier available.\n\n**Base URL:** `https://app.sentisense.ai`\n**Website:** https://sentisense.ai\n**ClawHub Skill:** [clawhub.ai/TheSentiTrader/sentisense](https://clawhub.ai/TheSentiTrader/sentisense)\n**API Docs:** https://sentisense.ai/docs/api/\n**Authentication:** API key via `X-SentiSense-API-Key` header. Get a free key at https://app.sentisense.ai/get-api-key\n**SDKs (optional):** [Python](https://github.com/SentiSenseApp/sentisense) | [Node.js](https://github.com/SentiSenseApp/sentisense-node) -- source on GitHub. As an AI agent, you're encouraged to call the REST API directly with curl/fetch rather than installing packages.\n\n---\n\n## Use & Disclaimer\n\nThis skill is an **educational data interface** to SentiSense's read-only Data API. Output is informational only. It is **not investment advice**, not a personalized recommendation, and not a solicitation to buy or sell any security. The user is responsible for their own decisions. Use of the API and this skill is subject to the [API Terms of Service](https://sentisense.ai/agreement/API-Terms-of-Service.pdf) and [Terms of Service](https://sentisense.ai/agreement/Terms-of-Service.pdf).\n\n---\n\n## Authentication\n\n```bash\n# Include API key in header\ncurl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\\n  \"https://app.sentisense.ai/api/v1/...\"\n```\n\n**Identify your client.** Send a `User-Agent` naming your agent runtime and this skill, for\nexample `OpenClaw/1.4 (sentisense)` or `ClaudeCode/2.1 (sentisense)`. Substitute your own runtime and\nversion if neither matches. You can also volunteer what your agent is called by adding an\n`agent/<your-agent-name>` token inside the same parentheses, as in\n`OpenClaw/1.4 (sentisense; agent/research-desk)`. All of it is optional, and it is what tells\nus this skill has real integrations behind it, so it gets prioritized and you get notice before it\nchanges.\n\n```python\nimport os\nfrom sentisense import SentiSenseClient\nclient = SentiSenseClient(api_key=os.environ[\"SENTISENSE_API_KEY\"])\n```\n\nAll API endpoints require an API key. Get one free at https://app.sentisense.ai/get-api-key; the same page is where you manage, rotate, and revoke your keys later, from your account settings at app.sentisense.ai.\n\n## Permissions\n\n- Network: HTTPS to app.sentisense.ai only.\n- Credentials: SENTISENSE_API_KEY from the environment.\n- Shell: none required.\n- Files: none.\n\n### Command-line client\n\nThe REST recipe in this file is the primary path. A maintained command-line client is available as the separate `sentisense-cli` skill for hosts that prefer one.\n\n### Access Tiers\n\n| Badge | Meaning |\n|-------|---------|\n| **Public** | Available on all tiers (Free and PRO) |\n| **Public (preview)** | Free gets limited preview; PRO gets full data |\n| **Quota-gated** | Consumes monthly quota (Free: limited, PRO: unlimited) |\n| **Discovery (no quota cost)** | API key required (identity/abuse tracking), but the call does not burn your monthly quota. Rate-limit-per-minute still applies. Used for lightweight metadata endpoints like `/stocks/with-kpis` and `/stocks/{ticker}/kpis/types`. |\n| **PRO only** | Requires PRO subscription |\n\n### Rate Limits\n\n| Tier | Requests/Month | Rate |\n|------|----------------|------|\n| Free | 1,000 | 30 requests/minute |\n| PRO ($15/mo) | Unlimited | 300 requests/minute |\n| Pro Max | Unlimited | 1,500 requests/minute |\n| Data License (Essentials, Premium) | Unlimited | 2,000 requests/minute |\n\nPro Max and the Data License plans include every PRO feature; the API reports their tier as `PRO`.\n\n### Ticker Symbols\n\nEndpoints that take a `{ticker}` path parameter accept the canonical primary ticker for each company. For dual-class share companies, the API also accepts the secondary class as an alias and resolves it server-side, so you can pass whichever ticker your data source provides.\n\n| You pass | Resolves to | Reason |\n|----------|-------------|--------|\n| `GOOG` | `GOOGL` | Alphabet Class C resolves to Class A |\n| `BRK.A`, `BRK-A`, `BRKA` | `BRK.B` | Berkshire Class A resolves to Class B |\n| `BRK-B`, `BRKB` | `BRK.B` | Punctuation variants normalized |\n\nAliasing applies to research endpoints (analyst, KPIs, insights, insider, institutional holders, politicians filings, options). Quote and chart endpoints leave the ticker as-is, since market-data providers handle their own symbology. Tickers are case-insensitive. News Corp (`NWSA`/`NWS`) and Fox (`FOXA`/`FOX`) are NOT aliased to each other (each class is tracked separately).\n\n---\n\n## What You Can Build\n\n### Smart Money Tracker\nCross-reference insider trading, institutional flows, and politician trades to follow where the smart money is moving. High-conviction signals come from convergence across all three.\n- `GET /api/v1/insider/activity` for market-wide insider buying/selling\n- `GET /api/v1/institutional/flows` for quarterly institutional positioning (optional `reportDate`; omit for the latest quarter)\n- `GET /api/v1/politicians/activity` for congressional STOCK Act trades\n- `GET /api/v1/insights/stock/{ticker}` for AI signals that combine these data sources\n\n### Sentiment-Driven Watchlist\nAlert when sentiment shifts for your stocks. Track news volume, social mentions, and baseline deviations.\n- `GET /api/v2/metrics/entity/{ticker}/metric/sentisense` for the SentiSense Score time series (prefer it over `sentiment`; see the metric notes below)\n- `GET /api/v2/metrics/entity/{ticker}/baselines/sentiment` for anomaly detection against historical and peer baselines\n- `GET /api/v1/documents/ticker/{ticker}` for the underlying news and social posts driving the shift\n\n### Congressional Trade Monitor\nTrack what Congress is buying before it moves. Filter by party, chamber, or individual politician. Check if corporate insiders agree.\n- `GET /api/v1/politicians/activity` for recent congressional trades across all members\n- `GET /api/v1/politicians/member/{slug}` for individual politician profiles and trade history\n- `GET /api/v1/insider/trades/{ticker}` to cross-reference with corporate insider activity on the same stock\n\n### AI Research Assistant\nGenerate stock research reports by combining multiple data signals into a single analysis.\n- `GET /api/v1/stocks/{ticker}/ai-summary?depth=deep` for the full AI analysis report\n- `GET /api/v1/insights/stock/{ticker}` for AI-generated stock signals\n- `GET /api/v1/stocks/fundamentals?ticker={ticker}` for a single period of financial statement data\n- `GET /api/v1/stocks/fundamentals/history?ticker={ticker}&timeframe=annual&limit=10` for multi-year revenue, margin, and free-cash-flow trend to support valuation work\n- `GET /api/v1/documents/ticker/{ticker}` for recent news context\n\n### Earnings Calendar Monitor\nPosition ahead of earnings instead of reacting to them. Pull the forward calendar, intersect it with a watchlist, and pre-load sentiment and smart-money context for the companies reporting soon.\n- `GET /api/v1/calendar/earnings?week=next` for who reports next week (or `?from=&to=` for a custom window)\n- `GET /api/v1/calendar/earnings?ticker={ticker}` for a single name's next report date and consensus EPS (on a FREE key this searches only the current Monday-to-Sunday week; see the Calendar section)\n- `GET /api/v2/metrics/entity/{ticker}/metric/sentisense` to gauge positioning into the print\n- `GET /api/v1/insider/trades/{ticker}` to see if insiders moved ahead of the date\n\n### Market Dashboard\nMarket overview combining prices, sentiment, and top signals.\n- `GET /api/v1/stocks/market-status` to check if the market is open\n- `GET /api/v1/market-summary` for AI-generated market headline and analysis\n- `GET /api/v1/insights/market` for the top market-moving signals right now\n- `GET /api/v1/stocks/prices?tickers=SPY,QQQ,IWM,DIA` for index tracking\n\n### Cross-Signal Stock Screener\nFilter the whole tracked universe on the SentiSense Score and attention in the same query as analyst consensus, technicals and price. The differentiated screens are the disagreements: crowd bullish where the street is not, price below its 200-day while the Score is rising.\n- `GET /api/v1/screener/fields` once at startup for the filterable field catalog (stock and ETF), then build filters from it\n- `GET /api/v1/screener/screens` for 28 curated screens, each with a plan you can execute as-is\n- `POST /api/v1/screener/execute` to run a plan against the stock universe (or a `tickers` watchlist)\n- `POST /api/v1/screener/etfs/execute` for the same against the ETF universe\n\n### Market Sentiment Structure\nWhich way the market's tone leans, and how widely it's shared. Daily snapshots.\n- `GET /api/v1/sentiment/sectors` for the 11 GICS sectors vs the market's own tone (`consensusVsMarket` + \"Hotter/Cooler than market\" labels; market-relative because news tone skews positive as a genre)\n- `GET /api/v1/sentiment/breadth` for the bullish/neutral/bearish share of ~1,000 covered stocks (the sentiment advance/decline line; `netBreadth` in points, stock- and mention-weighted)\n- `GET /api/v1/trackers/sentiment-leaderboard` for the most bullish and bearish stocks ranked by their 30-day SentiSense Score, with a minimum-mention confidence floor (each row also carries the 7-day Score and raw tone polarity, which do not set the order)\n- `GET /api/v1/trackers/sentiment-movers` for the biggest SentiSense Score shifts, improving and deteriorating, ranked by the 7-day average Score minus the 30-day average (a row with no Score change falls back to its tone change)\n\n---\n\n## Agent Tips\n\n### Workflow Pattern\n1. Call `GET /api/v1/stocks/market-status` first to check if the market is open\n2. Call `GET /api/v1/institutional/quarters` before the institutional endpoints that need a `reportDate` to get valid values (`/flows` does not need one; omit it for the latest quarter)\n3. All PRO-gated endpoints return `{isPreview, previewReason, data}`. Always access `response[\"data\"]` (or `response.data`). On a preview (FREE) list response a `totalCount` field is also present: the number of items in the full PRO dataset, so you can show \"showing N of totalCount\". **A preview is a slice, not the window.** When `isPreview` is `true` and `totalCount` is larger than the rows returned, those rows are the newest or top N only: label them (\"newest 5 of 61 trades, free preview\") and never infer absence from them. No \"zero insider buying\", \"no congressional activity\", \"not scheduled\" or \"no unusual contracts\" from a slice\n4. Use `lookbackDays` (1-365) on insider and politician endpoints to control the time window\n\n### Common Mistakes\n- **Do NOT hardcode `reportDate`** for institutional endpoints. When you pass one, fetch it from `/quarters` first; quarters change as new SEC filings come in. (`/flows` does not require one: omit it for the latest quarter, or pass one for a specific quarter.)\n- **Do NOT iterate the response directly.** Unwrap `response[\"data\"]` first. All PRO-gated endpoints use the `{isPreview, previewReason, data}` wrapper, and some Free ones do too (`/stocks/{ticker}/sentiment` wraps on every tier), so let each endpoint's own Response line decide rather than inferring the shape from the tier\n- **Do NOT use `/api/v1/entity-metrics/*`** for metrics. These are RETIRED (return 410 Gone). Use `/api/v2/metrics/` instead\n- **The `source` parameter is case-insensitive.** `news`, `NEWS`, `News` all work\n\n### Endpoints That Do NOT Exist\nDo not hallucinate these. They are not part of the SentiSense API:\n- `/api/v1/options/flow` or `/api/v1/dark-pool`: these exact paths do not exist. For end-of-day options analytics (IV rank, put/call percentile, 25-delta skew, open-interest walls, max pain, unusual-by-volume contracts) use the Options Intelligence endpoints instead: `/api/v1/options/overview` and `/api/v1/stocks/{ticker}/options/summary`. We do not attribute tick-level order flow (no buy/sell aggressor tagging) and we have no dark-pool data\n- `/api/v1/earnings` as a root: the only paths under it are `/api/v1/earnings/recent` (which covered companies already reported in a recent window), `/api/v1/earnings/ranked` (the importance-ranked view of recent reporters and upcoming reports) and `/api/v1/earnings/statistics` (market-wide beat rate joined to what the market did next). For the forward calendar use `/api/v1/calendar/earnings`; for a company's per-quarter earnings analysis report use `/api/v1/stocks/{ticker}/earnings-summaries`; for reported financials use `/api/v1/stocks/fundamentals` (single period) or `/api/v1/stocks/fundamentals/history` (multi-period trend, up to 40 quarters or 20 years)\n- `/api/v1/alerts` or `/api/v1/notifications`: alerts are user-facing only, not available via API\n- `/api/v1/chat` or `/api/v1/ask`: the AI chat is not accessible via API\n- `/api/v2/sentiment`: the correct path is `/api/v2/metrics/entity/{id}/metric/sentiment`\n- `/api/v1/congress` or `/api/v1/congressional`: the correct path is `/api/v1/politicians`\n- `/api/v1/screener/plan` and `/api/v1/screener/plans`: there is no natural-language screen planner and no saved-screen store on the public API. Build the plan object yourself and post it to `/api/v1/screener/execute`, or execute one of the curated plans from `/api/v1/screener/screens`\n\n---\n\n## Stocks API (`/api/v1/stocks`)\n\n### GET /api/v1/stocks/price\nLatest stock price, 15-minute delayed. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker (e.g., `AAPL`) |\n\n```bash\ncurl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\\n  \"https://app.sentisense.ai/api/v1/stocks/price?ticker=AAPL\"\n```\n\nResponse: `{ ticker, currentPrice, change, changePercent, previousClose, volume, timestamp, priceAsOf?, expiresEpochSecond, extendedHours?, listingStatus?, delistedDate?, delistingReason? }`.\n\n**A delisted symbol returns its last trade price, not an error, and `listingStatus` is what marks that price as frozen.** The three listing fields are present only when the symbol is delisted or pending delisting, and absent otherwise. `listingStatus` is `\"DELISTED\"` or `\"PENDING_DELISTING\"`; `delistedDate` is the ISO date trading stopped; `delistingReason` is one of `acquired`, `take_private`, `bankruptcy`, `exchange_rule`, `merged`. On a `\"DELISTED\"` symbol the price, change, and change percent never advance again, so do not render them as a current tick.\n\n**Prices are delayed 15 minutes.** This applies to every price on this API, in every session, including the `extendedHours` values below. Do not present these quotes as live, and do not use them for execution or for any decision that turns on the current tick.\n\nRead **`priceAsOf`** for freshness: it is when the market data behind `currentPrice` is actually from, in epoch milliseconds. Do not use `timestamp` for this. `timestamp` is when the response was served, so it tracks the current clock no matter how old the value is. `priceAsOf` is omitted outside regular hours and whenever the upstream data carries no time of its own, so treat an absent `priceAsOf` as unknown age, not as fresh, and fall back to assuming the 15 minutes.\n\n`currentPrice` is always the regular-session price: the most recent regular-session value during RTH (09:30 to 16:00 ET), and the most recent regular-session close otherwise. The optional `extendedHours` field is present whenever there is an extended-hours price to show, which is pre-market (from 04:00 ET) and from the 16:00 ET close until the next pre-market opens, weekends included: once after-hours trading stops at 20:00 ET the last print is carried forward rather than dropped. It is absent during regular hours and for a ticker that did not trade outside them. It carries `{ session: \"pre\" | \"post\", price, change, changePercent }`, where `change` / `changePercent` are computed vs `currentPrice`.\n\n### GET /api/v1/stocks/prices\nBatch latest prices, 15-minute delayed (see `/price` above). **Public.** Returns a JSON array; each element has the same shape as `/price` (including a `ticker` field, an optional `extendedHours` object, and the optional `listingStatus` / `delistedDate` / `delistingReason` fields), so check each element for a frozen price rather than assuming a batch is uniformly live.\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `tickers` | string | Yes | Comma-separated (e.g., `AAPL,TSLA,NVDA`) |\n\n### GET /api/v1/stocks/chart\nHistorical OHLCV chart data. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n| `timeframe` | string | No | `1D`, `5D`, `1W`, `1M`, `3M`, `6M`, `1Y`, `5Y`, `10Y`, `MAX` (default: `1M`) |\n\n`MAX` returns a stock's full available history, up to 26 years (AAPL: 320 monthly bars back to\n1999). Granularity scales with the range: intraday for `1D` through `1M` (5-minute for `1D`,\n15-minute for `5D`, 30-minute for `1W`, hourly for `1M`), daily for `3M` through `1Y`, weekly for\n`5Y`/`10Y`, monthly for `MAX`. Ranges of `10Y` and `MAX` are adjusted for both splits and\ndividends so the series is comparable end to end; shorter ranges (through `5Y`) are split-adjusted\nonly, so the two bases differ on the same historical date by roughly the dividends paid since.\n`volume` is on the same adjusted basis as the prices in every range (pre-split bars report shares\nin today's share count), so the volume series has no split cliff either. Every bar carries\n`adjusted: true` to mark that basis. Expect an old bar on a heavily-split stock to report a much\nlarger share count than a recent one: AAPL has split 28-for-1 since 2013, so one share of 2008 is\n28 shares now and its raw turnover is counted 28 times over. On the monthly series that puts a 2008\nbar near 24 billion shares against roughly 1 billion for a recent month. That is the restatement,\nnot an error.\n\n`10Y` and `MAX` may answer `202 Accepted` with an empty array and a `Retry-After` header, meaning\nthat stock's deep history is still being assembled; retry and you get the full series. A `200`\nalways carries the range you asked for, never a silently shortened one. An unrecognized\n`timeframe` value answers `400` with an `invalid_timeframe` error naming the valid values.\n\nEach bar includes `timestamp` (Unix ms), `date`, `open`, `high`, `low`, `close`, `volume`, `adjusted` (always `true`), and `session`. The `session` field is `pre` (04:00 to 09:30 ET), `regular` (09:30 to 16:00 ET), or `post` (16:00 to 20:00 ET) for intraday timeframes (`1D`, `5D`, `1W`, `1M`); it is `null` for daily, weekly, and monthly bars (`3M` and longer) that span whole sessions. The `1M` timeframe is filtered to `regular`-session bars only.\n\n### GET /api/v1/stocks\nList all tracked ticker symbols. **Public.**\n\n### GET /api/v1/stocks/detailed\nAll stocks with company name, KB entity ID, URL slug, and precomputed `socialDominance` (`{ value, rank, percentile }`, daily refresh, null when no signal). **Public.**\n\n**Example:** sort the universe by share of voice without any second request, or filter by `socialDominance.rank <= 50` for the top-50 most discussed names.\n\n### GET /api/v1/stocks/popular\nPopular stock tickers. **Public.**\n\n### GET /api/v1/stocks/popular/detailed\nPopular stocks with company details. **Public.** Rows carry the same keys as `/detailed`. Check `socialDominance` before you sort or filter this list by share of voice: where it is `null` on a row, read it from `/detailed` by `ticker`.\n\n### GET /api/v1/stocks/images\nCompany logo URLs. **Public.** `GET` a returned URL to receive the image bytes; no API key is needed for the image fetch itself. Treat the URLs as refreshable rather than permanent: brand assets are periodically refreshed, so re-read them from this endpoint instead of storing them long term.\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `tickers` | string | Yes | Comma-separated tickers (max 600) |\n\n### GET /api/v1/stocks/descriptions\nCompany profiles with branding, industry, and market cap; `sector` when available (often absent). **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `tickers` | string | Yes | Comma-separated tickers |\n\n### GET /api/v1/stocks/{ticker}/profile\nCompany profile (CEO, sector, industry). **Public.**\n\nAlso carries `listingStatus`, `delistedDate` and `delistingReason` when the symbol is delisted or pending delisting. All three are absent for a normally listed symbol. Values match `/price` above: `listingStatus` is `\"DELISTED\"` or `\"PENDING_DELISTING\"`, `delistedDate` is the ISO date trading stopped, `delistingReason` is one of `acquired`, `take_private`, `bankruptcy`, `exchange_rule`, `merged`.\n\nFor a tracked ETF ticker, the profile may also carry `imageUrl`, a square presentation image for the fund. It is the issuer's mark rather than the individual fund's, so every fund in a family shares one image, and it matches the `imageUrl` returned by the `/etfs` endpoints. It is square like `logoUrl` and `iconUrl`, so the same avatar slot renders a stock and an ETF, but it is a first-party asset rather than a vendor branding mark and is returned as a direct URL. It is absent for issuers we hold no image for.\n\n### GET /api/v1/stocks/{ticker}/similar\nPeer/similar stocks. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `limit` | int | No | 5 | Max results |\n\nResponse: bare array of `{ symbol, name, price, changePercent }`. The key is `symbol`, not `ticker`, and the array can hold fewer than `limit` entries.\n\n### GET /api/v1/stocks/{ticker}/sentiment\nOne-call sentiment picture for a stock: the SentiSense Score with its 30-day regime, where the conversation is happening by source, and what is driving it. **Public.** **Quota-gated** when called with a key.\n\nThis endpoint also answers without an API key, and returns the same full payload either way. The tradeoff is real in both directions: a keyed call is attributed to your account but spends monthly quota and per-minute rate limit, while a keyless call costs you neither and is not attributed. Send the key when you want the usage on your account; either way the data is identical.\n\nResponse: `{ isPreview, previewReason, data }`. Everything below lives under `data`, which carries `ticker`, `companyName`, `asOf`, then the fields in the table. This endpoint is Free but still uses the wrapper (`isPreview` is `false` and `previewReason` is `null` on every tier), so unwrap first: reading `sentisenseScore` off the root returns nothing, and the full path is `data.sentisenseScore`.\n\n| Field (under `data`) | Type | Description |\n|-------|------|-------------|\n| `sentisenseScore` | number or null | Today's Score (0-centered composite of sentiment and mentions, unbounded). Null until today's reading lands, see the note below |\n| `sentisenseScoreAvg30d` | number | 30-day average, the stable regime figure |\n| `sentisenseScoreDelta30d` | number | Change over 30 days |\n| `scoreLabel` | string | Seven-band label of the 30-day average |\n| `direction` | string | `Bullish`, `Neutral` or `Bearish`, from the 30-day average |\n| `latestDirection` | string or null | Same three bands, from today's read. Null in lockstep with `sentisenseScore` |\n| `trend` | string | `UP`, `DOWN` or `FLAT` |\n| `scoreSparkline` | number[] | Daily Score series |\n| `mentions` / `mentionsAvg30d` | number | Mention volume of the latest New York daily bucket with data (today's once it lands, otherwise an earlier day; `narrative` names which), and the 30-day daily average |\n| `socialDominance` | number | Latest share of voice, as a fraction (`0.021` = 2.1%) |\n| `bySource[]` | array | Per-source tone, loudest first: `source` (`News`, `Reddit`, `X`, `YouTube`, `Hacker News`, `Substack`), `direction`, `mentionShare` (whole-number percent; rounding can make the array sum to 99 or 101 rather than exactly 100), `value` (per-source polarity, -1 to +1) |\n| `relatedTickers[]` | array | Curated peers: `ticker`, `name` |\n| `drivers[]` | array | Top story drivers: `title`, `tone` (-1 to +1) |\n| `narrative` | string | Plain-language summary of why the Score sits where it does |\n| `faq[]` | array | `question` / `answer` pairs for the common asks on this ticker |\n\nUse this when you want the headline read in one call. Use `GET /api/v2/metrics/entity/{ticker}/metric/sentisense` instead when you need the Score as a time series over a specific window. Returns `404` when the ticker has no sentiment coverage.\n\n**`sentisenseScore` and `latestDirection` are today's reading, and are `null` until the day's first analytics run lands** (mid-morning ET, later at weekends). Poll before that and every ticker returns null for these two, which is a timing state and not an outage. The rest of the response is unaffected: `scoreLabel`, `direction` and `sentisenseScoreAvg30d` are all computed from the 30-day average, so prefer those when you need a headline that is always present. A null here means \"no reading yet\", never a Score of zero. A measured 0.0 is served as `0.0`, so do not coerce null to 0, and do not infer absence by thresholding the 30-day average, which would suppress genuine neutrals.\n\nAggregate metrics such as sentiment and mention counts incorporate signals from sources that are not individually retrievable as documents, so document counts from the Documents API are not a complete audit trail of a score.\n\n> Via the MCP connector this same picture comes back from the `get_stock_snapshot` tool rather than a separate sentiment tool.\n\n\n### GET /api/v1/stocks/{ticker}/entities\nRelated ontology entities (CEO, products, partners). **Public.** Each entry carries a `urlSlug` (e.g. `Tim-Cook`) that plugs into the Metrics API `{entityId}` parameter. It is a flat list: for the relationship behind each link, use the graph endpoint below.\n\n### GET /api/v1/stocks/{ticker}/graph\nOne company's neighborhood in the SentiSense ontology as a typed graph: the people, products, product families, peer companies and organizations the knowledge base connects to that ticker, plus the named relationship between each pair. **Public** (API key required). One ticker per call; there is no listing or enumeration form.\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `depth` | integer | No | `1` | `1` or `2`. `1` returns the company's own people, products and peers; `2` walks one hop further, which is how an organization behind a person appears. Anything else returns `400 invalid_depth`. Send it explicitly so the walk you describe is the walk you asked for |\n| `cap` | integer | No | `75` | `1` to `200`, the maximum number of non-root nodes returned. Anything else returns `400 invalid_cap`. Send it explicitly for the same reason |\n\nResponse: a flat object, no `{isPreview, data}` wrapper.\n\n| Field | Type | Notes |\n|-------|------|-------|\n| `ticker` | string | The normalized ticker |\n| `root` | string | The root company's slug. The root is also the first entry in `nodes` |\n| `depth`, `cap` | integer | The values the walk was asked for, echoed back. `depth` is what you requested, not how far the walk reached |\n| `truncated` | boolean | `true` when `cap` cut the walk short. The survivors are ordered by node type then name, not by importance, so a truncated response can drop people and products while keeping peers |\n| `counts` | object | `{nodes, edges, byType}`, where `byType` maps a node type to how many of it came back |\n| `omitted` | integer | Nodes left out for carrying no slug, and so not addressable. Normally `0` |\n| `groups` | object | `people`, `products`, `productFamilies`, `peers`, `organizations`, `publishers`, `topics`. Every one is a list of **slugs** except `productFamilies`, which is a list of `{family, members}`. A slug is the same handle the Metrics API takes, so you can query one straight from `groups`; join it to `nodes` when you need its `displayName` or `type` |\n| `nodes` | array | `{slug, displayName, type}`. `type` is uppercase (`COMPANY`, `PERSON`, `PRODUCT_OR_SERVICE`, `ORGANIZATION`, `PUBLISHER`, `TOPIC`), and `slug` is the Metrics API `{entityId}` handle |\n| `edges` | array | `{source, target, type, direction, properties}`, both ends slugs. `type` is one of `LEADS`, `FOUNDED`, `PRODUCT_OF`, `VARIANT_OF`, `PEER`, `OWNS`, `SUBSIDIARY_OF`, `SUBTOPIC_OF`, `BELONGS_TO`, `AFFILIATED_WITH`. `direction` is `DIRECTED` or `BIDIRECTIONAL`; on a `BIDIRECTIONAL` edge the order carries no meaning. `properties` is a flat string map and is often empty |\n\nAn unknown or unlisted ticker returns `404 entity_not_found` with up to three `suggestions`, which is a different answer from `/entities`, where an unknown ticker returns `200 []`. The response carries no sentiment, Score or mention counts: fetch those per handle from the Metrics API.\n\n`publishers` and `topics` are part of the response shape but are not reachable from a company root today, so treat an empty list there as the expected state rather than as missing theme coverage.\n\n### GET /api/v1/stocks/{ticker}/ai-summary\nAI-generated stock analysis report. **PRO** (Free: `depth=basic` unlimited, `depth=deep` limited to 10/month). `depth=basic` returns a preheader summary. `depth=deep` returns a full multi-section report. Exhausting the `depth=deep` monthly view allowance returns `429` with `{error: \"quota_exceeded\", ...}`, the same contract as every other quota-gated endpoint.\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `depth` | string | No | `basic` | `basic` or `deep` |\n\nResponse: flat object (no `{isPreview, data}` wrapper).\n\n| Field | Type | Notes |\n|-------|------|-------|\n| `ticker` | string | |\n| `companyName` | string | |\n| `status` | string | `READY`, `NOT_AVAILABLE`, or `ERROR` |\n| `statusReason` | string or null | Present on `NOT_AVAILABLE` / `ERROR` only |\n| `reportType` | string | `SUMMARY` for `depth=basic`, `FULL` for `depth=deep` |\n| `version` | integer | Report date encoded as yymmdd (e.g. 260520) |\n| `lastUpdated` | long | Epoch milliseconds |\n| `sections` | object | Section name to `{content, directives}`. Present on both depths: `depth=basic` returns a single `Executive Summary` section, `depth=deep` returns the full set. |\n| `sectionOrder` | string[] | Ordered section keys for rendering. Present on both depths; `[\"Executive Summary\"]` on `depth=basic`. |\n| `fromCache` | boolean | Whether this response was served from the report cache. `false` also covers a report served straight from the packaged knowledge base, so it does not mean the report was regenerated for your call: read freshness from `lastUpdated`. |\n| `moatRating` | integer or null | Proprietary moat quality score 0-10 (network effects, switching costs, intangibles, cost advantages, efficient scale). Present on `depth=deep` only. Null if not yet assessed for this ticker. |\n| `aiDisruptionRisk` | string or null | `Low`, `Medium`, `High`, or `Critical`. Measures AI revenue-displacement exposure. Present on `depth=deep` only. Null if not yet assessed. |\n\n**Do not test for the presence of `sections` to detect a deep report:** both depths return it. Branch on `reportType` (`SUMMARY` vs `FULL`) instead.\n\n### GET /api/v1/stocks/{ticker}/metrics/{metricType}/breakdown\nSentiment or mention metrics breakdown by sub-entities. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `metricType` | path | Yes | `sentiment` or `mentions` |\n| `startTime` | long | Yes | Start time in epoch ms |\n| `endTime` | long | Yes | End time in epoch ms |\n\n### GET /api/v1/stocks/market-status\nCurrent market open/closed status. **API key required.**\n\nResponse: `{ status: \"open\" | \"closed\", timestamp: <epoch_ms> }`. The `timestamp` is a numeric epoch milliseconds value (not a string).\n\n### GET /api/v1/stocks/fundamentals\nFinancial statement data. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `timeframe` | string | No | `quarterly` | `quarterly` or `annual` |\n| `fiscalPeriod` | string | No | - | e.g., `Q4` |\n| `fiscalYear` | int | No | - | e.g., `2024` |\n\n**Reporting currency (applies to every fundamentals endpoint):** figures are as reported by the\nfiler, in the filer's own currency, never converted to USD. Foreign ADR filers report in home\ncurrency (SK hynix: KRW, Toyota: JPY, ASML: EUR). The optional `reportedCurrency` field (\"USD\",\n\"KRW\", ...) on the response (and on each `/fundamentals/history` row) names it; when absent the\ncurrency is unknown, not implicitly USD. Never mix these figures with the share price: the price\nis the USD ADR price, so for non-USD filers `peRatio` / `psRatio` / `pbRatio` are served as\n`null` on purpose, and you should not recompute them. Same-currency ratios (margins, ROE, ROA,\ncurrent ratio, debt/equity) stay valid for all filers.\n\n### GET /api/v1/stocks/fundamentals/current\nTrailing-twelve-month valuation snapshot against the latest price. **Public.** It is not a statement snapshot: for income-statement, balance-sheet and cash-flow lines use `/fundamentals` or `/fundamentals/history`.\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n\nResponse (flat): `{ ticker, currentPrice, peTTM, psTTM, epsTTM, revenueTTM, quartersIncluded, available, reason, fetchedAt, reportedCurrency? }`. `peTTM` and `psTTM` are the latest price over trailing EPS and over trailing revenue per share; `quartersIncluded` is how many quarters the trailing figures sum (normally 4); `fetchedAt` is epoch seconds. When `available` is `false`, `reason` says why (no current price, or no trailing earnings data) and the TTM fields are null. `reportedCurrency` names the currency of `epsTTM` and `revenueTTM` (`currentPrice` stays USD) and is omitted when unknown; for a non-USD filer `peTTM` and `psTTM` are `null` by design, the same cross-currency rule as above.\n\n### GET /api/v1/stocks/fundamentals/history\nMulti-period history of full financial statements (income statement, balance sheet, cash flow), one\nentry per fiscal quarter or year, newest first. Use for margin trends, multi-year comparisons, or as\nthe input to a valuation model. Not the same endpoint as `/fundamentals` (single period) or\n`/fundamentals/historical/revenue` (income-statement lines only, no balance sheet or cash flow). **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `timeframe` | string | No | `quarterly` | `quarterly` or `annual` |\n| `limit` | int | No | 12 quarterly / 10 annual | Periods to return, capped at 40 quarterly / 20 annual |\n\nResponse includes `count` (periods actually returned, can be less than `limit`), `reason`\n(non-null only when `periods` is empty, e.g. a recent listing), and `dataSource` (deprecated:\nalways an empty string, kept for response-shape compatibility, slated for removal).\n\n**Earnings and share-count fields** (same on `/fundamentals`). These are reported independently by\nthe data provider. They are NOT derived from one another and will NOT reconcile arithmetically:\n`netIncome / weightedAverageSharesDiluted` does not reproduce any EPS field, because the provider\ncomputes EPS from its own numerator on its own share basis. Do not \"check\" our data by dividing\nthese, and do not present a computed per-share figure as if it were the reported one.\n\n| Field | Meaning |\n|---|---|\n| `epsBasic` | Basic EPS. Always basic, on every source. |\n| `epsDiluted` | Diluted EPS. Null when the provider reports no diluted figure. |\n| `eps` | EPS as the provider reports it, usually basic. Prefer `epsBasic`/`epsDiluted`, which name their basis. |\n| `netIncome` | Consolidated net income. Not the EPS numerator. |\n| `bottomLineNetIncome` | The provider's bottom-line income line, which can differ from `netIncome` in size and in sign. Null means the line was not supplied for that period, not that it equals `netIncome`. |\n| `weightedAverageSharesBasic` | Basic weighted-average shares for the period. Null when not reported. |\n| `weightedAverageSharesDiluted` | Diluted weighted-average shares for the period. Null when not reported. |\n| `sharesOutstanding` | **Deprecated, stops being populated 2026-12-15.** Not a period-end count despite the name. Use the weighted-average fields. |\n\nBoth share fields are averages ACROSS the period, not counts at period end, so neither is a correct\ninput to a market capitalisation or a book value per share; a share field is null when the provider\nreports no count on that basis or a count of zero or below. Income fields are in the filer's reporting\ncurrency (see `reportedCurrency`), EPS is that currency per share, share fields are a number of\nshares. Per-period EPS is served as the provider reports it, and we restate it for a small list of named issuers and nowhere else: where a provider restated a company's share counts for a split but left older rows' EPS on the pre-split basis, and that has been checked against the company's own filing, we divide the EPS on the affected rows by the split ratio and mark each one with `epsBasisRepair` (`fields`, `multiplier`, `splitExecutionDates`). Share counts and net income are never changed. `epsBasisRepair` is null on almost every row, and null means we applied no EPS repair to that row: it is NOT a statement that the row's EPS and share count are on the same basis, since an unlisted issuer, a row that did not qualify, and a row whose split history we could not read all carry null. `epsBasisRepair` describes per-period EPS only: this repair never changes `epsTTM` or the other trailing-twelve-month figures, and the marker never describes a trailing adjustment. Trailing figures are assembled separately and whether they carry a split adjustment of their own depends on which source served them. For a small list of recently listed companies, quarterly history also includes a pre-IPO quarter the company filed only as the prior-year comparison column of a later filing, usually its first 10-Q: that row carries `preIpoFiling` (`form`, `accession`, `filedDate`, `note`) naming the filing, holds the income-statement lines only, and gives way to the provider's own row for the same period once one exists. `preIpoFiling` is null on every other row.\n\n### GET /api/v1/stocks/fundamentals/periods\nAvailable fiscal periods. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n\n### GET /api/v1/stocks/fundamentals/historical/revenue\nHistorical income-statement lines per period: revenue, gross profit, operating income, net income,\nand EPS. Response wraps them in `dataPoints` (not `periods` like `/fundamentals/history`), plus\n`count`, `dataSource`, and `reason`. For full statements including balance sheet and cash flow,\nuse `/fundamentals/history` instead. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `timeframe` | string | No | `quarterly` | `quarterly` or `annual` |\n\n### GET /api/v1/stocks/short-interest\nShort interest data from FINRA. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `limit` | int | No | 24 | Max data points |\n\n### GET /api/v1/stocks/float\nFloat information (shares outstanding, public float). **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n\n### GET /api/v1/stocks/short-volume\nShort volume trading data. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `limit` | int | No | 90 | Max data points |\n\n### GET /api/v1/stocks/{ticker}/quote\nAggregate quote snapshot: latest price (15-minute delayed), today OHLC, 52-week range, market cap, P/E, EPS TTM, dividend yield, 200-day moving average. Single call for detail pages. **API key required.**\n\nResponse: `{ ticker, currentPrice, change, changePercent, volume, open, dayHigh, dayLow, previousClose, week52High, week52Low, marketCap, peRatio, epsTTM, dividendYield, movingAverage200Day, reportedCurrency, timestamp, extendedHours?, listingStatus?, delistedDate?, delistingReason? }` -- all fields except `ticker` are nullable. `currentPrice` is always the regular-session price; the optional `extendedHours` object (`{ session, price, change, changePercent }`) is present outside regular hours whenever an extended-hours price exists, and `session` stays `\"post\"` while the last after-hours print is carried overnight and through the weekend. `movingAverage200Day` is `null` when fewer than 200 trading days of history exist. `reportedCurrency` (\"USD\", \"EUR\", \"KRW\", ...) names the currency `epsTTM` is reported in, matching the fundamentals endpoints. Responses carry a private 15 s `max-age`; the server's own price cache is 30 s, per process.\n\n**Null fields are omitted, and foreign filers omit `peRatio`.** A null field is left out of the JSON entirely rather than serialized as `null`, so do not assume a key is present: read defensively. On foreign ADR filers such as `ASML` and `TM`, `peRatio` is absent, while `epsTTM` is served in the filer's home currency and `reportedCurrency` names that currency (`EUR` for ASML, `JPY` for TM, whose `epsTTM` reads in the thousands beside a USD price near 200). Price fields and `dividendYield` are served normally. This is the same cross-currency rule as the fundamentals endpoints: the price is the USD ADR price and the filer's earnings are in home currency, so `peRatio` is withheld rather than computed across two currencies. Always check `reportedCurrency` before using `epsTTM`, and do not divide `currentPrice` by a non-USD `epsTTM` to fill the gap yourself.\n\n**Delisted symbols keep quoting their last trade.** `listingStatus`, `delistedDate` and `delistingReason` are present only when the symbol is delisted or pending delisting, and absent otherwise, with the same values as `/price`. When `listingStatus` reads `\"DELISTED\"`, every price field in this payload is frozen at the last trade before `delistedDate` and nothing else in the response says so.\n\nETF tickers (e.g. `VTI`, `SPY`) return `400 ticker_is_etf` from this endpoint. Use `GET /api/v1/etfs/{ticker}/quote` instead, which returns AUM, expense ratio, NAV, and inception date rather than market cap, P/E, and EPS.\n\n\n### GET /api/v1/stocks/{ticker}/kpis\nCompany-specific KPI time-series. Curated GAAP and non-GAAP metrics from earnings filings: iPhone unit sales, Tesla deliveries, AWS revenue, Netflix paid net adds, etc. **PRO (preview)** -- Free: metadata only with empty `kpis` list, PRO: full series. Returns 404 for tickers without curated coverage.\n\nCoverage today: near-complete for the S&P 500 plus an extended universe of 900+ US-listed companies (970 tickers as of 2026-09-09). Use `GET /api/v1/stocks/with-kpis` to enumerate.\n\nResponse wrapper: `{ isPreview, previewReason, data: CompanyKpis }`.\n\n`CompanyKpis` shape: `{ ticker, companyName, cik, lastUpdated, kpis: KpiSeries[] }`.\n\n`KpiSeries` shape: `{ id, name, category, unit, displayFormat, chartType, values: KpiDataPoint[], sourceRef, discontinued, discontinuedNote }`. `id` is a stable per-ticker identifier (e.g. `iphone_revenue`). `category` is one of `product_revenue`, `segment_revenue`, `unit_economics`, etc. `chartType` is `bar` or `line`.\n\n`KpiDataPoint` shape: `{ period, date, value, isEstimate }`. `period` is the fiscal label (e.g. `Q2 FY2026`); `date` is the ISO close date.\n\nPass ticker, selected KPI IDs and any fetched response to the `company-kpi-tracker` skill; return a dated card with matched deltas and source and estimate flags.\n\n### GET /api/v1/stocks/with-kpis\nList every ticker with curated KPI coverage. Sorted alphabetically. Builder discovery: render a supported-tickers page or seed a watchlist without 404-probing one ticker at a time. **Discovery (no quota cost)** -- API key required for identity/abuse tracking, but the call does not consume your monthly quota. Rate-limit-per-minute still applies.\n\nResponse: `{ count, tickers: KpiCoverageEntry[] }` where each entry is `{ ticker, companyName, lastUpdated, kpiCount }`.\n\n```python\nclient = SentiSenseClient(api_key=os.environ[\"SENTISENSE_API_KEY\"])\ncoverage = client.list_kpi_coverage()\nprint(f\"{coverage.count} tickers covered\")\nfor entry in coverage.tickers[:5]:\n    print(f\"  {entry.ticker}: {entry.kpiCount} KPIs (refreshed {entry.lastUpdated})\")\n```\n\n### GET /api/v1/stocks/{ticker}/kpis/types\nLightweight KPI metadata tuples for a ticker, without the full series payload. Mirrors `/api/v1/insights/stock/{ticker}/types`. Useful for letting an agent or UI decide what to fetch before committing to the heavy data call. **Discovery (no quota cost)** -- API key required, no quota burn.\n\nResponse: bare array of `{ id, name, category, chartType }`. Returns 404 if the ticker has no curated KPIs.\n\n```python\ntypes = client.get_kpi_types(\"AAPL\")\nfor t in types:\n    print(f\"  {t.id} ({t.chartType}): {t.name}\")\n```\n\n---\n\n## Entities API (`/api/v1/kb`)\n\n### GET /api/v1/kb/entities/search\nSearch the SentiSense ontology for the people, companies, products, and organizations SentiSense tracks, and get the handle to query their metrics. **Public** (API key required).\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `q` | string | Yes | - | Name, alias, ticker, or slug fragment (case-insensitive, minimum 2 characters) |\n| `type` | string | No | all | `company`, `country`, `etf`, `organization`, `person`, `product`, `topic` |\n| `limit` | int | No | 10 | Max results (capped at 25) |\n\n**Response:** array of `{name, urlSlug, type, ticker}` matches, best first. `ticker` is null for entities without one. Feed the `urlSlug` (or `ticker`) into the Metrics API `{entityId}` parameter:\n\n```\nGET /api/v1/kb/entities/search?q=pelosi -> [{\"name\": \"Nancy Pelosi\", \"urlSlug\": \"Nancy-Pelosi\", \"type\": \"person\", \"ticker\": null}]\nGET /api/v2/metrics/entity/Nancy-Pelosi/metric/sentisense\n```\n\nPeople, products, and organizations have the same metrics surface as stocks, so this unlocks queries like a politician's mention volume, a CEO's SentiSense Score (`.../entity/Jensen-Huang/metric/sentisense`), or crowd sentiment on a product versus its parent ticker.\n\n### GET /api/v1/kb/entities/popular\nCurated list of high-profile tracked entities (major CEOs, political figures, the Federal Reserve). **Public** (API key required). Returns `{displayName, type, urlSlug, relatedStock}` entries; use as an autocomplete seed list without issuing a search.\n\n## Metrics API (`/api/v2/metrics`)\n\nTime series metrics for stocks and entities: mentions, sentiment, social dominance, and more. The `{entityId}` path segment accepts a stock ticker (e.g. `AAPL`) or an entity `urlSlug` (e.g. `Nancy-Pelosi`); both are case-insensitive, and a ticker-shaped identifier always means the listed company. Discover handles with `GET /api/v1/kb/entities/search?q=` or `GET /api/v1/stocks/{ticker}/entities`. An unknown identifier returns `404 entity_not_found` with up to three `suggestions`.\n\nWhich handle to store: the `urlSlug`, or the ticker for a listed company. It is the only identifier these paths accept. Internal KB ids, in any spelling (`kb/person/65`, `kb-person-65`, `p65`), are not part of the public API and resolve to nothing. If a rename ever breaks a stored handle, find the entity again by name with `GET /api/v1/kb/entities/search?q=`.\n\nEvery metric type (`mentions`, `sentiment`, `sentisense`, `social_dominance`, `sentisense_rating`, `app_review_count`, `app_rating`) is available on the Free tier: no PRO subscription needed. All metrics endpoints are **Quota-gated**: an API key is required and each request counts against your monthly quota (Free: 1,000 requests/month; PRO: no monthly cap). Per-minute rate limits apply on every tier.\n\n### GET /api/v2/metrics/entity/{entityId}/metric/{metricType}\nTime series metric data for a stock or entity. **Quota-gated** -- all metric types (`mentions`, `sentiment`, `sentisense`, `social_dominance`, `sentisense_rating`, `app_review_count`, `app_rating`) are available on the Free tier. `sentisense_rating` is stocks-only and its `value` is the daily Rating score, 0 to 100, which is the number the letter is banded from and not the percentile; see the SentiSense Rating API section below.\n\nWhat each metric type means:\n\n- `mentions` -- count of documents that ment\n\nFile v2.21.1:_meta.json\n\n{\n  \"ownerId\": \"kn71ca3nrt3w6w0v3nhv3c4tan82x1ym\",\n  \"slug\": \"sentisense\",\n  \"version\": \"2.21.1\",\n  \"publishedAt\": 1790896335426\n}\n\nFile v2.21.1:skill-card.md\n\n## Description:\n\nProvides read-only US stock market data and insights, including prices, sentiment, ratings, filings, options, and earnings through the SentiSense API.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[thesentitrader](https://clawhub.ai/user/thesentitrader)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, research analysts, and other users can query US equity prices, news sentiment, insider and congressional trades, institutional holdings, and AI-generated market insights for informational research. The skill does not place trades or provide investment advice.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The SentiSense API key may be disclosed or used outside its intended service.\n\nMitigation: Keep the key in the environment, send it only to the documented SentiSense API, and never include it in responses.\n\nRisk: Personalized insights may reveal a user's watchlist or portfolio interests to the service and agent context.\n\nMitigation: Call the personalized insights endpoint only when the user explicitly requests account-specific results.\n\nRisk: Delayed market quotes or generated insights may be mistaken for real-time prices or investment advice.\n\nMitigation: Label quote delays, check data timestamps, and present results as informational rather than trade recommendations.\n\n## Reference(s):\n\n- [SentiSense on ClawHub](https://clawhub.ai/thesentitrader/skills/sentisense)\n- [SentiSense API documentation](https://sentisense.ai/docs/api/)\n- [SentiSense methodology](https://sentisense.ai/methodology/)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Guidance]\n\n**Output Format:** [Markdown research summaries, JSON API data, and optional curl or client examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read-only; requires SENTISENSE_API_KEY; stock prices are approximately 15 minutes delayed.]\n\n## Skill Version(s):\n\n2.21.1 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v2.21.0: 3 files, 73590 bytes\n\nFiles: skill-card.md (2488b), SKILL.md (206054b), _meta.json (130b)\n\nFile v2.21.0:SKILL.md\n\n---\nname: sentisense\ndescription: \"US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers every endpoint. Use for stock sentiment API, stock market API, stock rating API, stock letter grade, insider trading data, congress stock trades, 13F holdings, options flow, earnings calendar, stock price API, market data for AI agents. Read-only. No trading, no purchases, no write operations, no wallet access.\"\nhomepage: https://sentisense.ai\nrequires:\n  env:\n    - SENTISENSE_API_KEY\nprimaryEnv: SENTISENSE_API_KEY\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - SENTISENSE_API_KEY\n    primaryEnv: SENTISENSE_API_KEY\n---\n\n# SentiSense API - Skill File for AI Agents\n\n> **SentiSense** is a read-only financial intelligence API: stock prices, insider/politician trading, institutional flows, AI insights, and news sentiment. No trading, no purchases, no write operations. Free tier available.\n\n**Base URL:** `https://app.sentisense.ai`\n**Website:** https://sentisense.ai\n**ClawHub Skill:** [clawhub.ai/TheSentiTrader/sentisense](https://clawhub.ai/TheSentiTrader/sentisense)\n**API Docs:** https://sentisense.ai/docs/api/\n**Authentication:** API key via `X-SentiSense-API-Key` header. Get a free key at https://app.sentisense.ai/get-api-key\n**SDKs (optional):** [Python](https://github.com/SentiSenseApp/sentisense) | [Node.js](https://github.com/SentiSenseApp/sentisense-node) -- source on GitHub. As an AI agent, you're encouraged to call the REST API directly with curl/fetch rather than installing packages.\n\n---\n\n## Use & Disclaimer\n\nThis skill is an **educational data interface** to SentiSense's read-only Data API. Output is informational only. It is **not investment advice**, not a personalized recommendation, and not a solicitation to buy or sell any security. The user is responsible for their own decisions. Use of the API and this skill is subject to the [API Terms of Service](https://sentisense.ai/agreement/API-Terms-of-Service.pdf) and [Terms of Service](https://sentisense.ai/agreement/Terms-of-Service.pdf).\n\n---\n\n## Authentication\n\n```bash\n# Include API key in header\ncurl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\\n  \"https://app.sentisense.ai/api/v1/...\"\n```\n\n**Identify your client.** Send a `User-Agent` naming your agent runtime and this skill, for\nexample `OpenClaw/1.4 (sentisense)` or `ClaudeCode/2.1 (sentisense)`. Substitute your own runtime and\nversion if neither matches. You can also volunteer what your agent is called by adding an\n`agent/<your-agent-name>` token inside the same parentheses, as in\n`OpenClaw/1.4 (sentisense; agent/research-desk)`. All of it is optional, and it is what tells\nus this skill has real integrations behind it, so it gets prioritized and you get notice before it\nchanges.\n\n```python\nimport os\nfrom sentisense import SentiSenseClient\nclient = SentiSenseClient(api_key=os.environ[\"SENTISENSE_API_KEY\"])\n```\n\nAll API endpoints require an API key. Get one free at https://app.sentisense.ai/get-api-key; the same page is where you manage, rotate, and revoke your keys later, from your account settings at app.sentisense.ai.\n\n## Permissions\n\n- Network: HTTPS to app.sentisense.ai only.\n- Credentials: SENTISENSE_API_KEY from the environment.\n- Shell: none required.\n- Files: none.\n\n### Command-line client\n\nThe REST recipe in this file is the primary path. A maintained command-line client is available as the separate `sentisense-cli` skill for hosts that prefer one.\n\n### Access Tiers\n\n| Badge | Meaning |\n|-------|---------|\n| **Public** | Available on all tiers (Free and PRO) |\n| **Public (preview)** | Free gets limited preview; PRO gets full data |\n| **Quota-gated** | Consumes monthly quota (Free: limited, PRO: unlimited) |\n| **Discovery (no quota cost)** | API key required (identity/abuse tracking), but the call does not burn your monthly quota. Rate-limit-per-minute still applies. Used for lightweight metadata endpoints like `/stocks/with-kpis` and `/stocks/{ticker}/kpis/types`. |\n| **PRO only** | Requires PRO subscription |\n\n### Rate Limits\n\n| Tier | Requests/Month | Rate |\n|------|----------------|------|\n| Free | 1,000 | 30 requests/minute |\n| PRO ($15/mo) | Unlimited | 300 requests/minute |\n| Pro Max | Unlimited | 1,500 requests/minute |\n| Data License (Essentials, Premium) | Unlimited | 2,000 requests/minute |\n\nPro Max and the Data License plans include every PRO feature; the API reports their tier as `PRO`.\n\n### Ticker Symbols\n\nEndpoints that take a `{ticker}` path parameter accept the canonical primary ticker for each company. For dual-class share companies, the API also accepts the secondary class as an alias and resolves it server-side, so you can pass whichever ticker your data source provides.\n\n| You pass | Resolves to | Reason |\n|----------|-------------|--------|\n| `GOOG` | `GOOGL` | Alphabet Class C resolves to Class A |\n| `BRK.A`, `BRK-A`, `BRKA` | `BRK.B` | Berkshire Class A resolves to Class B |\n| `BRK-B`, `BRKB` | `BRK.B` | Punctuation variants normalized |\n\nAliasing applies to research endpoints (analyst, KPIs, insights, insider, institutional holders, politicians filings, options). Quote and chart endpoints leave the ticker as-is, since market-data providers handle their own symbology. Tickers are case-insensitive. News Corp (`NWSA`/`NWS`) and Fox (`FOXA`/`FOX`) are NOT aliased to each other (each class is tracked separately).\n\n---\n\n## What You Can Build\n\n### Smart Money Tracker\nCross-reference insider trading, institutional flows, and politician trades to follow where the smart money is moving. High-conviction signals come from convergence across all three.\n- `GET /api/v1/insider/activity` for market-wide insider buying/selling\n- `GET /api/v1/institutional/flows` for quarterly institutional positioning (optional `reportDate`; omit for the latest quarter)\n- `GET /api/v1/politicians/activity` for congressional STOCK Act trades\n- `GET /api/v1/insights/stock/{ticker}` for AI signals that combine these data sources\n\n### Sentiment-Driven Watchlist\nAlert when sentiment shifts for your stocks. Track news volume, social mentions, and baseline deviations.\n- `GET /api/v2/metrics/entity/{ticker}/metric/sentisense` for the SentiSense Score time series (prefer it over `sentiment`; see the metric notes below)\n- `GET /api/v2/metrics/entity/{ticker}/baselines/sentiment` for anomaly detection against historical and peer baselines\n- `GET /api/v1/documents/ticker/{ticker}` for the underlying news and social posts driving the shift\n\n### Congressional Trade Monitor\nTrack what Congress is buying before it moves. Filter by party, chamber, or individual politician. Check if corporate insiders agree.\n- `GET /api/v1/politicians/activity` for recent congressional trades across all members\n- `GET /api/v1/politicians/member/{slug}` for individual politician profiles and trade history\n- `GET /api/v1/insider/trades/{ticker}` to cross-reference with corporate insider activity on the same stock\n\n### AI Research Assistant\nGenerate stock research reports by combining multiple data signals into a single analysis.\n- `GET /api/v1/stocks/{ticker}/ai-summary?depth=deep` for the full AI analysis report\n- `GET /api/v1/insights/stock/{ticker}` for AI-generated stock signals\n- `GET /api/v1/stocks/fundamentals?ticker={ticker}` for a single period of financial statement data\n- `GET /api/v1/stocks/fundamentals/history?ticker={ticker}&timeframe=annual&limit=10` for multi-year revenue, margin, and free-cash-flow trend to support valuation work\n- `GET /api/v1/documents/ticker/{ticker}` for recent news context\n\n### Earnings Calendar Monitor\nPosition ahead of earnings instead of reacting to them. Pull the forward calendar, intersect it with a watchlist, and pre-load sentiment and smart-money context for the companies reporting soon.\n- `GET /api/v1/calendar/earnings?week=next` for who reports next week (or `?from=&to=` for a custom window)\n- `GET /api/v1/calendar/earnings?ticker={ticker}` for a single name's next report date and consensus EPS (on a FREE key this searches only the current Monday-to-Sunday week; see the Calendar section)\n- `GET /api/v2/metrics/entity/{ticker}/metric/sentisense` to gauge positioning into the print\n- `GET /api/v1/insider/trades/{ticker}` to see if insiders moved ahead of the date\n\n### Market Dashboard\nMarket overview combining prices, sentiment, and top signals.\n- `GET /api/v1/stocks/market-status` to check if the market is open\n- `GET /api/v1/market-summary` for AI-generated market headline and analysis\n- `GET /api/v1/insights/market` for the top market-moving signals right now\n- `GET /api/v1/stocks/prices?tickers=SPY,QQQ,IWM,DIA` for index tracking\n\n### Cross-Signal Stock Screener\nFilter the whole tracked universe on the SentiSense Score and attention in the same query as analyst consensus, technicals and price. The differentiated screens are the disagreements: crowd bullish where the street is not, price below its 200-day while the Score is rising.\n- `GET /api/v1/screener/fields` once at startup for the filterable field catalog (stock and ETF), then build filters from it\n- `GET /api/v1/screener/screens` for 28 curated screens, each with a plan you can execute as-is\n- `POST /api/v1/screener/execute` to run a plan against the stock universe (or a `tickers` watchlist)\n- `POST /api/v1/screener/etfs/execute` for the same against the ETF universe\n\n### Market Sentiment Structure\nWhich way the market's tone leans, and how widely it's shared. Daily snapshots.\n- `GET /api/v1/sentiment/sectors` for the 11 GICS sectors vs the market's own tone (`consensusVsMarket` + \"Hotter/Cooler than market\" labels; market-relative because news tone skews positive as a genre)\n- `GET /api/v1/sentiment/breadth` for the bullish/neutral/bearish share of ~1,000 covered stocks (the sentiment advance/decline line; `netBreadth` in points, stock- and mention-weighted)\n- `GET /api/v1/trackers/sentiment-leaderboard` for the most bullish and bearish stocks ranked by their 30-day SentiSense Score, with a minimum-mention confidence floor (each row also carries the 7-day Score and raw tone polarity, which do not set the order)\n- `GET /api/v1/trackers/sentiment-movers` for the biggest SentiSense Score shifts, improving and deteriorating, ranked by the 7-day average Score minus the 30-day average (a row with no Score change falls back to its tone change)\n\n---\n\n## Agent Tips\n\n### Workflow Pattern\n1. Call `GET /api/v1/stocks/market-status` first to check if the market is open\n2. Call `GET /api/v1/institutional/quarters` before the institutional endpoints that need a `reportDate` to get valid values (`/flows` does not need one; omit it for the latest quarter)\n3. All PRO-gated endpoints return `{isPreview, previewReason, data}`. Always access `response[\"data\"]` (or `response.data`). On a preview (FREE) list response a `totalCount` field is also present: the number of items in the full PRO dataset, so you can show \"showing N of totalCount\". **A preview is a slice, not the window.** When `isPreview` is `true` and `totalCount` is larger than the rows returned, those rows are the newest or top N only: label them (\"newest 5 of 61 trades, free preview\") and never infer absence from them. No \"zero insider buying\", \"no congressional activity\", \"not scheduled\" or \"no unusual contracts\" from a slice\n4. Use `lookbackDays` (1-365) on insider and politician endpoints to control the time window\n\n### Common Mistakes\n- **Do NOT hardcode `reportDate`** for institutional endpoints. When you pass one, fetch it from `/quarters` first; quarters change as new SEC filings come in. (`/flows` does not require one: omit it for the latest quarter, or pass one for a specific quarter.)\n- **Do NOT iterate the response directly.** Unwrap `response[\"data\"]` first. All PRO-gated endpoints use the `{isPreview, previewReason, data}` wrapper, and some Free ones do too (`/stocks/{ticker}/sentiment` wraps on every tier), so let each endpoint's own Response line decide rather than inferring the shape from the tier\n- **Do NOT use `/api/v1/entity-metrics/*`** for metrics. These are RETIRED (return 410 Gone). Use `/api/v2/metrics/` instead\n- **The `source` parameter is case-insensitive.** `news`, `NEWS`, `News` all work\n\n### Endpoints That Do NOT Exist\nDo not hallucinate these. They are not part of the SentiSense API:\n- `/api/v1/options/flow` or `/api/v1/dark-pool`: these exact paths do not exist. For end-of-day options analytics (IV rank, put/call percentile, 25-delta skew, open-interest walls, max pain, unusual-by-volume contracts) use the Options Intelligence endpoints instead: `/api/v1/options/overview` and `/api/v1/stocks/{ticker}/options/summary`. We do not attribute tick-level order flow (no buy/sell aggressor tagging) and we have no dark-pool data\n- `/api/v1/earnings` as a root: the only paths under it are `/api/v1/earnings/recent` (which covered companies already reported in a recent window), `/api/v1/earnings/ranked` (the importance-ranked view of recent reporters and upcoming reports) and `/api/v1/earnings/statistics` (market-wide beat rate joined to what the market did next). For the forward calendar use `/api/v1/calendar/earnings`; for a company's per-quarter earnings analysis report use `/api/v1/stocks/{ticker}/earnings-summaries`; for reported financials use `/api/v1/stocks/fundamentals` (single period) or `/api/v1/stocks/fundamentals/history` (multi-period trend, up to 40 quarters or 20 years)\n- `/api/v1/alerts` or `/api/v1/notifications`: alerts are user-facing only, not available via API\n- `/api/v1/chat` or `/api/v1/ask`: the AI chat is not accessible via API\n- `/api/v2/sentiment`: the correct path is `/api/v2/metrics/entity/{id}/metric/sentiment`\n- `/api/v1/congress` or `/api/v1/congressional`: the correct path is `/api/v1/politicians`\n- `/api/v1/screener/plan` and `/api/v1/screener/plans`: there is no natural-language screen planner and no saved-screen store on the public API. Build the plan object yourself and post it to `/api/v1/screener/execute`, or execute one of the curated plans from `/api/v1/screener/screens`\n\n---\n\n## Stocks API (`/api/v1/stocks`)\n\n### GET /api/v1/stocks/price\nLatest stock price, 15-minute delayed. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker (e.g., `AAPL`) |\n\n```bash\ncurl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\\n  \"https://app.sentisense.ai/api/v1/stocks/price?ticker=AAPL\"\n```\n\nResponse: `{ ticker, currentPrice, change, changePercent, previousClose, volume, timestamp, priceAsOf?, expiresEpochSecond, extendedHours?, listingStatus?, delistedDate?, delistingReason? }`.\n\n**A delisted symbol returns its last trade price, not an error, and `listingStatus` is what marks that price as frozen.** The three listing fields are present only when the symbol is delisted or pending delisting, and absent otherwise. `listingStatus` is `\"DELISTED\"` or `\"PENDING_DELISTING\"`; `delistedDate` is the ISO date trading stopped; `delistingReason` is one of `acquired`, `take_private`, `bankruptcy`, `exchange_rule`, `merged`. On a `\"DELISTED\"` symbol the price, change, and change percent never advance again, so do not render them as a current tick.\n\n**Prices are delayed 15 minutes.** This applies to every price on this API, in every session, including the `extendedHours` values below. Do not present these quotes as live, and do not use them for execution or for any decision that turns on the current tick.\n\nRead **`priceAsOf`** for freshness: it is when the market data behind `currentPrice` is actually from, in epoch milliseconds. Do not use `timestamp` for this. `timestamp` is when the response was served, so it tracks the current clock no matter how old the value is. `priceAsOf` is omitted outside regular hours and whenever the upstream data carries no time of its own, so treat an absent `priceAsOf` as unknown age, not as fresh, and fall back to assuming the 15 minutes.\n\n`currentPrice` is always the regular-session price: the most recent regular-session value during RTH (09:30 to 16:00 ET), and the most recent regular-session close otherwise. The optional `extendedHours` field is present whenever there is an extended-hours price to show, which is pre-market (from 04:00 ET) and from the 16:00 ET close until the next pre-market opens, weekends included: once after-hours trading stops at 20:00 ET the last print is carried forward rather than dropped. It is absent during regular hours and for a ticker that did not trade outside them. It carries `{ session: \"pre\" | \"post\", price, change, changePercent }`, where `change` / `changePercent` are computed vs `currentPrice`.\n\n### GET /api/v1/stocks/prices\nBatch latest prices, 15-minute delayed (see `/price` above). **Public.** Returns a JSON array; each element has the same shape as `/price` (including a `ticker` field, an optional `extendedHours` object, and the optional `listingStatus` / `delistedDate` / `delistingReason` fields), so check each element for a frozen price rather than assuming a batch is uniformly live.\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `tickers` | string | Yes | Comma-separated (e.g., `AAPL,TSLA,NVDA`) |\n\n### GET /api/v1/stocks/chart\nHistorical OHLCV chart data. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n| `timeframe` | string | No | `1D`, `5D`, `1W`, `1M`, `3M`, `6M`, `1Y`, `5Y`, `10Y`, `MAX` (default: `1M`) |\n\n`MAX` returns a stock's full available history, up to 26 years (AAPL: 320 monthly bars back to\n1999). Granularity scales with the range: intraday for `1D` through `1M` (5-minute for `1D`,\n15-minute for `5D`, 30-minute for `1W`, hourly for `1M`), daily for `3M` through `1Y`, weekly for\n`5Y`/`10Y`, monthly for `MAX`. Ranges of `10Y` and `MAX` are adjusted for both splits and\ndividends so the series is comparable end to end; shorter ranges (through `5Y`) are split-adjusted\nonly, so the two bases differ on the same historical date by roughly the dividends paid since.\n`volume` is on the same adjusted basis as the prices in every range (pre-split bars report shares\nin today's share count), so the volume series has no split cliff either. Every bar carries\n`adjusted: true` to mark that basis. Expect an old bar on a heavily-split stock to report a much\nlarger share count than a recent one: AAPL has split 28-for-1 since 2013, so one share of 2008 is\n28 shares now and its raw turnover is counted 28 times over. On the monthly series that puts a 2008\nbar near 24 billion shares against roughly 1 billion for a recent month. That is the restatement,\nnot an error.\n\n`10Y` and `MAX` may answer `202 Accepted` with an empty array and a `Retry-After` header, meaning\nthat stock's deep history is still being assembled; retry and you get the full series. A `200`\nalways carries the range you asked for, never a silently shortened one. An unrecognized\n`timeframe` value answers `400` with an `invalid_timeframe` error naming the valid values.\n\nEach bar includes `timestamp` (Unix ms), `date`, `open`, `high`, `low`, `close`, `volume`, `adjusted` (always `true`), and `session`. The `session` field is `pre` (04:00 to 09:30 ET), `regular` (09:30 to 16:00 ET), or `post` (16:00 to 20:00 ET) for intraday timeframes (`1D`, `5D`, `1W`, `1M`); it is `null` for daily, weekly, and monthly bars (`3M` and longer) that span whole sessions. The `1M` timeframe is filtered to `regular`-session bars only.\n\n### GET /api/v1/stocks\nList all tracked ticker symbols. **Public.**\n\n### GET /api/v1/stocks/detailed\nAll stocks with company name, KB entity ID, URL slug, and precomputed `socialDominance` (`{ value, rank, percentile }`, daily refresh, null when no signal). **Public.**\n\n**Example:** sort the universe by share of voice without any second request, or filter by `socialDominance.rank <= 50` for the top-50 most discussed names.\n\n### GET /api/v1/stocks/popular\nPopular stock tickers. **Public.**\n\n### GET /api/v1/stocks/popular/detailed\nPopular stocks with company details. **Public.** Rows carry the same keys as `/detailed`. Check `socialDominance` before you sort or filter this list by share of voice: where it is `null` on a row, read it from `/detailed` by `ticker`.\n\n### GET /api/v1/stocks/images\nCompany logo URLs. **Public.** `GET` a returned URL to receive the image bytes; no API key is needed for the image fetch itself. Treat the URLs as refreshable rather than permanent: brand assets are periodically refreshed, so re-read them from this endpoint instead of storing them long term.\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `tickers` | string | Yes | Comma-separated tickers (max 600) |\n\n### GET /api/v1/stocks/descriptions\nCompany profiles with branding, industry, and market cap; `sector` when available (often absent). **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `tickers` | string | Yes | Comma-separated tickers |\n\n### GET /api/v1/stocks/{ticker}/profile\nCompany profile (CEO, sector, industry). **Public.**\n\nAlso carries `listingStatus`, `delistedDate` and `delistingReason` when the symbol is delisted or pending delisting. All three are absent for a normally listed symbol. Values match `/price` above: `listingStatus` is `\"DELISTED\"` or `\"PENDING_DELISTING\"`, `delistedDate` is the ISO date trading stopped, `delistingReason` is one of `acquired`, `take_private`, `bankruptcy`, `exchange_rule`, `merged`.\n\nFor a tracked ETF ticker, the profile may also carry `imageUrl`, a square presentation image for the fund. It is the issuer's mark rather than the individual fund's, so every fund in a family shares one image, and it matches the `imageUrl` returned by the `/etfs` endpoints. It is square like `logoUrl` and `iconUrl`, so the same avatar slot renders a stock and an ETF, but it is a first-party asset rather than a vendor branding mark and is returned as a direct URL. It is absent for issuers we hold no image for.\n\n### GET /api/v1/stocks/{ticker}/similar\nPeer/similar stocks. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `limit` | int | No | 5 | Max results |\n\nResponse: bare array of `{ symbol, name, price, changePercent }`. The key is `symbol`, not `ticker`, and the array can hold fewer than `limit` entries.\n\n### GET /api/v1/stocks/{ticker}/sentiment\nOne-call sentiment picture for a stock: the SentiSense Score with its 30-day regime, where the conversation is happening by source, and what is driving it. **Public.** **Quota-gated** when called with a key.\n\nThis endpoint also answers without an API key, and returns the same full payload either way. The tradeoff is real in both directions: a keyed call is attributed to your account but spends monthly quota and per-minute rate limit, while a keyless call costs you neither and is not attributed. Send the key when you want the usage on your account; either way the data is identical.\n\nResponse: `{ isPreview, previewReason, data }`. Everything below lives under `data`, which carries `ticker`, `companyName`, `asOf`, then the fields in the table. This endpoint is Free but still uses the wrapper (`isPreview` is `false` and `previewReason` is `null` on every tier), so unwrap first: reading `sentisenseScore` off the root returns nothing, and the full path is `data.sentisenseScore`.\n\n| Field (under `data`) | Type | Description |\n|-------|------|-------------|\n| `sentisenseScore` | number or null | Today's Score (0-centered composite of sentiment and mentions, unbounded). Null until today's reading lands, see the note below |\n| `sentisenseScoreAvg30d` | number | 30-day average, the stable regime figure |\n| `sentisenseScoreDelta30d` | number | Change over 30 days |\n| `scoreLabel` | string | Seven-band label of the 30-day average |\n| `direction` | string | `Bullish`, `Neutral` or `Bearish`, from the 30-day average |\n| `latestDirection` | string or null | Same three bands, from today's read. Null in lockstep with `sentisenseScore` |\n| `trend` | string | `UP`, `DOWN` or `FLAT` |\n| `scoreSparkline` | number[] | Daily Score series |\n| `mentions` / `mentionsAvg30d` | number | Mention volume of the latest New York daily bucket with data (today's once it lands, otherwise an earlier day; `narrative` names which), and the 30-day daily average |\n| `socialDominance` | number | Latest share of voice, as a fraction (`0.021` = 2.1%) |\n| `bySource[]` | array | Per-source tone, loudest first: `source` (`News`, `Reddit`, `X`, `YouTube`, `Hacker News`, `Substack`), `direction`, `mentionShare` (whole-number percent; rounding can make the array sum to 99 or 101 rather than exactly 100), `value` (per-source polarity, -1 to +1) |\n| `relatedTickers[]` | array | Curated peers: `ticker`, `name` |\n| `drivers[]` | array | Top story drivers: `title`, `tone` (-1 to +1) |\n| `narrative` | string | Plain-language summary of why the Score sits where it does |\n| `faq[]` | array | `question` / `answer` pairs for the common asks on this ticker |\n\nUse this when you want the headline read in one call. Use `GET /api/v2/metrics/entity/{ticker}/metric/sentisense` instead when you need the Score as a time series over a specific window. Returns `404` when the ticker has no sentiment coverage.\n\n**`sentisenseScore` and `latestDirection` are today's reading, and are `null` until the day's first analytics run lands** (mid-morning ET, later at weekends). Poll before that and every ticker returns null for these two, which is a timing state and not an outage. The rest of the response is unaffected: `scoreLabel`, `direction` and `sentisenseScoreAvg30d` are all computed from the 30-day average, so prefer those when you need a headline that is always present. A null here means \"no reading yet\", never a Score of zero. A measured 0.0 is served as `0.0`, so do not coerce null to 0, and do not infer absence by thresholding the 30-day average, which would suppress genuine neutrals.\n\nAggregate metrics such as sentiment and mention counts incorporate signals from sources that are not individually retrievable as documents, so document counts from the Documents API are not a complete audit trail of a score.\n\n> Via the MCP connector this same picture comes back from the `get_stock_snapshot` tool rather than a separate sentiment tool.\n\n\n### GET /api/v1/stocks/{ticker}/entities\nRelated ontology entities (CEO, products, partners). **Public.** Each entry carries a `urlSlug` (e.g. `Tim-Cook`) that plugs into the Metrics API `{entityId}` parameter. It is a flat list: for the relationship behind each link, use the graph endpoint below.\n\n### GET /api/v1/stocks/{ticker}/graph\nOne company's neighborhood in the SentiSense ontology as a typed graph: the people, products, product families, peer companies and organizations the knowledge base connects to that ticker, plus the named relationship between each pair. **Public** (API key required). One ticker per call; there is no listing or enumeration form.\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `depth` | integer | No | `1` | `1` or `2`. `1` returns the company's own people, products and peers; `2` walks one hop further, which is how an organization behind a person appears. Anything else returns `400 invalid_depth`. Send it explicitly so the walk you describe is the walk you asked for |\n| `cap` | integer | No | `75` | `1` to `200`, the maximum number of non-root nodes returned. Anything else returns `400 invalid_cap`. Send it explicitly for the same reason |\n\nResponse: a flat object, no `{isPreview, data}` wrapper.\n\n| Field | Type | Notes |\n|-------|------|-------|\n| `ticker` | string | The normalized ticker |\n| `root` | string | The root company's slug. The root is also the first entry in `nodes` |\n| `depth`, `cap` | integer | The values the walk was asked for, echoed back. `depth` is what you requested, not how far the walk reached |\n| `truncated` | boolean | `true` when `cap` cut the walk short. The survivors are ordered by node type then name, not by importance, so a truncated response can drop people and products while keeping peers |\n| `counts` | object | `{nodes, edges, byType}`, where `byType` maps a node type to how many of it came back |\n| `omitted` | integer | Nodes left out for carrying no slug, and so not addressable. Normally `0` |\n| `groups` | object | `people`, `products`, `productFamilies`, `peers`, `organizations`, `publishers`, `topics`. Every one is a list of **slugs** except `productFamilies`, which is a list of `{family, members}`. A slug is the same handle the Metrics API takes, so you can query one straight from `groups`; join it to `nodes` when you need its `displayName` or `type` |\n| `nodes` | array | `{slug, displayName, type}`. `type` is uppercase (`COMPANY`, `PERSON`, `PRODUCT_OR_SERVICE`, `ORGANIZATION`, `PUBLISHER`, `TOPIC`), and `slug` is the Metrics API `{entityId}` handle |\n| `edges` | array | `{source, target, type, direction, properties}`, both ends slugs. `type` is one of `LEADS`, `FOUNDED`, `PRODUCT_OF`, `VARIANT_OF`, `PEER`, `OWNS`, `SUBSIDIARY_OF`, `SUBTOPIC_OF`, `BELONGS_TO`, `AFFILIATED_WITH`. `direction` is `DIRECTED` or `BIDIRECTIONAL`; on a `BIDIRECTIONAL` edge the order carries no meaning. `properties` is a flat string map and is often empty |\n\nAn unknown or unlisted ticker returns `404 entity_not_found` with up to three `suggestions`, which is a different answer from `/entities`, where an unknown ticker returns `200 []`. The response carries no sentiment, Score or mention counts: fetch those per handle from the Metrics API.\n\n`publishers` and `topics` are part of the response shape but are not reachable from a company root today, so treat an empty list there as the expected state rather than as missing theme coverage.\n\n### GET /api/v1/stocks/{ticker}/ai-summary\nAI-generated stock analysis report. **PRO** (Free: `depth=basic` unlimited, `depth=deep` limited to 10/month). `depth=basic` returns a preheader summary. `depth=deep` returns a full multi-section report. Exhausting the `depth=deep` monthly view allowance returns `429` with `{error: \"quota_exceeded\", ...}`, the same contract as every other quota-gated endpoint.\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `depth` | string | No | `basic` | `basic` or `deep` |\n\nResponse: flat object (no `{isPreview, data}` wrapper).\n\n| Field | Type | Notes |\n|-------|------|-------|\n| `ticker` | string | |\n| `companyName` | string | |\n| `status` | string | `READY`, `NOT_AVAILABLE`, or `ERROR` |\n| `statusReason` | string or null | Present on `NOT_AVAILABLE` / `ERROR` only |\n| `reportType` | string | `SUMMARY` for `depth=basic`, `FULL` for `depth=deep` |\n| `version` | integer | Report date encoded as yymmdd (e.g. 260520) |\n| `lastUpdated` | long | Epoch milliseconds |\n| `sections` | object | Section name to `{content, directives}`. Present on both depths: `depth=basic` returns a single `Executive Summary` section, `depth=deep` returns the full set. |\n| `sectionOrder` | string[] | Ordered section keys for rendering. Present on both depths; `[\"Executive Summary\"]` on `depth=basic`. |\n| `fromCache` | boolean | Whether this response was served from the report cache. `false` also covers a report served straight from the packaged knowledge base, so it does not mean the report was regenerated for your call: read freshness from `lastUpdated`. |\n| `moatRating` | integer or null | Proprietary moat quality score 0-10 (network effects, switching costs, intangibles, cost advantages, efficient scale). Present on `depth=deep` only. Null if not yet assessed for this ticker. |\n| `aiDisruptionRisk` | string or null | `Low`, `Medium`, `High`, or `Critical`. Measures AI revenue-displacement exposure. Present on `depth=deep` only. Null if not yet assessed. |\n\n**Do not test for the presence of `sections` to detect a deep report:** both depths return it. Branch on `reportType` (`SUMMARY` vs `FULL`) instead.\n\n### GET /api/v1/stocks/{ticker}/metrics/{metricType}/breakdown\nSentiment or mention metrics breakdown by sub-entities. **Public.**\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `metricType` | path | Yes | `sentiment` or `mentions` |\n| `startTime` | long | Yes | Start time in epoch ms |\n| `endTime` | long | Yes | End time in epoch ms |\n\n### GET /api/v1/stocks/market-status\nCurrent market open/closed status. **API key required.**\n\nResponse: `{ status: \"open\" | \"closed\", timestamp: <epoch_ms> }`. The `timestamp` is a numeric epoch milliseconds value (not a string).\n\n### GET /api/v1/stocks/fundamentals\nFinancial statement data. **Public.**\n\n| Param | Type | Required | Default | Description |\n|-------|------|----------|---------|-------------|\n| `ticker` | string | Yes | - | Stock ticker |\n| `timeframe` | string | No | `quarterly` | `quarterly` or `annual` |\n| `fiscalPeriod` | string | No | - | e.g., `Q4` |\n| `fiscalYear` | int | No | - | e.g., `2024` |\n\n**Reporting currency (applies to every fundamentals endpoint):** figures are as reported by the\nfiler, in the filer's own currency, never converted to USD. Foreign ADR filers report in home\ncurrency (SK hynix: KRW, Toyota: JPY, ASML: EUR). The optional `reportedCurrency` field (\"USD\",\n\"KRW\", ...) on the response (and on each `/fundamentals/history` row) names it; when absent the\ncurrency is unknown, not implicitly USD. Never mix these figures with the share price: the price\nis the USD ADR price, so for non-USD filers `peRatio` / `psRatio` / `pbRatio` are served as\n`null` on purpose, and you should not recompute them. Same-currency ratios (margins, ROE, ROA,\ncurrent ratio, debt/equity) stay valid for all filers.\n\n### GET /api/v1/stocks/fundamentals/current\nTrailing-twelve-month valuation snapshot against the latest price. **Public.** It is not a statement snapshot: for income-statement, balance-sheet and cash-flow lines use `/fundamentals` or `/fundamentals/history`.\n\n| Param | Type | Required | Description |\n|-------|------|----------|-------------|\n| `ticker` | string | Yes | Stock ticker |\n\nResponse (flat): `{ ticker, currentPrice, peTTM, psTTM, epsTTM, revenueTTM, quartersIncluded, available, reason, fetchedAt, reportedCurrency? }`. `peTTM` and `psTTM` are the latest price over trailing EPS and over trailing revenue per share; `quartersIncluded` is how many quarters the trailing figures sum (normally 4); `fetchedAt` is epoch seconds. When `available` is `false`, `reason` says why (no current price, or no trailing earnings data) and the TTM fields are null. `reportedCurrency` names the currency of `epsTTM` and `revenueTTM` (`currentPrice` stays USD) and is omitted when unknown; for a non-USD filer `peTTM` and `psTTM` are `null` by design, the same cross-currency rule as above.\n\n### GET /api/v1/stocks/fundamentals/history\nMulti-period history of full financial statements (income statement, balance sheet, cash flow), one\nentry per fiscal quarter or year, newest first. Use for margin trends, multi-year comparisons, or as\nthe input to a valuation model. Not the sa\n\nArchive v2.20.1: 3 files, 69077 bytes\n\nFiles: skill-card.md (1852b), SKILL.md (193707b), _meta.json (130b)\n\nArchive v2.20.0: 3 files, 68392 bytes\n\nFiles: skill-card.md (2095b), SKILL.md (191381b), _meta.json (130b)\n\nArchive v2.19.0: 3 files, 68291 bytes\n\nFiles: skill-card.md (2230b), SKILL.md (190887b), _meta.json (130b)\n\nArchive v2.18.0: 3 files, 67783 bytes\n\nFiles: skill-card.md (2165b), SKILL.md (189596b), _meta.json (130b)\n\nArchive v2.17.1: 3 files, 66885 bytes\n\nFiles: skill-card.md (2428b), SKILL.md (186353b), _meta.json (130b)\n\nArchive v2.17.0: 3 files, 66624 bytes\n\nFiles: skill-card.md (2679b), SKILL.md (185428b), _meta.json (130b)\n\nArchive v2.16.0: 3 files, 66083 bytes\n\nFiles: skill-card.md (2565b), SKILL.md (184099b), _meta.json (130b)","readmeExcerpt":"Skill: sentisense Owner: thesentitrader Summary: US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers ev","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"curl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\"},{"language":"bash","snippet":"# Include API key in header\ncurl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\\n  \"https://app.sentisense.ai/api/v1/...\""},{"language":"python","snippet":"import os\nfrom sentisense import SentiSenseClient\nclient = SentiSenseClient(api_key=os.environ[\"SENTISENSE_API_KEY\"])"},{"language":"bash","snippet":"curl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\"},{"language":"bash","snippet":"curl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\\n  \"https://app.sentisense.ai/api/v1/stocks/price?ticker=AAPL\""},{"language":"python","snippet":"client = SentiSenseClient(api_key=os.environ[\"SENTISENSE_API_KEY\"])\ncoverage = client.list_kpi_coverage()\nprint(f\"{coverage.count} tickers covered\")\nfor entry in coverage.tickers[:5]:\n    print(f\"  {entry.ticker}: {entry.kpiCount} KPIs (refreshed {entry.lastUpdated})\")"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: sentisense\ndescription: \"US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers every endpoint. Use for stock sentiment API, stock market API, stock rating API, stock letter grade, insider trading data, congress stock trades, 13F holdings, options flow, earnings calendar, stock price API, market data for AI agents. Read-only. No trading, no purchases, no write operations, no wallet access.\"\nhomepage: https://sentisense.ai\nrequires:\n  env:\n    - SENTISENSE_API_KEY\nprimaryEnv: SENTISENSE_API_KEY\nmetadata:\n  openclaw:\n    requires:\n      env:\n        - SENTISENSE_API_KEY\n    primaryEnv: SENTISENSE_API_KEY\n---\n\n# SentiSense API - Skill File for AI Agents\n\n> **SentiSense** is a read-only financial intelligence API: stock prices, insider/politician trading, institutional flows, AI insights, and news sentiment. No trading, no purchases, no write operations. Free tier available.\n\n**Base URL:** `https://app.sentisense.ai`\n**Website:** https://sentisense.ai\n**ClawHub Skill:** [clawhub.ai/TheSentiTrader/sentisense](https://clawhub.ai/TheSentiTrader/sentisense)\n**API Docs:** https://sentisense.ai/docs/api/\n**Authentication:** API key via `X-SentiSense-API-Key` header. Get a free key at https://app.sentisense.ai/get-api-key\n**SDKs (optional):** [Python](https://github.com/SentiSenseApp/sentisense) | [Node.js](https://github.com/SentiSenseApp/sentisense-node) -- source on GitHub. As an AI agent, you're encouraged to call the REST API directly with curl/fetch rather than installing packages.\n\n---\n\n## Use & Disclaimer\n\nThis skill is an **educational data interface** to SentiSense's read-only Data API. Output is informational only. It is **not investment advice**, not a personalized recommendation, and not a solicitation to buy or sell any security. The user is responsible for their own decisions. Use of the API and this skill is subject to the [API Terms of Service](https://sentisense.ai/agreement/API-Terms-of-Service.pdf) and [Terms of Service](https://sentisense.ai/agreement/Terms-of-Service.pdf).\n\n---\n\n## Authentication\n\n```bash\n# Include API key in header\ncurl -H \"X-SentiSense-API-Key: $SENTISENSE_API_KEY\" \\\n  \"https://app.sentisense.ai/api/v1/...\"\n```\n\n**Identify your client.** Send a `User-Agent` naming your agent runtime and this skill, for\nexample `OpenClaw/1.4 (sentisense)` or `ClaudeCode/2.1 (sentisense)`. Substitute your own runtime and\nversion if neither matches. You can also volunteer what your agent is called by adding an\n`agent/<your-agent-name>` token inside the same parentheses, as in\n`OpenClaw/1.4 (sentisense; agent/research-desk)`. All of it is optional, and it is what tells\nus this skill has real integrations behind it, so i"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn71ca3nrt3w6w0v3nhv3c4tan82x1ym\",\n  \"slug\": \"sentisense\",\n  \"version\": \"2.21.2\",\n  \"publishedAt\": 1791085845985\n}"},{"path":"skill-card.md","content":"## Description:\n\nProvides agents with read-only US stock-market data, sentiment, ratings, filings, institutional activity, and AI-generated insights through the SentiSense API.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[thesentitrader](https://clawhub.ai/user/thesentitrader)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nAgents and developers use this skill to research US stocks, monitor market sentiment and disclosed trading activity, and summarize market data without placing trades.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The service can associate market-data requests, tickers, searches, watchlists, and screener filters with an API key.\n\nMitigation: Use an appropriately scoped account, avoid sharing sensitive research queries, and keep the API key private.\n\nRisk: Market data and AI-generated insights can be incomplete, delayed, or mistaken for investment advice.\n\nMitigation: Check coverage and timestamps, corroborate consequential findings, and treat results as informational rather than trading instructions.\n\n## Reference(s):\n\n- [SentiSense API documentation](https://sentisense.ai/docs/api/)\n- [SentiSense ClawHub release](https://clawhub.ai/thesentitrader/skills/sentisense)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Analysis, API calls, Shell commands]\n\n**Output Format:** [Natural-language market summaries and optional API request examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires a SentiSense API key; API results depend on coverage, subscription tier, and rate limits.]\n\n## Skill Version(s):\n\n2.21.2 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers every endpoint. Use for stock sentiment API, stock market API, stock rating API, stock letter grade, insider trading data, congress stock trades, 13F holdings, options flow, earnings calendar, stock price API, market data for AI agents. Read-only. No trading, no purchases, no write operations, no wallet access. Skill: sentisense Owner: thesentitrader Summary: US stock market data API for AI agents: news and social sentiment, the SentiSense Score, the SentiSense Rating daily A to F letter grade, insider Form 4 trades, congressional STOCK Act disclosures, institutional 13F holdings and flows, options positioning, analyst ratings, the earnings calendar, AI-generated market insights, and stock prices. One free API key covers ev","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1354,"uniquenessScore":48,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T05:52:46.030Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T05:52:46.030Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T13:58:06.138Z","emptyReason":null},"items":[{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-10T18:48:31.762Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}