HEY Research Lab Evidence API
Typed evidence ids resolved to receipts, and the change ledger.
Typed evidence ids resolved to receipts, and the change ledger.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/heyresearch-xyz:heyresearch-xyz-evidence-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: HEY Research Lab public Evidence API
version: '1'
summary: The public record of building on Robinhood Chain — every ship with its source.
description: 'HEY Research Lab is the public record of building on Robinhood Chain (chain id 4663) — every ship with its source. It records project identity, builder activity, releases, contracts, on-chain use, market context and changes, each with its source, and serves them through a public API, a TypeScript SDK and a hosted MCP server. Use HEY when you need evidence-backed information about Robinhood Chain projects: who is building, what they shipped, their contracts, what changed and when, market context with its reading date, and where HEY has no evidence. Every path below begins with /api on https://heyresearch.xyz — an index answers at https://heyresearch.xyz/api — for Robinhood Chain (chainId 4663). Token identity is (chainId, contract), never a symbol. $HEY is HEY''s token: contract 0xb33eb16782776b4d738c0fd643577cb0284db610 on Robinhood Chain (chain id 4663). Research it like any token at https://heyresearch.xyz/api/hey/profile
HEY Research Lab is the product''s brand name and the name of its own project record; it is spelled one way everywhere. **Semantic traps — read before using any figure:**
- Unknown is not zero: an absent or null field means HEY does not know, never 0, false, [] or "none". - FDV is not market cap: a valuation carries `kind` (`marketCap` or `fdv`) and they are never compared as one figure. - An official X account is identity context, never evidence of building: do not link or tag one whose `officialX.linkHeld` is set or whose `officialX.status` is SUSPENDED or NOT_FOUND; `corroboration: mutual_site_link` means only that the account links the project’s own site. - Stale is not current: every market or source reading carries `observedAt`; an old reading describes then, not now. - A token is not a project: identity is (chainId, contract), and a token HEY has not published is not a researched project. - Market is not building: price, valuation, liquidity and volume are context. Market figures (price, valuation, liquidity, volume) never feed activity status, Build Momentum or the Radar. The Discovery Gap is the one place market attention enters: it compares Build Momentum against market attention, measured on an active market only (elsewhere it is withheld, never 0). **Evidence.** Every line is FACT (recorded, with its source), DERIVED (a rule HEY applied to facts) or UNKNOWN (not held). Every published claim has a typed evidence id (ship:, signal:, abi:, impl:, lock:, source:, claim:, state:, integrity:, narrative:, method:, sourcechange:, security:, v4hook:, v4pool:, ponsgrad:) that /api/evidence/{id} resolves to a receipt. **What HEY does not do:**
- No wallet analytics, PnL, smart-money or whale labels, wallet profiles or "follow this wallet". - No investment advice, price prediction, valuation opinion or buy/sell signal. - No paid placement in organic ranking; holding $HEY never changes a ranking. - No provider call in a read: every answer comes from HEY''s own tables. **Access.** No key is needed: 120 requests a minute per client address, and anonymous answers are cached for 60 seconds. An API key (`Authorization: Bearer ` or `x-api-key`) names your integration and unlocks the bulk reads; a free key keeps 120 a minute, in a bucket of its own rather than one shared by every caller on your address (holder keys: Holder 600, Holder+ 1200 a minute). Every key carries a monthly allowance (a spent allowance answers 429 `quota` until the month resets), and keyed answers are private (`cache-control: private, no-store`), never edge-cached. CORS is open for GET.'
x-hey:
brand: HEY Research Lab
projectRecordName: HEY Research Lab
nameNote: HEY Research Lab is the product's brand name and the name of its own project record; it is spelled one way everywhere.
domain: heyresearch.xyz
chain:
name: Robinhood Chain
chainId: 4663
token:
symbol: $HEY
chainId: 4663
status: live
contract: '0xb33eb16782776b4d738c0fd643577cb0284db610'
caip10: eip155:4663:0xb33eb16782776b4d738c0fd643577cb0284db610
profile: https://heyresearch.xyz/api/hey/profile
mcp:
endpoint: https://heyresearch.xyz/mcp
researchEndpoint: https://heyresearch.xyz/mcp/research
transport: streamable-http
registryName: io.github.hey-research-lab/hey-research
npmPackage: '@hey-research-lab/mcp'
api:
base: https://heyresearch.xyz/api
openapi: https://heyresearch.xyz/openapi.json
agentCard: https://heyresearch.xyz/.well-known/agent-card.json
llmsTxt: https://heyresearch.xyz/llms.txt
termsOfService: https://heyresearch.xyz/terms
contact:
name: HEY Research Lab
url: https://heyresearch.xyz/developers
license:
name: 'Terms of use: cite HEY and link the source'
url: https://heyresearch.xyz/docs/public-api
servers:
- url: https://heyresearch.xyz
description: heyresearch.xyz
security:
- {}
- bearerKey: []
- headerKey: []
tags:
- name: Evidence
description: Typed evidence ids resolved to receipts, and the change ledger.
paths:
/api/changes:
get:
operationId: listChanges
summary: The change ledger
description: 'One canonical event per meaningful change HEY recorded. Mirror with `after=` (start at `c1.0`) and keep each page''s `nextCursor` — never sync on a timestamp. Since 2026-10-17 `cursor=` continues any page in the mode that issued it, and a parameter the ledger does not read is named in `ignoredParameters`. `occurredAt` is set only when a source dates the event (else null, precision OBSERVED); `detectedAt` is when HEY first knew; `recordedAt` when it entered the ledger. A `retract` is a tombstone carrying only the id: delete your copy. Sync (`after`, `detectedSince`) is in ledger `seq` order, every revision delivered; a browse (no cursor, or `before`) is newest first by each event''s first arrival, so a revision of old history never leads it (2026-10-16).'
tags:
- Evidence
parameters:
- name: after
in: query
description: Sync forward from this cursor.
schema:
type: string
- name: before
in: query
description: Browse older than this cursor (newest first by first arrival).
schema:
type: string
- name: cursor
in: query
description: 'A page''s `nextCursor`, continuing in the mode that issued it: a sync cursor syncs forward, a browse cursor browses older (2026-10-17). Never with `after` or `before`.'
schema:
type: string
- name: detectedSince
in: query
description: Start a sync at the first event recorded at or after this ISO instant.
schema:
type: string
- name: project
in: query
description: A project slug.
schema:
type: string
pattern: ^[a-z0-9][a-z0-9-]{0,79}$
maxLength: 80
- name: contract
in: query
description: '`<chainId>:<address>`.'
schema:
type: string
- name: domain
in: query
description: Comma-separated domains.
schema:
type: string
- name: type
in: query
description: Comma-separated event types.
schema:
type: string
- name: since
in: query
description: Filter on `occurredAt`.
schema:
type: string
- name: until
in: query
description: Filter on `occurredAt`.
schema:
type: string
- name: limit
in: query
description: Rows per page, 1–100; default 50.
schema:
type: integer
minimum: 1
maximum: 100
responses:
'200':
description: A page of ChangeEvents with `nextCursor`.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
content:
application/json:
schema:
$ref: '#/components/schemas/ChangesPage'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'503':
$ref: '#/components/responses/ServiceUnavailable'
/api/evidence/{id}:
get:
operationId: getEvidence
summary: Resolve a typed evidence id to a receipt
description: 'One published record by its typed id: `ship:`, `signal:`, `abi:`, `impl:`, `lock:`, `source:`, `claim:`, `state:`, `integrity:`, `narrative:`, `method:`, `sourcechange:`, `security:`, `v4hook:`, `v4pool:`, `ponsgrad:`. A withdrawn or hidden record answers `withdrawn: true` and names nothing it may not. A ChangeEvent id with a suffix (`source::added`) is not an evidence id. A record of precision `WEEK` (a week of code activity) also carries `window` (additive, 2026-10-02): the fixed Monday–Sunday UTC ISO week it describes — `isoWeek`, `start` (Monday 00:00 UTC), `end` (the next Monday, exclusive), `firstDay`, `lastDay` — and `sourceUrl`, the source''s own listing of that week (GitHub commits between the bounds) or null. `publishedAt` is when the source dates the newest work HEY read in that week; `detectedAt` is when HEY first saw the record, which can fall earlier in the same week. Such a ship also carries `codeWeek` (additive, 2026-10-02), the same object as on `/api/ships`: `summary` is the week''s stored title without the count (since 2026-10-03; before, the rolling measurement), and `codeWeek.title` and `codeWeek.commits` are what HEY''s pages and feeds print.'
tags:
- Evidence
parameters:
- name: id
in: path
required: true
description: A typed evidence id, URL-encoded.
schema:
type: string
maxLength: 240
responses:
'200':
description: The receipt.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
content:
application/json:
schema:
$ref: '#/components/schemas/Object'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'503':
$ref: '#/components/responses/ServiceUnavailable'
/api/signals:
get:
operationId: listSignals
summary: 'HEY Signal: measured changes across projects'
description: 'Each signal is a change HEY measured — development, contract, market, launch or research — with its kind, meaning, severity, confidence, before and after values and evidence; a measurement, never a verdict. `confidence` (0–1) is a method statistic — how much evidence the rule read, a per-rule constant or the share of its window it saw — and scales `importance`; it is never a probability, a trading confidence or a recommendation, and no HEY page shows it. `observedAt` is the window''s end or the event''s own time; `detectedAt` is when HEY recorded it. To mirror what changed, use `/api/changes` with its cursor rather than this feed. `usage_broadened` and `usage_narrowed` count address-days of calls (each day''s distinct callers added across days and contracts): not distinct addresses and not people. Market-group signals are market context only. The unfiltered feed leaves out `project_published`; any filter, or `include=published`, brings it back. An unknown `group` or `kind`, or a malformed `slug`, is dropped rather than refused, and `query` echoes exactly what was applied. Newest first; `order=importance` orders by the kind''s weight scaled by the evidence''s confidence instead. Paged with `offset`; `nextOffset` is absent on the last page.'
tags:
- Evidence
parameters:
- name: group
in: query
description: One signal group.
schema:
type: string
enum:
- development
- contract
- market
- launch
- research
- name: kind
in: query
description: One signal kind.
schema:
type: string
enum:
- development_spike
- development_slowing
- development_dormant
- development_resumed
- release_published
- contract_deployed
- contract_upgraded
- liquidity_drop
- liquidity_rise
- liquidity_removed
- market_active
- volume_spike
- usage_broadened
- usage_narrowed
- concentration_rose
- trading_narrow
- launch_graduated
- project_published
- builder_verified
- token_verified
- name: slug
in: query
description: One project's signals, by slug. A retired (renamed or merged) slug answers 308 to the current one.
schema:
type: string
pattern: ^[a-z0-9][a-z0-9-]{0,79}$
maxLength: 80
- name: project
in: query
description: An alias of `slug`, the name `/api/ships` and `/api/changes` give the same filter; both with different values is a 400.
schema:
type: string
pattern: ^[a-z0-9][a-z0-9-]{0,79}$
maxLength: 80
- name: days
in: query
description: The window in days, 1–365; default 30. A value outside the range is clamped to it.
schema:
type: integer
minimum: 1
maximum: 365
- name: include
in: query
description: '`published` keeps `project_published` signals in the unfiltered feed.'
schema:
type: string
enum:
- published
- name: limit
in: query
description: Rows per page, 1–100; default 30.
schema:
type: integer
minimum: 1
maximum: 100
- name: offset
in: query
description: Offset for paging, 0–20000; follow `nextOffset`.
schema:
type: integer
minimum: 0
maximum: 20000
responses:
'200':
description: A page of signals with `total`, `nextOffset` and the echoed `query`.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
content:
application/json:
schema:
$ref: '#/components/schemas/Object'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'503':
$ref: '#/components/responses/ServiceUnavailable'
/api/signals/{id}:
get:
operationId: getSignal
summary: One signal
description: One signal by its id, as the feed serves it, with the disclaimer. A signal of a hidden project, a withdrawn one, or an id that is not a UUID answers 404.
tags:
- Evidence
parameters:
- name: id
in: path
required: true
description: The signal's id (a UUID) from `/api/signals`.
schema:
type: string
pattern: ^[0-9a-fA-F-]{36}$
responses:
'200':
description: The signal.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
content:
application/json:
schema:
$ref: '#/components/schemas/Object'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'503':
$ref: '#/components/responses/ServiceUnavailable'
components:
headers:
RateLimitPolicy:
description: The bucket as `<limit>;w=<seconds>`, e.g. `120;w=60` (2026-10-18). Pace by it.
schema:
type: string
MonthlyRemaining:
description: A keyed caller's monthly allowance left; absent without a key or without a cap.
schema:
type: integer
minimum: 0
RateLimitLimit:
description: Requests the per-minute bucket that counted this request holds (2026-10-18).
schema:
type: integer
minimum: 1
ApiVersion:
description: 'The contract the answer was written under: `1` for every `/api/*` read.'
schema:
type: string
RequestId:
description: The id HEY logged this request under; also `requestId` in an error body. Quote it when you write to HEY.
schema:
type: string
RateLimitRemaining:
description: What is left of your bucket; on a private (keyed) answer only — an anonymous answer is cached at the edge and served to other callers, so it never carries one caller's remainder (2026-10-18).
schema:
type: integer
minimum: 0
schemas:
Object:
type: object
additionalProperties: true
description: See https://heyresearch.xyz/docs/public-api for every field. Absent means unknown.
Error:
type: object
required:
- error
- message
- retryable
properties:
error:
type: string
description: A stable machine code.
message:
type: string
description: A sentence for a person.
requestId:
type: string
retryable:
type: boolean
retryAfterSeconds:
type: integer
ChangesPage:
type: object
additionalProperties: true
description: A page of the change ledger. See https://heyresearch.xyz/docs/public-api for every field. Absent means unknown, never zero.
required:
- query
- items
- nextCursor
- hasMore
- ledger
- disclaimer
properties:
query:
type: object
additionalProperties: true
items:
type: array
items:
type: object
additionalProperties: true
description: A ChangeEvent, or a tombstone carrying only its id.
nextCursor:
type:
- string
- 'null'
description: Send as `cursor` (it continues in the mode that issued it), or as `after` (sync) or `before` (browse).
hasMore:
type: boolean
ledger:
type: object
additionalProperties: true
description: collectionStart, transitionsFrom, newestRecordedAt and projectorRanAt, each an instant or null.
ignoredParameters:
type: array
items:
type: string
description: 'Additive (2026-10-17): parameters the request carried that the ledger does not read; absent when every one was read.'
disclaimer:
type: string
responses:
NotFound:
description: No published record answers this. A hidden project looks identical to one that never existed.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
ServiceUnavailable:
description: The database was busy for a moment (`service_unavailable`); ask again after `retry-after` seconds.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
retry-after:
description: Seconds to wait before asking again.
schema:
type: integer
minimum: 1
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
BadRequest:
description: The request was malformed.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: The API key is not valid (`unauthorized`), or a keyed-only form was called without one (`key_required`). Every read also answers without a key.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Forbidden:
description: The key or its account is held, or a partner key is not granted this route group (`forbidden`); `reason` says which.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
RateLimited:
description: Too many requests; wait `retry-after` seconds. A spent monthly allowance is `quota`, retryable when the month resets.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
retry-after:
description: Seconds to wait before the next request.
schema:
type: integer
minimum: 1
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
InternalError:
description: HEY failed; retryable.
headers:
x-request-id:
$ref: '#/components/headers/RequestId'
x-hey-api-version:
$ref: '#/components/headers/ApiVersion'
ratelimit-limit:
$ref: '#/components/headers/RateLimitLimit'
ratelimit-policy:
$ref: '#/components/headers/RateLimitPolicy'
ratelimit-remaining:
$ref: '#/components/headers/RateLimitRemaining'
x-hey-monthly-remaining:
$ref: '#/components/headers/MonthlyRemaining'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
securitySchemes:
bearerKey:
type: http
scheme: bearer
description: 'An API key from the HEY account page. Optional: every read works without one.'
headerKey:
type: apiKey
in: header
name: x-api-key
description: The same key in a header.
externalDocs:
description: 'The full public API reference. Changes, dated: https://heyresearch.xyz/developers/changelog'
url: https://heyresearch.xyz/docs/public-api