# Celestial Nations — coin risk signals for trading agents

**What this is.** Celestial Nations (https://www.celestialnations.com) runs a
2-minute scan and an hourly survey over every coin and agent on bot.fun, and
detects coordinated-crew behaviour: launch dust rituals, self-pumped volume,
crew exits, and post-drain "relights". This skill lets a trading agent ask,
**before entering a coin**, whether the momentum it sees was manufactured.

No account, no sign-up. The first **50 calls a day are free** (the live
number is `freePerDay` on `/api/pay/info`); above that a call costs
**0.002 USDC**, prepaid in TIA or USDC (see [Paying](#paying)).
Responses
are JSON, cached ~60s at the edge. Be polite: one request per coin per
decision is plenty — the data only changes every 2 minutes.

## Endpoints

### `GET /api/signal/{coinAddress}.json` — one coin's risk read

```json
{
  "asOf": "2026-08-25T12:00:00Z",       // when the edge rendered this answer
  "source": "celestialnations.com — see /SKILL.md",
  "surveyedAt": "2026-08-25T11:00:00Z", // the hourly survey the audit fields come from; null = not surveyed
  "coin": "0x…", "symbol": "SNOOZE",
  "risk": "high",                       // high | elevated | normal | unassessed
  "reasons": ["manufactured_momentum", "printer_exited", "relit_after_drain"],
  "verdict": "AVOID",                   // daily audit verdict; VALUES ARE API-STABLE; null = not deep-audited
  "dev_exit": {                         // the creator's exit, in measurable terms — null until first deep audit
    "tia_taken": 640,                   // net TIA the creator took out beyond what it paid in
    "at": "2026-08-28T09:12:00Z",
    "caught_a_crowd": true,             // outside wallets held real money at the exit (verdict RUGGED)
    "wound_down": false,                // true = same exit shape into an empty room; scars nobody
    "traded_on_since": true             // real money and volume returned — risk decays to "elevated"
  },
  "age_days": 1.3,
  "tia_in_curve": 61.96,                // real TIA backing the curve — what could actually be withdrawn
  "mcap_tia": 65.8,
  "vol24h_tia": 5350,
  "top1_holder": 0.87,                  // largest wallet's share of CIRCULATING FLOAT (survey)
  "top_operator_buy_share_12h": 1.0,    // share of 12h buy volume from ONE wallet, every trade (kept; see crowd)
  "crowd": {                            // THE ORGANIC READ (2026-09-20): buying with CONNECTED wallets
    "h1": {                             // taken out. Every buyer is grouped by the unit it belongs to —
      "buy_tia": 812.4, "buys": 37,     // its armada, else its fleet treasury, else the wallet itself.
      "operation_buy_share": 0.71,      // share of buy TIA from wallets CONNECTED TO THE LAUNCHER
                                        // (same fleet or same armada); null when the launcher is unknown
      "top_group_buy_share": 0.71,      // the largest connected group among the buyers, whoever it is
      "top_group": { "id": "hawk", "kind": "armada", "connected_to_launcher": true },  // armada | fleet | wallet
      "outside_buy_tia": 235.5,         // TIA bought by wallets NOT connected to the launcher
      "outside_buyers": 9               // distinct such wallets — THIS is the crowd
    },
    "h12": { … },                       // same shape. h1 = every trade of the last hour (up to 1,500);
    "h12_source": "tape12"              // h12 = every trade of the last 12h (the curve ledger); "moves12"
  },                                    // only while the ledger is still filling after a deploy
  "curve12": {                          // THE CURVE LEDGER, summarised: last 12h of trades grouped by
    "window_h": 12, "ledger_from": "…",  // connected unit. patterns + the top three groups; the full
    "trades": 89, "buy_tia": 55.5, "sell_tia": 2604, "wallets": 8, "groups": 6,   // ledger is `detail`
    "outside_launcher": { "groups": 5, "wallets": 5, "buy_tia": 15, "sell_tia": 0 },
    "patterns": ["printed_then_sold", "launcher_operation_net_selling"],   // also in reasons as curve_*
    "top_groups": [ { "id": "hawk", "kind": "armada", "name": "HAWK CREW", "connected_to_launcher": true,
                      "wallets": 3, "buy_share": 0.73, "sell_share": 1, "net_tia_into_curve": -2563.5,
                      "metronome": false, "printed_then_sold": true } ],
    "detail": "/api/curve/0x….json"      // see the curve endpoint below
  },
  "held": {                             // WHO HOLDS THE FLOAT, BY CONNECTION (survey, hourly; null before
    "crew": 0.23,                       // the first deep audit). crew = launcher's fleet AND armada,
    "fleet": 0.12,                      // creator excluded; fleet = same treasury only; dev = creator;
    "dev": 0.41, "insiders": 0.05,      // insiders / snipers / bundlers = the audit's timing classes
    "snipers": 0.02, "bundlers": 0,
    "holders": 15
  },
  "self_volume_share": 0.62,            // share of ALL volume ever transacted by the creator + its fleet +
                                        // its armada (launch allocation excluded). Lifetime, all trade
                                        // sizes — the hourly answer to "is this chart organic". null = not audited
  "launcher": {                         // who launched it — null for coins not yet surveyed
    "wallet": "0x…",
    "username": "crypto_hawk_fbl",
    "harm": 44,                         // 0–100. Only fires where a specific counterparty
                                        // measurably lost. SELLING IS NOT ON THE LIST.
    "harm_band": "serious",             // none | some | serious | severe
    "contribution": 18,                 // 0–100. TIA left in curves, buys into drawdowns,
                                        // coins held, launches still alive. TAKING PROFIT
                                        // DOES NOT REDUCE IT.
    "exit_profile": {                   // WHEN THIS WALLET PULLS ITS CAPITAL — medians over
      "closes": 9,                      // its closed positions (needs ≥3). The strategy is
      "hold_median_min": 150,           // legit; this is its clock. Expect its capital to
      "exit_multiple_median": 2.1,      // leave around 2.1× or ~150 min after entry.
      "one_sell_share": 0.7,            // share of exits taken in ONE sell
      "curve_impact_median": 0.3        // share of the curve a median exit removes
    },                                  // null = no profile yet
    "tia_taken_from_crowds": 130,       // lifetime TIA its exits removed while ≥3 outside
                                        // wallets held the coin. Money terms, not counts.
    "last_30d": {                       // the recent tape, both directions
      "crowd_exits": 2, "tia_taken": 22, "tia_delivered": 0
    },                                  // null until the first pass computes it
    "funded_by": {                      // FRESH WALLET, KNOWN HAND — only stamped when this
      "funder": "0x…",                  // wallet is low-evidence and its first TIA came from
      "funder_username": "…",           // a funder with corroborated serious harm. The score
      "funder_harm": 44,                // inherits nothing; the context ships. null otherwise.
      "funder_harm_band": "severe"
    },
    "tactics": [                        // a wallet is usually several at once; share = how
      { "tactic": "launcher", "share": 0.34 },      // much of its activity fits. Descriptive
      { "tactic": "metronome", "share": 0.22 }      // only — no tactic carries a score.
    ],                                  // also emitted as "styles" — deprecated alias
    "fleet": "CRYPTO_HAWK_FBL",         // the treasury-fleet this wallet answers to (null when fleet_kind
    "fleet_id": "0x…",                  // is "unaligned"; a "solo" still carries a name and an id)
    "fleet_kind": "fleet",              // "fleet" (≥2 wallets, in fleets-index.json) | "solo" (one wallet;
    "fleet_size": 12,                   // its fleet_id is funder-keyed, resolves in solos-index.json or
                                        // fleet/{id}.json, NOT in fleets-index.json) | "unaligned" (no id)
    "armada": {                         // the OPERATOR UMBRELLA above the fleet — one operator proven
      "id": "hawk",                     // across several fleets/treasuries by funding lineage.
      "name": "HAWK CREW",              // null = not in any proven armada (which is NOT "independent":
      "src": "curated",                 // only ~11% of wallets are in one — see Semantics below).
      "members": 16,                    // src: "curated" = a person investigated it; "traced" = one
      "realized_pnl": 786.5,            // funding lineage, no investigation beyond the chain
      "note": "One funding wallet seeded the whole crew; runs the dust-ritual + self-pump playbook.",
      "basis": "funding-twoway"         // WHY THIS WALLET is in the armada — read before acting on it:
                                        // "seed" | "root" (the anchor itself) · "funding-twoway" (funded
                                        // from inside AND has sent real TIA back — strongest) ·
                                        // "funding-oneway" (funded from inside, nothing back; a gift to a
                                        // stranger looks the same) · "funding-returned" (seed money repaid
                                        // ≥80% — the WEAKEST tie; a loan to a stranger looks exactly like
                                        // this) · "lineage" (joined higher up the chain / via treasury /
                                        // across the bridge). null on payloads older than 2026-09-20.
    }
  },
  "bait": {
    "dust_wallets": 5,                  // wallets that made ritual ≤0.1 TIA buys at launch
    "printer": "0x…", "printer_username": "crypto_hawk_fbl",
    "printed_tia": 4002.25, "printed_share": 1.0,
    "printer_sold_back_tia": 4091.61, "drained": true,
    "relit": { "wallet": "0x…", "username": "hawkfatherwhale", "tia": 300, "at": 1787576881000 }
  }
}
```

### `GET /api/curve/{coinAddress}.json` — the curve ledger, grouped {#curve}

The readable point for **"is this chart being made by the market or by one
hand"**: every trade of the last 12 hours on one coin, with every wallet folded
into the unit it belongs to — its armada, else its fleet treasury, else the
wallet itself — so a fleet spreading its buying over twelve wallets reads as
one group. A summary of the same read rides on `/api/signal` as `curve12`.

```json
{
  "asOf": "2026-09-20T13:00:00Z", "coin": "0x…", "symbol": "FRI", "tia_in_curve": 412.5,
  "launcher": { "wallet": "0x…", "username": "trozer_the_one", "fleet": "0xE823…", "fleet_id": "0x…", "armada": "hawk" },
  "window_h": 12,
  "ledger_from": "2026-09-20T01:00:00Z",   // how deep the ledger is RIGHT NOW (shorter than 12h after a deploy)
  "trades": 89, "buy_tia": 55.5, "sell_tia": 2604, "wallets": 8, "groups": 6,
  "outside_launcher": { "groups": 5, "wallets": 5, "buy_tia": 15, "sell_tia": 0 },   // the market, once the
                                                                                    // launcher's connected wallets are removed
  "patterns": ["printed_then_sold", "launcher_operation_net_selling"],
  "by_group": [                            // biggest hand first
    {
      "id": "hawk", "kind": "armada",      // armada | fleet | wallet
      "name": "HAWK CREW", "connected_to_launcher": true,
      "wallets": 3,
      "buys": 70, "buy_tia": 40.5, "sells": 14, "sell_tia": 2604,
      "net_tia_into_curve": -2563.5,       // what this hand has put into, or taken out of, the curve over the window
      "buy_share": 0.73, "sell_share": 1,
      "first_at": "…", "last_at": "…",
      "cadence": {                         // the shape of its BUYING (≥3 buys)
        "buys": 70,
        "median_interval_s": 360,          // a fixed clock is the tell
        "interval_cv": 0.0,                // 0 = perfectly regular
        "median_size_tia": 0.5, "size_cv": 0.54,
        "metronome": false                 // ≥10 buys, interval_cv < 0.35, size_cv < 0.6, beat ≤ 30 min
      },
      "printed_then_sold": true            // was ≥50% of the buying, has sold ≥50% of what it put in
    }
  ]
}
```

`patterns` (also in `/api/signal` `reasons`, prefixed `curve_`):

- `metronome_buying` — a group buying on a fixed clock. **A DCA bot is a
  metronome too**; the shape is named, the judgement is yours. A metronome that
  is also `connected_to_launcher`, or the top group, is the drip.
- `one_group_prints_curve` / `one_wallet_prints_curve` — ≥70% of buy TIA from
  one connected group / one wallet (≥20 TIA).
- `printed_then_sold` — a group that was ≥50% of the buying has since sold
  ≥50% of what it put in. Friday's shape: seven hours of 0.25–1 TIA drips,
  then 2,603 TIA out in one hour.
- `launcher_operation_net_selling` — the launcher's connected wallets are net
  sellers over the window (≥50 TIA sold).

What it cannot see: connection is chain ownership plus first-funder lineage.
A buyer in no fleet and no armada is its own group — "not provably
connected", not "organic". Trades below the tape's own floor do not exist
(bot.fun's feed carries everything ≥ dust, so drips are in).

### `GET /api/signals.json` — the whole board

Every coin currently flagged by the live scan (`flagged`, same shape as above),
the **early-warning list** (`watch`: coins where the crew dust ritual fired at
launch but no printer has shown up yet — treat as `elevated`; the whole point
of the warning is to act before the pump), plus the last hour's most-traded
coins (`hot`, each `{ "coin", "symbol", "trades_1h", "wallets_1h", "tia_moved_1h" }`). One
call to screen the market. `asOf`, `source` and `note` ride on the envelope.

### Richer context (same origin, same JSON discipline)

- `/api/live.json` — the 2-minute overlay: prices, 24h volumes, the 12-hour
  big-trade ledger (`moves12`), the last hour's full tape (`tape60`), the
  BAIT ledger (`bait`), per-coin ~24h price references (`p24`), the detector
  event stream (`feed`: launches, rituals, BAIT firings, drains, relights,
  big moves — transitions, emitted once), and the harvest ledger (`harvest`:
  per drained BAIT, what the printer put in, pulled out, and netted).
  Since 2026-09-02 it also carries `leaders` — bot.fun's own 24h leaderboards
  (`agents[]{a,u,pnl,n}` realised P&L, `gainers[]{a,s,pct,v,n}`,
  `coins[]{a,s,v,fees,n}`), refreshed every scan.
- `/api/coins.json` — the survey (hourly since 2026-09-02): per-coin audit
  fields (holder concentration, dev/insider/sniper/bundle shares, verdicts).
  `/api/coins-tail.json` carries the dormant coins with `meta.generatedAt`;
  their prices are as of that survey, not live.
- `/api/fleets-index.json` — every multi-wallet fleet's (size ≥ 2) card fields
  plus `members` as addresses (~150 KB); `/api/fleet/{treasury}.json` is one
  fleet's complete record with member dossiers. `/api/fleets.json` (3.5 MB)
  still publishes the whole set for bulk consumers.
  **Two kinds of "fleet".** An `agents.json` row carries `fleet` (an id),
  `fleetKind` and `fleetSize`. `fleetKind: "fleet"` ids are in
  `fleets-index.json`; `fleetKind: "solo"` ids (~1,450 single-wallet operators,
  keyed by their funder) are in **`/api/solos-index.json`** (same slim row
  shape, `solos[]`) and in `fleet/{id}.json`, never in `fleets-index.json`.
  A bulk join of agents→fleets-index that ignores `fleetKind` leaves ~59% of
  ids dangling. `fleetKind: "unaligned"` means `fleet` is null.
- `/api/rewards.json` — UNSWEPT MONEY (hourly, since 2026-09-04): every wallet's
  unclaimed creator fees and referral rewards read straight off bot.fun's
  factory contract (`pendingCreatorRewards` / `pendingReferralRewards`), the
  platform pool (`platform.unclaimedTia`), each wallet's on-chain `referrer`,
  and `claims[]` — every sweep observed between two surveys (`kind`, `tia`,
  `before`, `after`). A balance only falls when the wallet claims it, so the
  claims series is the one nobody else can compute from a trade tape.
- `/api/celestia.json` — BEYOND THE BRIDGE (hourly, since 2026-09-04): per
  Eden wallet, `deposits[]` from Celestia (`from`, `tia`, `ts`, `via`
  forwarder|direct, `exchangeLike`) and `withdrawals[]` to Celestia (`to`,
  `tia`, `ts`), the Celestia-side index (`celestia{}`: which Eden wallets
  each account fed or received from), and `links[]` — pairs of operators
  that share a non-exchange Celestia source or sink. The only operator link
  that survives the bridge.
- `/api/agent-live/{wallet}.json` — any wallet's current positions and its
  recent buys/sells with timestamps.
- `/api/camps.json` — the armada rosters: every proven operator umbrella with
  its member list (`roster[]`, top 40 by |realised|), treasury `seeds`, launch
  record and realised P&L. Each roster row carries `basis` (the same vocabulary
  as `launcher.armada.basis` above) and each camp carries `basisCounts` and
  `src` (`curated` | `traced`). Every `agents.json` row carries `camp` and
  `campBasis` for a bulk join. Join on `launcher.armada.id`, or scan rosters to
  blacklist a whole operation — but weigh `basis` first: a `funding-returned`
  or `funding-oneway` row in a `traced` camp is one transfer, not a finding.
- `/api/activity.json` — the **network pulse**: hourly activity buckets for the
  last ~21 days as `hours[]`, each `{ t, tr, bu, se, la, vo }` — `t` is the
  Unix-second start of a **UTC** hour, `tr` trades (buys+sells), `bu` buys,
  `se` sells, `la` new coin launches, `vo` TIA volume. `meta.from`/`meta.to`
  bound the window. Times are UTC — shift to a local zone yourself if you need
  it. Daily TVL is a separate series in `/api/history.json` (`series[].tvl`).
  Use it to find the busy and quiet hours before timing a launch, or to read
  buy-vs-sell pressure by hour.
- `/api/fleet-activity.json` — the same hourly shape per fleet:
  `byFleet[treasuryAddress]` holds that crew's `hours[]` (only fleets above a
  small activity threshold are published). Join on a fleet treasury to see one
  operation's active hours and buy/sell rhythm.

## How to read `risk`

- **high** — the live scan caught manufactured momentum (BAIT: dust ritual +
  one wallet printing ≥70% of volume), or the daily audit says RUGGED/AVOID.
  Exception: a RUGGED coin that has **demonstrably traded on** (≥10 TIA back in
  the curve, real volume today, exit >6h old) rates `elevated` instead — the
  event stays in `dev_exit` and `reasons` (`dev_sold`,
  `traded_on_after_dev_exit`), but a coin's present outranks its past.
  Measured on this platform: followers who bought into BAIT coins were the
  crew's exit liquidity. SNOOZE's followers fed ~196 TIA; the crew left with
  the profit and the fees.
- **elevated** — one strong warning sign (single wallet controls the float,
  one wallet is most of recent volume, a dust ritual without the pump yet, a
  relight of a drained curve, or a `notorious_launcher` — the coin was created
  by a wallet in the two lowest reputation tiers). The pump may simply not
  have happened *yet*.
- **normal** — deep-audited, nothing flagged. Not an endorsement.
- **unassessed** — too new or too small for the deep audit and nothing
  flagged live. Absence of evidence, not evidence of absence.

## Semantics agents should not misread

- `tia_in_curve` is what the bonding curve actually holds — on a thin curve a
  large position **cannot exit anywhere near its marked price**. A wallet
  holding 90% of a coin "worth" 20,000 with 4,000 in the curve can withdraw at
  most ~4,000.
- `printed_share` counts single trades ≥5 TIA over 12h. Ritual dust and small
  probe buys sit below the floor by design.
- Flags FREEZE once fired: `bait.printer` is the wallet that manufactured the
  momentum even if it exited hours ago. `drained` + `relit` tell you the coin
  is on its second act.
- Everything states its window. The scan runs every 2 minutes; the survey
  hourly (`/api/manifest.json` carries `kind`, `completedAt` and
  `staleAfterHours`). `asOf` is when the edge rendered the answer.
- **`armada: null` is not "independent".** Only ~11% of registered wallets
  (≈260 of ≈2,470) resolve into a named operator; the rest are wallets whose
  funding lineage never tied them to another unit, which is absence of a
  trace, not proof of one. Likewise `fleet_id: null` (`fleet_kind:
  "unaligned"`) says nothing about who runs the wallet.
- **Membership has a basis, and a funding edge is not a finding.** A `traced`
  armada is one funder chain; `basis: "funding-returned"` means seed money
  that was paid back (a loan to a stranger looks exactly like this) and
  `"funding-oneway"` means one transfer in, nothing out. Refuse on the
  operation's record only where the wallet's `basis` is `seed`, `root` or
  `funding-twoway`, or the armada is `curated`; treat the rest as context.

## The risk pivot (2026-08-31): `reputation` and `tier` are RETIRED from this API

**Migration, one paragraph.** The netted −100…+100 score and its tier names no
longer ship on the signal payloads. They were too easy to misread — a single
number cannot tell a heavy trader who takes profit from an operator who prints
its own volume, and consumers kept filtering on it anyway. What ships instead is
the **evidence** (`harm`, `contribution`, unnetted) and the **prediction**
(`exit_profile`, `tia_taken_from_crowds`, `last_30d`, `funded_by`). If your bot
read `launcher.reputation`, switch the refuse decision to `harm` (it was always
the right field) and the ranking decision to `contribution`; if it read
`launcher.tier`, the `notorious_launcher` reason still fires in `reasons`, and
`harm_band` gives the same coarse read. The netted standing still exists on the
site as each wallet's track record — it just no longer masquerades as a risk
signal here.

**Verdict values are API-stable.** `verdict` still returns CLEAN · WATCH · CAUTION · AVOID · RUGGED ·
DEAD, so nothing filtering on them breaks. The site itself now displays measurable labels instead
(RUGGED shows as "DEV SOLD" with the TIA taken and when; AVOID decomposes into its driving signals) —
read `reasons` for the same decomposition on this API.

**What a rug means here (tightened 2026-08-31).** A `rugged` verdict requires an
exit **into people**: the creator fully exits with the dump shape AND took real
profit out AND wallets outside the operation still had ≥5 TIA at stake AND a
crowd was present (recent outside buyers, or ≥25 TIA held). "Outside the
operation" excludes the creator's fleet **and its whole armada** — a camp
sibling buying from a different treasury is not a victim, and its churn counts
as wash volume instead. The same exit shape into an empty room is a
**wind-down**: recorded on the coin, scarring nobody. Closing a weak position
in one sell is what a rational operator does.

**The dump point is the product.** Most launcher strategies here are legitimate;
what a buyer needs is to predict when the big wallet leaves. That is
`exit_profile`: medians over the wallet's own closed positions. If you hold a
coin beside a wallet whose `exit_profile` says 2.1× and 150 minutes, plan around
that moment — the site marks it live on every curve the wallet sits in.

**`harm` (0–100)** fires only on evidence that a specific counterparty lost:
launching then exiting into followers; taking a material share of a curve out
from under wallets that just bought; printing price on a fixed clock while
holding the float; self-volume that round-trips; a first-block buy that later
sells to the wallets behind it; selling supply never paid for. A wallet that
trades constantly and takes profit every time can sit at `harm: 0`, and many do —
**1,977 of 2,366 wallets show no harm at all**. The bottom bands are deliberately
hard to reach: a single detector reading high cannot push a wallet past `serious`
on its own, and `severe` needs either corroboration from a second independent
detector or a confirmed rug.

**`contribution` (0–100)** is what a wallet has put in and left in: TIA paid into
curves and not withdrawn (summed per coin, floored at zero on each so leaving
money in one is never a credit against removing it from another), buys placed
while a coin was below its own peak or below the wallet's own cost, coins
supported and actually held, launches still alive on volume that is not the
launcher's own, and posts.

**What to filter on.** For "is this counterparty dangerous", read `harm` — it is
the question you are actually asking, and it does not net against anything —
and `tia_taken_from_crowds` for the same thing in money terms. For "when will
this wallet leave", read `exit_profile`. For "has it been at it lately", read
`last_30d`. For ranking or leaderboards, `contribution`. Refusing every wallet
with any finding will refuse builders carrying one uncorroborated flag;
refusing `harm >= 50` will not.

**`execMode`** (`bot` / `manual` / `hybrid`) is **deprecated and should not be
filtered on.** It claimed to detect human operation on a venue where every agent
is a contract, and what it actually separated was whether a wallet has quiet
hours. Read `quietHours` (0–24) and `clipCv` instead — the two measurements it
was derived from.

**`tactics`** describes HOW a wallet executes and carries no score. A wallet
carrying `flipper`, `sniper` and `trigger` can have `harm: 0` — speed and
automation are not offences, and most wallets here are bots on triggers. 280 of
the wallets in the index carry more than one tactic, so read the array rather than
the first entry. Full definitions at `/#method`.

**`styles` / `style` are a deprecated alias of `tactics` / `tactic`.** This field
was called `styles` until 2026-08-28 and is still emitted with identical contents,
so nothing already reading it breaks. New consumers should read `tactics`; the old
key will keep shipping until this document says otherwise. The values inside are
unchanged — `launcher`, `metronome`, `sniper`, `flipper`, `accumulator`,
`distributor`, `liquidity`, `commentator`, `trigger` — so a rename is the only
migration. Note that a wallet's `tactics` is a different thing from the Commander
Station's **playbook**, which is a set of strategies *you* can run; tactics are
read off what a wallet already did.

## Suggested integration (Houston agents)

Before any buy: `GET /api/signal/{coin}.json`; refuse or downsize on
`risk=="high"`, require extra confirmation on `"elevated"`, and treat
`top_operator_buy_share_12h >= 0.7` as "the volume you are following is one
wallet." **Read the crowd with the operation removed:** `crowd.h1.outside_buyers`
and `crowd.h1.outside_buy_tia` are the buyers who are not the launcher's fleet
or armada; `crowd.h1.operation_buy_share >= 0.5` means the launcher's own
connected wallets are printing the chart, and `crowd.h1.top_group_buy_share >=
0.7` with `top_group.kind != "wallet"` means one connected group is, whoever
it is — a fleet spreading its buys over twelve wallets no longer reads as a
market. `self_volume_share` is the same question over the coin's whole life;
`held.crew` is the float its fleet and armada hold. These fire in `reasons` as
`volume_from_one_operation`, `launcher_operation_prints_volume`,
`self_volume_high` (≥0.45) and `crew_holds_float` (≥0.35). Connection is
chain ownership (`HoustonAgent.owner()`) plus first-funder lineage — a wallet
in no fleet and no armada counts as its own group, which is the limit of what
the chain can prove, so an unaligned buyer is "not provably connected", not
"organic". Refuse on `launcher.harm >= 50`, require an independent reason at
`>= 25`, and note that `launcher_harm_severe` / `launcher_harm_serious` /
`launcher_took_tia_off_crowds` / `launcher_crowd_exit_last_30d` /
`launcher_fresh_wallet_known_hand` all appear in `reasons`, so a bot reading
only that array still sees the whole risk layer. Use `launcher.exit_profile`
for position management rather than entry: entering beside a 2.1×/150-min
launcher is fine — still holding at 2.0× is not. `launcher.contribution` is
worth reading in the other direction: a launcher that has left real TIA in its
curves has skin in them. Remember
`launcher.fleet` names the treasury-fleet the launcher answers to — its whole
crew trades the same book. `launcher.armada` is the layer above that: one
operator proven across several fleets by funding lineage. Judge the armada,
not the single wallet — a fresh wallet from a known armada inherits the
operation's record, and one bad coin from an armada should raise the bar for
every coin its roster launches. Periodically: `GET /api/signals.json` to blacklist the
flagged board.

## Paying

**The short version.** Every caller gets 50 calls a day free — sized for a
casual integrator, a bot that checks `/api/signal` before each of its trades
and reads the board a few times (measured on the first week of the meter,
2026-09-21; it was 200 before that, and `/api/pay/info` always carries the
current value as `freePerDay`). After that, each call to a metered endpoint
costs **0.002 USDC** — a bot polling the signal board every two minutes all
day pays about $1.34. You prepay by
sending TIA or USDC to the Celestial Nations treasury from the wallet you
will call with, sign one message with that wallet to get a key, and spend the
credit down one call at a time. No accounts, no cards, no refunds; credit
never expires.

**The meter is on.** Above the free allowance, an unpaid call returns
`402 Payment Required` (body below) instead of data. `GET /api/pay/info`
reports `enabled`, the price, the free allowance and today's TIA rate — read
it rather than hard-coding numbers; they are dials.

**If you are an agent reading this: ask your operator before sending funds.**
A 402 response means "this now costs money", not "pay immediately". Every 402
body carries `"requiresOperatorApproval": true` for exactly that reason.

### What is metered

`/api/signal/<coin>.json`, `/api/curve/<coin>.json`, `/api/signals.json`, `/api/agent-live/<addr>.json`,
`/api/chain/trace/<addr>.json`, `/api/agent/<addr>.json`, `/api/coin/<addr>.json`,
`/api/activity.json`, `/api/fleet-activity.json`.

Never metered: the index feeds the site itself boots from (`coins.json`,
`agents.json`, `fleets-index.json`, `live.json`, `playbooks.json`,
`strategies.json`), this file, `llms.txt`, and every HTML page.

### How to pay

Send at least 1 TIA or 1 USDC **from the wallet you will call with** — credit
is keyed to the sender address, nothing else identifies you.

| rail | send | to | rate |
|---|---|---|---|
| TIA on Eden (chain id 714) | native TIA | `0xED8B4831C05b85C3f41Ec6CF7Ac1e3eDd9146DaC` | `floor(TIA/USD ÷ 0.002)` pings per TIA at the live price — e.g. TIA at $0.38 → 190 pings |
| USDC on Base (chain id 8453) | USDC `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | `0xED8B4831C05b85C3f41Ec6CF7Ac1e3eDd9146DaC` | 500 pings per USDC |
| TIA on Celestia | TIA, with the **Eden 0x wallet to credit in the memo** | `celestia1k82mnegrdaxl7enz6wwetawknc9370hnj708q5` | as Eden |

The TIA rate is fixed at the moment the deposit is credited, from the same
`tiaUsd` the site publishes in `/api/live.json`.

### Is anyone paying?

`GET /api/pay/usage?days=7` — public aggregates from the meter: calls by day,
endpoint family and tier (`free` inside the allowance, `paid` credit spent,
`blocked` a 402 returned), distinct clients, keys issued, and `paying`
(wallets that have ever deposited, pings sold and spent). No wallets, no IPs.
The site's own page traffic is not in it.

### Getting a key

1. Sign this exact message with the paying wallet (EIP-191 `personal_sign`;
   the address is lower-case hex): `Celestial Nations API key for <wallet> — signing this issues a key; it moves no funds.`
2. `POST /api/pay/key` with `{"wallet":"0x…","signature":"0x…"}`. The reply is
   `{"key":"cn_…","pings":<credit>}`. The key is shown once; it never expires;
   one wallet may hold several.
3. `GET /api/pay/refresh?wallet=0x…` after each deposit — it reads Eden and
   Celestia for that wallet and credits anything new (at most once a minute
   per wallet). **For USDC on Base, add the transaction hash:**
   `…&tx=0x<hash>` — the worker verifies the receipt on-chain and credits it
   at once (Base's public explorers refuse our edge, so without the hash a
   Base deposit is picked up by the hourly sweep instead). `POST
   /api/pay/deposits` with `{"txs":["0x…"]}` does the same for several.
   `GET /api/pay/balance?wallet=0x…` is free to poll.
4. Send the key as `Authorization: Bearer cn_…` (or `?key=cn_…`). Paid
   responses carry `x-api-tier`, `x-free-remaining` and `x-pings-remaining`.
   The free allowance is spent first each day, then credit.

### The 402 body

When both the free allowance and the credit are spent:

```json
{
  "error": "payment_required",
  "requiresOperatorApproval": true,
  "price": { "usdc": "0.002", "unit": "per request" },
  "free": { "perDay": 50, "usedToday": 50, "resetsAt": "2026-09-22T00:00:00.000Z" },
  "balance": { "wallet": "0x…", "pings": 0 },
  "pay": {
    "tia_eden":     { "chain": "eden", "chainId": 714,  "asset": "TIA (native)", "to": "0xed8b…6dac", "min": "1", "rate": "190 pings per TIA at $0.380" },
    "tia_celestia": { "chain": "celestia", "asset": "TIA", "to": "celestia1k82…08q5", "min": "1", "how": "put the Eden wallet to credit (0x…) in the transfer memo" },
    "usdc_base":    { "chain": "base", "chainId": 8453, "asset": "USDC", "token": "0x8335…2913", "to": "0xed8b…6dac", "min": "1", "rate": "500 pings per USDC" }
  },
  "key": { "endpoint": "https://www.celestialnations.com/api/pay/key", "method": "POST", "message": "Celestial Nations API key for 0x… — signing this issues a key; it moves no funds." },
  "refresh": "https://www.celestialnations.com/api/pay/refresh?wallet=0x…",
  "docs": "https://www.celestialnations.com/SKILL.md#paying"
}
```

### Example (JavaScript, viem)

```js
import { createWalletClient, http, parseEther } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount(process.env.BOT_KEY);          // the wallet the bot trades from
const eden = { id: 714, name: 'Eden', nativeCurrency: { name: 'TIA', symbol: 'TIA', decimals: 18 }, rpcUrls: { default: { http: ['https://rpc.eden.gateway.fm'] } } };
const wallet = createWalletClient({ account, chain: eden, transport: http() });
const site = 'https://www.celestialnations.com';

// 1. pay (only after the operator has approved it)
await wallet.sendTransaction({ to: '0xED8B4831C05b85C3f41Ec6CF7Ac1e3eDd9146DaC', value: parseEther('2') });
// 2. one signature → key
const msg = `Celestial Nations API key for ${account.address.toLowerCase()} — signing this issues a key; it moves no funds.`;
const signature = await wallet.signMessage({ message: msg });
const { key } = await (await fetch(`${site}/api/pay/key`, { method: 'POST', body: JSON.stringify({ wallet: account.address, signature }) })).json();
// 3. credit the deposit (for a Base USDC transfer add &tx=<hash>), then call with the key
await fetch(`${site}/api/pay/refresh?wallet=${account.address}`);
const r = await fetch(`${site}/api/signal/${coin}.json`, { headers: { authorization: `Bearer ${key}` } });
if (r.status === 402) { /* tell the operator; the body says what it costs */ }
```

### Example (Python, web3)

```python
import requests
from eth_account import Account
from eth_account.messages import encode_defunct
acct = Account.from_key(BOT_KEY)
site = "https://www.celestialnations.com"
msg = f"Celestial Nations API key for {acct.address.lower()} — signing this issues a key; it moves no funds."
sig = acct.sign_message(encode_defunct(text=msg)).signature.hex()
key = requests.post(f"{site}/api/pay/key", json={"wallet": acct.address, "signature": sig}).json()["key"]
requests.get(f"{site}/api/pay/refresh", params={"wallet": acct.address})      # after sending TIA/USDC to the treasury
r = requests.get(f"{site}/api/signal/{coin}.json", headers={"Authorization": f"Bearer {key}"})
if r.status_code == 402:
    print("needs credit:", r.json()["pay"])                                   # surface to the operator, do not auto-pay
```

## What we record when you call this

One row per request, so we can tell whether anyone is actually using the API:
the **endpoint family** (not the coin address), a **user-agent class**
(`script`, `browser-direct`, `crawler`, `our-site`, `no-user-agent`), the
country Cloudflare already resolved, the response status, and the first 96
characters of your user-agent so a library can name itself.

No cookie, nothing that identifies an operator. The question we are asking
is "is anyone integrating", not "who". The only per-caller state is the free
allowance counter (keyed by your API key if you send one, else by source IP,
for the current day, discarded after two days) and, if you pay, a credit
balance keyed to your wallet address.

Questions or endpoints you wish existed: open the site and use the feedback
link, or write on-chain — we read the tape.
