Skip to content

DevelopersIntegration guide

Putting HEY in your bot

One call by contract address, the line to render from it, and the four things not to do with it.

Someone pastes a contract address into a chat. You want one line that says whether anyone is actually building it. This is how, end to end, in one HTTP call and no account.

The one call

GET https://heyresearch.xyz/api/token/4663/{contractAddress}

No key. No account. No signup. 120 requests a minute per client, cached 60 seconds at the edge, and readable from a browser as well as a server — access-control-allow-origin: * is set and the preflight is answered.

Try it now, on a project that is shipping:

curl -s https://heyresearch.xyz/api/token/4663/0xebb4c5b97e4117e30ec82ce025e6f21dded05436

What comes back

{
  "chainId": 4663,
  "contractAddress": "0xebb4…5436",
  "status": "published",
  "project": {
    "slug": "darkroute",
    "name": "DarkRoute",
    "symbol": "dark",
    "url": "https://heyresearch.xyz/project/darkroute",
    "activityStatus": "SHIPPING",
    "activityLabel": "Shipping",
    "activityHelp": "Shipped something meaningful in the last 7 days.",
    "shipsLast30Days": 4,
    "lastShipAt": "2026-09-16T02:38:59.000Z",
    "lastShip": {
      "title": "Active development: 3 commits in the last 90 days across 1 contributor",
      "publishedAt": "2026-09-16T02:38:59.000Z",
      "sourceUrl": "https://github.com/darkrouteRH/contracts"
    },
    "deployedAt": "2026-09-08T09:25:46.000Z",
    "badgeUrl": "https://heyresearch.xyz/badge/darkroute.svg"
  },
  "scanUrl": "https://heyresearch.xyz/scan?address=0xebb4…5436",
  "disclaimer": "…"
}
Field What it is
activityStatus One of SHIPPING, ACTIVE, QUIET, DORMANT, RESUMED, UNKNOWN. Derived from what a project ships, never from price.
activityLabel The same status in words. Use this rather than mapping the enum yourself — see below.
shipsLast30Days Ships in the window the field names, counted exactly the way the project page counts them. Your number and the page a reader lands on cannot disagree.
lastShip The most recent one, with sourceUrl — the actual commit, release or post it was read from. Link it.
deployedAt When the contract went on chain, read from the block. Absent where HEY has not read one.
badgeUrl A ready-made SVG: name, status, last ship. Drop it in the card if it fits.
url The page behind all of it. Always render this.

The three answers you must handle

Case HTTP Do this
status: "published" 200 Render the line.
status: "unknown" 200 HEY has no published page. There is no project. Offer scanUrl.
error 400 Not an address, or not this chain. Say nothing about the token.

Why unknown is a 200 and not a 404. Most addresses pasted into a group chat are not indexed projects. A 404 would make your ordinary case an error branch. So the shape is uniform, you check one field, and scanUrl gives you somewhere to send the person: HEY reads the chain live for an address it has never seen.

An address HEY holds but has not reviewed also answers unknown. An unreviewed launch record is not a project, and this endpoint will not pretend otherwise.

The bot, in about thirty lines

const HEY = 'https://heyresearch.xyz';

async function heyLine(address) {
  const r = await fetch(`${HEY}/api/token/4663/${address}`);
  // 400 means the address is not one, or not this chain.
  if (r.status === 400) return null;
  if (!r.ok) return null;           // stay quiet on a hiccup

  const d = await r.json();

  if (d.status !== 'published') {
    return `HEY: not indexed yet · read the chain → ${d.scanUrl}`;
  }

  const p = d.project;
  const ships = p.shipsLast30Days === 1 ? '1 ship' : `${p.shipsLast30Days} ships`;
  const when = p.lastShipAt ? `, last ${daysAgo(p.lastShipAt)}` : '';

  // p.activityLabel is HEY's own wording. Do not invent your own.
  return `HEY: ${p.activityLabel} · ${ships} in 30d${when} → ${p.url}`;
}

function daysAgo(iso) {
  const days = Math.floor((Date.now() - new Date(iso)) / 86400000);
  return days === 0 ? 'today' : days === 1 ? 'yesterday' : `${days}d ago`;
}

Which renders as:

HEY: Shipping · 4 ships in 30d, last today → heyresearch.xyz/project/darkroute
HEY: not indexed yet · read the chain → heyresearch.xyz/scan?address=0x7655…d78a

Four things not to do

Do not translate the status yourself. Use activityLabel. Left to themselves, integrators turn DORMANT into dead and UNKNOWN into suspicious. Dormant means HEY has observed no public activity for a long time. It is not the same as abandoned, and unknown is a gap in our knowledge, not a fault of the project. The labels ship in the payload so nobody has to guess.

Do not present it as a risk reading. HEY gives no score, no grade and no safe/unsafe verdict, anywhere, by design — the moment there is one number on a card, people read it as a rating. If you want a risk signal, put one from a tool that actually does that work beside our line. Honeypot: clean · HEY: Shipping, 4 ships in 30d is a better card than either of us alone, and neither is pretending to be the other.

Do not drop the link. Whatever you render, carry url. Someone who sees a HEY line should be one tap from the evidence behind it. This is the one condition of use.

Do not poll POST /api/scan in a hot path. That second, heavier endpoint reads the chain live for an address nobody has indexed. It allows ten requests an hour, is never cached, and spends a budget HEY's scheduled indexing needs first. Link people to scanUrl instead — that is a page, and it costs you nothing.

Limits, caching and failure

  • 120 requests a minute per client. Over that, 429 with a retry-after in seconds.
  • Answers are cached 60 seconds and served stale for five minutes while they refresh. Caching on your side beyond that buys nothing; the catalogue moves on HEY's worker schedule, not per request.
  • Dates are ISO 8601, UTC, always.
  • Absent means unknown. A field HEY has no answer for is left out — never sent as null or 0. Do not fill a gap with a zero: a missing deployedAt means HEY has not read one, not that the contract was deployed at the epoch.
  • If HEY is down, say nothing rather than guessing. A bot that omits a line is fine; one that invents one is not.

If you want more

The same public API carries the rest of what HEY knows, on the same terms — no key, 120 a minute. See the public read API for every endpoint, field and limit, and the MCP server to give an assistant the same index, read-only.

What HEY will never send you

Worth stating plainly, so you do not design around something that is not coming.

  • No wallet analytics, no PnL, no smart-money labels, no holder lists read as a claim about people. HEY does not build it. The one thing it does keep is a daily snapshot of a single token's largest balances, which draws the distribution map on that token's market page — no API payload carries it, and nothing in it reaches a status, a score or an ordering.
  • No risk score, no safety grade, no verdict.
  • No paid placement in any ordering. Nothing anyone pays HEY changes a status, a rank or a figure.
  • No claim that a project which keeps building will be worth more. Those are two different things and HEY keeps them apart.

What is left is narrow on purpose: who is building, what they shipped, when, and where HEY read it.