DevelopersChangelog
Public API changelog
Last changed 2026-10-24: Proof of Ship attestations. Subscribe by RSS.
Every change to HEY's public API that a partner or an agent can see, dated, newest first: what was added, what changed meaning, what is deprecated. The site renders this file at /developers/changelog, with an RSS feed at /developers/changelog/feed.xml, and the OpenAPI document links it.
/api/* changes additively: a field is added, never renamed, removed or given a new meaning, and a
change of meaning needs /api/v2 with at least 90 days of overlap. When HEY narrows what a value
returns because the old answer was not true — a truth repair — the change is dated here and in the
public API reference the day it ships, and the old population keeps a name of its
own. Changes before 2026-10-16 are dated where they happened, in the reference.
The TypeScript SDK keeps its own changelog in its package; its entries are summarised here.
— Proof of Ship attestations
Changed
GET /api/v1/proof-of-ship/attestationcounts a ship only when HEY first recorded it inside[since, until](a ship read afteruntilno longer counts), and at most one ship of each kind — a release, a contract deployment or upgrade, a code week, any other entry — per UTC day of HEY's first record.evidenceIdslists exactly what was counted;definitionsays so. Activity status and scores are unchanged.builderties only by a wallet-signature claim made for the project's current tracked token, or that token's recorded deployer measured as no serial launcher, and only while the token stands as the project's own (verified, not an issuer's, not disowned or passed over by the project's site, not contested by a lookalike). Otherwise403 builder_not_tied, as before.
Added
slugaccepts an old slug that redirects to a published page; HEY signs over the slug as asked. The answer addscurrentSlug. The endpoint is now in the OpenAPI document (getProofOfShipAttestation), llms.txt and /developers.GET /api/v1/proof-of-ship/attestation?slug=&builder=&since=&until=&escrow=: the ships HEY counts as building for one published project in the window, by the same rule as activity status and first recorded by HEY inside it (a code week only when its whole week is), with their sortedship:<uuid>ids and receipt pages, signed as EIP-712 typed data (Ships(bytes32 project,address builder,uint64 since,uint64 until,uint32 ships,bytes32 evidence,uint64 issuedAt), domain "HEY Proof of Ship" v1, chain 4663) for the open-sourceShipEscrowcontract — only for a payoutbuilderHEY's evidence ties to the project (builderTie:wallet_claimortoken_deployer). New error codesescrow_not_configured(400),builder_not_tied(403) andnot_configured(503). Additive: no existing field or route changes. See Proof of Ship.
— Listings, partner cards and snapshots say what they read
Changed
has=liveMarket(truth repair): only projects whose tracked token has a market that is not gone. It also passed every project with no token — about 2,000 of 3,619 rows — whilecatalogue.marketCoverage.liveMarketcounted tokens only. The documented meaning ("card facts the project must have") is unchanged; the list now matches it.- A repeated
has=ortype=is read as one comma-separated list; the second value was dropped. GET /api/v1/scan?chain=abc(a chain that is not digits) is a 400bad_request, neverfound: false, reason: "chain".- A token's earlier depth reading older than 7 days is no longer sent as
liquidityon a card when the current reading carries none (absent, never 0): the market classifier already calls such depth not current. The detail now sends the same earlier figure the card sends. usage.methodEventsisnullwhere HEY holds no usage figures (no contract watched), never zeros. The key is always sent; SDKHeyUsageSummary.methodEventsis typed… | null.activity_applies_to_token(truth repair) on/api/v1/scan,/api/v1/builderand/api/token/{chainId}/{address}is alsofalsefor a token whose verification reason issite_disclaims_contract: the project's own site names this contract and says it is not the project's token. Its meaning — whether the project's building may be read as this token's — is unchanged; it wastruefor that case, which the project page and the scorer already treated as not the project's. Such a card carries nocta, as forMISMATCH./api/projects/{slug}/marketlastTradeDaycounts complete UTC days only, and a day's trading needs a measured volume above $1 (the classifier's own definition); a sub-dollar day is no trade day.- MCP: every per-project tool reads
projectasslugandslugasproject, and a list argument sent as one string (domain: "market,build") as the list REST reads;get_changesprints a numeric move as money or a rounded count;find_projectsdates a liquidity figure read more than a day ago.
Added
adjustedParametersonGET /api/projectsandGET /api/ships: each value read otherwise than sent —limitabove 48 or not a number,offsetbelow 0 or above 20,000, a single-value parameter sent twice — withparameter,value,readAsandreason(above_maximum,below_minimum,not_a_number,not_an_integer,repeated). The values are capped as before; now the answer says so.activity.releases_measuredon the/api/v1/scancard: false when HEY reads no repository, changelog or feed releases come from, or building is not measured.releases_30dkeeps its value and meaning; print it only besidereleases_measured: true.identity.officialXonGET /api/projects/{slug}/snapshot(and MCPget_project_snapshot), the card's own field:status,checkedAt,linkHeld,corroboration.eventsDaybesideevents24hon the project detail'sonchainActivityand the snapshot'sonchain: the UTC day the count is for, the newest day HEY read — never a rolling 24 hours.chain.tokensTradedBasis: "busiest_day"on every weekly report (stated on read for older ones) andchain.tokensTradedDayon reports written since:tokensTradedis the busiest day's distinct count, never a total.
Fixed
- The OpenAPI descriptions of
/api/v1/scan,/api/v1/builderand/api/token/{chainId}/{address}name the 400 for a well-formed address that is not a token identity (the burn address).
— One change, explained
Changed
- The partner builder card's
latest_changenow picks its event by the Research Summary's rule (the project's own builder change before HEY's reclassifications, newest by the source's date), the rule the Telegram card and the homepage Check card also use. Lock events, which left the builder story on 2026-10-19, are no longer named there; a verified-source record (contract.deployed) and a source added, lost or restored now can be. The field's meaning — the newest builder-side change — is unchanged. - Truth repair: an
impl:<chain>:<address>:rpc:<uuid>receipt is withdrawn (superseded) when an upgrade log already explains it, and (moderation_hidden) when its upgrade ship was withdrawn by a moderator — exactly when the change ledger retracts the event. It read live before. - Truth repair: the before/after read (
/around/{eventId}) reads usage days through the same shared-infrastructure re-roll as the usage section, so stored days that counted a shared contract (the v4 PoolManager) are not compared; a project is watched only through coverage the method watch reads.
Added
GET /api/projects/{slug}/explain?fact=build.change[&event=<ledger id>](SDKHeyExplainFact,projects.explain(slug, 'build.change', { event }); MCPexplain_factwithevent): one change explained, from HEY's own tables, with no provider or model call. Withoutevent, the project's latest builder change; with it, that public change of this project (404otherwise; an id that is not a ledger id is400 invalid_event). The answer addschange(HeyChangeExplanation,change-explain-v1): -stage.observed—announcement,code,maintenance,release,deployment,upgrade,interface,source_verification(the explorer showing verified source; never a deployment),site_change,owner_update,hey_reading— withstage.notObserved(code is not a deployment; an announcement is not code); -reportedBy.kind(team_self_report,team_source,chain_record,explorer_record,third_party_record,hey_reading) andcorroboration(corroboratedonly by a record HEY read itself — the chain, the explorer, a package version published from the same repository with the release's exact version, or HEY's review); -releaseDeployment.state—establishedonly when the stored release text names the exact contract or implementation address the project holds; never by timing (not_established, reasonno_exact_referenceorrelease_text_truncated); -activity— calls to a contract tied to the change, own functions (ownFunctionCalls) apart from ERC-20 calls (tokenStandardCalls), over the seven days ending on the coverage's newest day;SHARED_INFRASTRUCTUREfor a shared contract,NOT_WATCHED/NOT_READnever zero;successis alwaysnot_measured;aroundUrlopens the before/after read (observed context, never a cause); -time—occurredAt(null when no source dates it),precision,detectedAt,recordedAt,basis(source_datedorobserved_by_hey); -standing— evidence withdrawn since is never cited and is listed here;unknowns[]— what HEY does not know.- The snapshot's Research Summary: the
latestChangeline carrieschange, the same object (HeySummaryLine.change). The line'stext,tagandevidenceare unchanged. - The partner builder card (
GET /api/v1/builder):latest_change.explanation—headline,stage,reported_by,corroboration,release_deployment,activity,call_success(not_measured),time_basis,standing,unknowns,explain_url; null when HEY could not read it. GET /api/projects/{slug}/around/{eventId}: a fieldownCalls— calls per covered day to the watched contracts' own functions, ERC-20 transfers and approvals left out.callskeeps its meaning (ERC-20 included).
- The partner builder card's
— An account found by name, and the partner card's market words
Changed
- A truth repair (2026-10-19 audit):
officialX.corroborationis nevermutual_site_linkfor an account HEY found by name and no person verified — the site never linked it, so the link is one-way.x_urlin the CSV export andofficialXin the/dataproject records are left empty or out for a held or dead account rather than named as an official link.
Added
officialX.foundByHey(cards, profiles, SDKHeyOfficialX):truewhen HEY found the account by the project's name — its profile links the project's site, but the project's own pages do not name it — and no person has verified it yet. Such an account is nevercorroboration: mutual_site_link, its posts are not shown and it is never tagged.falseotherwise. Additive.- The partner card's
market_status(GET /api/v1/scan,GET /api/v1/builder) gainsreason(the stored classifier reason, or null) andlabel(the words the project page prints, e.g. "Launch pool only", "Readings not confirmed").statusandobserved_atkeep their meaning. Additive. - The CSV export of projects gains a last column,
x_withheld: whyx_urlis empty for an account HEY holds back (handle_reassigned,links_other_project,not_the_project,SUSPENDED,UNAVAILABLEorNOT_FOUND).
- A truth repair (2026-10-19 audit):
— Partner reads say what the page says
Changed
officialX.linkHeldgains a second value on 2026-10-19,not_the_project: a moderator held the account the project's sources name as not the project's (a famous person's, a company's or a placeholder the page borrowed). Do not link or tag it. Additive. The search keys (?q=on/api/projects, suggest, MCPfind_projects) no longer match the handle of an account HEY read as suspended, gone, reassigned, another project's or held.officialX.linkHeld(cards, profiles, SDKHeyOfficialX, MCP lines) gains a value,links_other_project: the account's own profile links another published project's site and not this project's, so the handle is that project's account. Do not link or tag it. Additive (machine rule 10):handle_reassignedandnullkeep their meaning; a client that knows only those should treat any non-null value as "held".has=xand card completeness (the default order's head start) no longer count an official X account HEY last read asSUSPENDEDorNOT_FOUND(founder ruling, 2026-10-18).UNAVAILABLEand unread accounts still count. No field changed meaning:officialXis still sent for such a card, with itsstatus.GET /api/v1/builder:hey_status_labelandhey_status_helpare the project page's own words for the status. An UNKNOWN status read "Activity unknown" here while the page,/api/v1/scan(status_label) and/api/token/{chainId}/{address}(activityLabel) said "No builder source linked" or "Activity not measurable"; the three by-contract reads now print the same words for every state.hey_statusandstatusare unchanged.- A code week still running reads by absolute days in every partner field — "Code changes, week starting 2026-10-12 (to 2026-10-17)", never a range ending in days that have not happened:
/api/v1/builder'slatest_meaningful_ship.titleandlatest_change.summary(aslast_code_activity.summaryhas since 2026-10-16),/api/v1/scan'sactivity.last_ship_titleand/api/token/{chainId}/{address}'sproject.lastShip.title. A finished week keeps its range. GET /apistarts with the agent contract (/api/agent) and names one read by contract, the Partner Card (/api/v1/builder);/api/tokenand/api/v1/scanare described as the chat-line and Chit-card shapes of the same answer.
Added
officialX.status,officialX.statusReasonandofficialX.checkedAton every project card (/api/projectsand its tabs) and on the dossier (/api/projects/{slug}): what HEY's last read of the project's official X account found —ACTIVE,SUSPENDED,UNAVAILABLE,NOT_FOUND, ornullwithstatusReason(not_read,read_failed) when HEY holds no read of the handle — and when.handleandurlare unchanged. Identity context only: no status, score, order or filter reads it. OpenAPI#/components/schemas/OfficialX; SDK typesHeyOfficialX,HeyOfficialXStatus. Every account readsstatus: nulluntil the reads are switched on.- MCP
find_projectsand the other listing lines state an official X account HEY last read as suspended, unavailable or not found, with the date. officialX.linkHeld,officialX.corroborationandofficialX.corroborationCheckedAton every card and on the dossier (founder rulings, 2026-10-18):linkHeld: "handle_reassigned"when the handle now answers for a different X account than the one HEY first read — HEY holds the link until a moderator confirms, so do not link it;corroboration: "mutual_site_link"when the account's profile links the project's own site, as ofcorroborationCheckedAt— trust in the account itself, never a source's confidence, indexing, status, score or order. All three arenullotherwise. SDKHeyOfficialXgains them as optional fields; MCP listing lines state a held handle and a mutual link, dated.- Every answer the per-minute bucket counted states it:
ratelimit-limitandratelimit-policy(120;w=60), and on a private (keyed) answerratelimit-remaining. An anonymous answer is cached at the edge and served to other callers, so it never carries one caller's remainder. All three are readable from a browser. - A write method sent to
/api/v1/builder,/api/v1/scan,/api/token/...or/api/projectsanswers405 method_not_allowedin the error envelope, with its CORS headers andallow(it was an empty body with no content type). - The error table names
invalid_evidence_id,invalid_cursor,invalid_json,source_requiredandmethod_not_allowed, which the API already answered. - OpenAPI:
401,403and503on every operation; the Partner Card's404typed (PartnerNotFound, withscan_url) and itstext/plainandtext/markdownforms; the token lookup typed (TokenLookup);components.headersfor the request id, the API version, the budget and the monthly allowance;/api/reports/monthly[/{month}],/api/agent/stats,/api/export/projects,/api/export/shipsand/api/share/chain-day; a definition for everytabvalue; and links to this changelog. /.well-known/security.txt: where to report a vulnerability in HEY itself.- This changelog and its feed.
- SDK 0.3.3 — prepared in the repository; npm still serves 0.3.2 until it is published, so
npm i @hey-research-lab/sdkinstalls 0.3.2. In 0.3.3 the walks (pages(),items(),sync()) pace their pages by the stated budget and wait out a temporary429by itsretry-after, at most three times and never longer than 60 seconds (rateLimit: { wait: 'walks' | 'always' | 'never' }); a single call still throws unlesswaitis'always', and a monthlyquotais never waited for.HeyApiErrorcarries the server's code (apiCode) andrequestId. The types added on 2026-10-17 (below) are in the package. In 0.3.2 nothing waits: every429throws aHeyApiError(code: 'rate_limited', withretryAfterSeconds) for the caller to wait out. GET /api/v1/builder's404for a contract HEY has not published carriespublishedNamesakes(and thetextandmdforms its line) where a published project's token shares this token's name or ticker — the same shape and sentence as/api/v1/scan's not-found card, so a partner bot asked about a copy can say which published project it imitates. Absent when none does.- MCP (hosted and stdio): a slug HEY retired when its page was renamed or merged answers for the page it moved to, says so first in the text ("Resolved from the slug …"), and carries
resolvedFrom: { slug, to }instructuredContent(research_answer:subject.resolvedFrom.slug). The hosted endpoint failed every such slug with an error naming its internal address. GET /api/evidence/{id}for a ship (additive):countedAs—counted(it counts itself),counted_once_with(one of a deploy run, a repository's release day, a code week or a prerelease week, which the score counts once;countedWith: { id, group }names the ship that stands for it) orcontext(it does not count;countedAsReasonsays why) — andcountedAsSentence, the receipt's one sentence for it. About 3,000 receipts said a folded ship "does not count, it is context" when it had counted once with its group.countsAsBuildingkeeps its meaning. MCPget_evidenceprints the sentence.GET /api/projects/{slug}/built-on: thedefinitionand sidesentencesay a code link is a reference — the project's own code names the other project's token — never "builds on"; a hook link keeps "builds on". Keys, counts and the edges the rules accept are unchanged.
Fixed
- A bad key sent as
x-api-keyis told to remove that header; the401named theauthorizationheader whichever one was sent. GET /api/v1/builder'slast_code_activity.commitsandactive_daysare the newest code week's own counts — what its receipt (/api/evidence/ship:<uuid>,codeWeek.commits) says — not the whole read window behind the week's summary (up to ninety days), which printed "8 commits" for a week whose receipt counted 3.commits_partialsays the week's count is a floor; a week HEY holds no count for isnull, never the window's figure. The fields keep their meaning: the week's count.- MCP
get_changesandget_project_timeline, and thehey://changes/latestand project timeline resources: a page over the 24 KB answer is asked for again with a smallerlimituntil it fits, so the cursor the text prints reads on from the last row shown. It printed the full page's cursor under a page cut on its rows, and an agent following it skipped the cut events — retractions included (16 of 100 on one live call). A page that still cannot fit prints no cursor.
— New builders means builders
Changed
GET /api/projects?tab=new-builderslists projects published on HEY in the last 7 days with a builder source HEY reads and at least one counted ship, the most recent first ship first. Before, it listed every page published in the window: of 192 rows, 171 read "Activity unknown" with no builder source, under a name that promised builders. On 2026-10-18 the tab held 47 projects where the old population held 379. This is a truth repair, kept under its name by the founder's ruling; the old population istab=new-on-hey. A partner pollingnew-buildersfor every new page should switch tonew-on-hey.
Added
tab=new-on-hey: every project published on HEY in the last 7 days, builder or not, newest first — whatnew-builderslisted before.GET /api/projects/{slug}/built-on: which builders a project builds on and which build on it, named in code or running on a hook, each link with its evidence. Never a partnership, never an on-chain interaction./api/changes:cursor=continues any page in the mode that issued it;ignoredParametersnames a parameter the ledger does not read./api/projectsreadsqueryasqand names ignored parameters the same way.- The agent contract sets cache-busters and campaign tags aside (
query.ignoredParameters) instead of answering 400;what_changedcarriesdata.resume; an ambiguous name lists up to eight candidates with ticker, activity and catalog status, anderror.candidatesTotal. /api/chain/accelerating:judged,notMeasuredand, for an empty list,reason.underTheRadar(HELD,NOT_HELDorNOT_MEASUREDwith its reason) on the dossier'sscoreand the snapshot'sbuild.
— Today's words beside the stored ones
Changed
/api/changeswithout a cursor (or withbefore) is newest first by each event's first arrival, so a revised old event never leads;afteranddetectedSincekeep ledger order.
Added
- Ships and timeline entries:
displayTitle(a running code week in today's words;titleis unchanged) andcodeWeek.complete. Change upserts and evidence receipts:summaryCurrent. - Market detail:
distribution.figuresWithheld,pools;marketStatusLabel,distribution.staleandtvlReadon the token market;tokenMarket.labelon project cards. - Scores:
cohortEvaluatedAt; the Still Building withheld reasonno_tracked_high.