Skip to content

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.

  1. — Proof of Ship attestations

    Changed

    • GET /api/v1/proof-of-ship/attestation counts a ship only when HEY first recorded it inside [since, until] (a ship read after until no 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. evidenceIds lists exactly what was counted; definition says so. Activity status and scores are unchanged.
    • builder ties 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). Otherwise 403 builder_not_tied, as before.

    Added

    • slug accepts an old slug that redirects to a published page; HEY signs over the slug as asked. The answer adds currentSlug. 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 sorted ship:<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-source ShipEscrow contract — only for a payout builder HEY's evidence ties to the project (builderTie: wallet_claim or token_deployer). New error codes escrow_not_configured (400), builder_not_tied (403) and not_configured (503). Additive: no existing field or route changes. See Proof of Ship.
  2. — 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 — while catalogue.marketCoverage.liveMarket counted tokens only. The documented meaning ("card facts the project must have") is unchanged; the list now matches it.
    • A repeated has= or type= 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 400 bad_request, never found: false, reason: "chain".
    • A token's earlier depth reading older than 7 days is no longer sent as liquidity on 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.methodEvents is null where HEY holds no usage figures (no contract watched), never zeros. The key is always sent; SDK HeyUsageSummary.methodEvents is typed … | null.
    • activity_applies_to_token (truth repair) on /api/v1/scan, /api/v1/builder and /api/token/{chainId}/{address} is also false for a token whose verification reason is site_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 was true for that case, which the project page and the scorer already treated as not the project's. Such a card carries no cta, as for MISMATCH.
    • /api/projects/{slug}/market lastTradeDay counts 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 project as slug and slug as project, and a list argument sent as one string (domain: "market,build") as the list REST reads; get_changes prints a numeric move as money or a rounded count; find_projects dates a liquidity figure read more than a day ago.

    Added

    • adjustedParameters on GET /api/projects and GET /api/ships: each value read otherwise than sent — limit above 48 or not a number, offset below 0 or above 20,000, a single-value parameter sent twice — with parameter, value, readAs and reason (above_maximum, below_minimum, not_a_number, not_an_integer, repeated). The values are capped as before; now the answer says so.
    • activity.releases_measured on the /api/v1/scan card: false when HEY reads no repository, changelog or feed releases come from, or building is not measured. releases_30d keeps its value and meaning; print it only beside releases_measured: true.
    • identity.officialX on GET /api/projects/{slug}/snapshot (and MCP get_project_snapshot), the card's own field: status, checkedAt, linkHeld, corroboration.
    • eventsDay beside events24h on the project detail's onchainActivity and the snapshot's onchain: 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) and chain.tokensTradedDay on reports written since: tokensTraded is the busiest day's distinct count, never a total.

    Fixed

    • The OpenAPI descriptions of /api/v1/scan, /api/v1/builder and /api/token/{chainId}/{address} name the 400 for a well-formed address that is not a token identity (the burn address).
  3. — One change, explained

    Changed

    • The partner builder card's latest_change now 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>] (SDK HeyExplainFact, projects.explain(slug, 'build.change', { event }); MCP explain_fact with event): one change explained, from HEY's own tables, with no provider or model call. Without event, the project's latest builder change; with it, that public change of this project (404 otherwise; an id that is not a ledger id is 400 invalid_event). The answer adds change (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 — with stage.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) and corroboration (corroborated only 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 — established only when the stored release text names the exact contract or implementation address the project holds; never by timing (not_established, reason no_exact_reference or release_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_INFRASTRUCTURE for a shared contract, NOT_WATCHED/NOT_READ never zero; success is always not_measured; aroundUrl opens the before/after read (observed context, never a cause); - time — occurredAt (null when no source dates it), precision, detectedAt, recordedAt, basis (source_dated or observed_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 latestChange line carries change, the same object (HeySummaryLine.change). The line's text, tag and evidence are 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 field ownCalls — calls per covered day to the watched contracts' own functions, ERC-20 transfers and approvals left out. calls keeps its meaning (ERC-20 included).
  4. — An account found by name, and the partner card's market words

    Changed

    • A truth repair (2026-10-19 audit): officialX.corroboration is never mutual_site_link for an account HEY found by name and no person verified — the site never linked it, so the link is one-way. x_url in the CSV export and officialX in the /data project records are left empty or out for a held or dead account rather than named as an official link.

    Added

    • officialX.foundByHey (cards, profiles, SDK HeyOfficialX): true when 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 never corroboration: mutual_site_link, its posts are not shown and it is never tagged. false otherwise. Additive.
    • The partner card's market_status (GET /api/v1/scan, GET /api/v1/builder) gains reason (the stored classifier reason, or null) and label (the words the project page prints, e.g. "Launch pool only", "Readings not confirmed"). status and observed_at keep their meaning. Additive.
    • The CSV export of projects gains a last column, x_withheld: why x_url is empty for an account HEY holds back (handle_reassigned, links_other_project, not_the_project, SUSPENDED, UNAVAILABLE or NOT_FOUND).
  5. — Partner reads say what the page says

    Changed

    • officialX.linkHeld gains 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, MCP find_projects) no longer match the handle of an account HEY read as suspended, gone, reassigned, another project's or held.
    • officialX.linkHeld (cards, profiles, SDK HeyOfficialX, 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_reassigned and null keep their meaning; a client that knows only those should treat any non-null value as "held".
    • has=x and card completeness (the default order's head start) no longer count an official X account HEY last read as SUSPENDED or NOT_FOUND (founder ruling, 2026-10-18). UNAVAILABLE and unread accounts still count. No field changed meaning: officialX is still sent for such a card, with its status.
    • GET /api/v1/builder: hey_status_label and hey_status_help are 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_status and status are 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's latest_meaningful_ship.title and latest_change.summary (as last_code_activity.summary has since 2026-10-16), /api/v1/scan's activity.last_ship_title and /api/token/{chainId}/{address}'s project.lastShip.title. A finished week keeps its range.
    • GET /api starts with the agent contract (/api/agent) and names one read by contract, the Partner Card (/api/v1/builder); /api/token and /api/v1/scan are described as the chat-line and Chit-card shapes of the same answer.

    Added

    • officialX.status, officialX.statusReason and officialX.checkedAt on every project card (/api/projects and 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, or null with statusReason (not_read, read_failed) when HEY holds no read of the handle — and when. handle and url are unchanged. Identity context only: no status, score, order or filter reads it. OpenAPI #/components/schemas/OfficialX; SDK types HeyOfficialX, HeyOfficialXStatus. Every account reads status: null until the reads are switched on.
    • MCP find_projects and the other listing lines state an official X account HEY last read as suspended, unavailable or not found, with the date.
    • officialX.linkHeld, officialX.corroboration and officialX.corroborationCheckedAt on 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 of corroborationCheckedAt — trust in the account itself, never a source's confidence, indexing, status, score or order. All three are null otherwise. SDK HeyOfficialX gains 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-limit and ratelimit-policy (120;w=60), and on a private (keyed) answer ratelimit-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/projects answers 405 method_not_allowed in the error envelope, with its CORS headers and allow (it was an empty body with no content type).
    • The error table names invalid_evidence_id, invalid_cursor, invalid_json, source_required and method_not_allowed, which the API already answered.
    • OpenAPI: 401, 403 and 503 on every operation; the Partner Card's 404 typed (PartnerNotFound, with scan_url) and its text/plain and text/markdown forms; the token lookup typed (TokenLookup); components.headers for the request id, the API version, the budget and the monthly allowance; /api/reports/monthly[/{month}], /api/agent/stats, /api/export/projects, /api/export/ships and /api/share/chain-day; a definition for every tab value; 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/sdk installs 0.3.2. In 0.3.3 the walks (pages(), items(), sync()) pace their pages by the stated budget and wait out a temporary 429 by its retry-after, at most three times and never longer than 60 seconds (rateLimit: { wait: 'walks' | 'always' | 'never' }); a single call still throws unless wait is 'always', and a monthly quota is never waited for. HeyApiError carries the server's code (apiCode) and requestId. The types added on 2026-10-17 (below) are in the package. In 0.3.2 nothing waits: every 429 throws a HeyApiError (code: 'rate_limited', with retryAfterSeconds) for the caller to wait out.
    • GET /api/v1/builder's 404 for a contract HEY has not published carries publishedNamesakes (and the text and md forms 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 } in structuredContent (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) or context (it does not count; countedAsReason says why) — and countedAsSentence, 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. countsAsBuilding keeps its meaning. MCP get_evidence prints the sentence.
    • GET /api/projects/{slug}/built-on: the definition and side sentence say 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-key is told to remove that header; the 401 named the authorization header whichever one was sent.
    • GET /api/v1/builder's last_code_activity.commits and active_days are 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_partial says the week's count is a floor; a week HEY holds no count for is null, never the window's figure. The fields keep their meaning: the week's count.
    • MCP get_changes and get_project_timeline, and the hey://changes/latest and project timeline resources: a page over the 24 KB answer is asked for again with a smaller limit until 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.
  6. — New builders means builders

    Changed

    • GET /api/projects?tab=new-builders lists 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 is tab=new-on-hey. A partner polling new-builders for every new page should switch to new-on-hey.

    Added

    • tab=new-on-hey: every project published on HEY in the last 7 days, builder or not, newest first — what new-builders listed 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; ignoredParameters names a parameter the ledger does not read. /api/projects reads query as q and names ignored parameters the same way.
    • The agent contract sets cache-busters and campaign tags aside (query.ignoredParameters) instead of answering 400; what_changed carries data.resume; an ambiguous name lists up to eight candidates with ticker, activity and catalog status, and error.candidatesTotal.
    • /api/chain/accelerating: judged, notMeasured and, for an empty list, reason.
    • underTheRadar (HELD, NOT_HELD or NOT_MEASURED with its reason) on the dossier's score and the snapshot's build.
  7. — Today's words beside the stored ones

    Changed

    • /api/changes without a cursor (or with before) is newest first by each event's first arrival, so a revised old event never leads; after and detectedSince keep ledger order.

    Added

    • Ships and timeline entries: displayTitle (a running code week in today's words; title is unchanged) and codeWeek.complete. Change upserts and evidence receipts: summaryCurrent.
    • Market detail: distribution.figuresWithheld, pools; marketStatusLabel, distribution.stale and tvlRead on the token market; tokenMarket.label on project cards.
    • Scores: cohortEvaluatedAt; the Still Building withheld reason no_tracked_high.