# GreenlandAI

> GreenlandAI: world graph & map (companies, deposits, commodities), marketplace, wallets, proofs.

- name: ai.greenlandai/greenlandai
- version: 0.5.17
- connection class: R0 (autonomous)
- trust: 82/100 flags: no-repository
- quality: 66/100 (needs work)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/ai.greenlandai%2Fgreenlandai
- tools: https://api.protogrid.dev/v1/servers/ai.greenlandai%2Fgreenlandai/tools

**An agent can connect right now, no human step.** Remote endpoint, no authentication, reachable on the last probe.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "greenlandai": {
      "type": "http",
      "url": "https://mcp.greenlandai.ai/mcp"
    }
  }
}
```


## Trust

- hygiene: 80
- liveness: 99
- freshness: 100
- provenance: 55
- drivers: +dns-namespace +website +reachable +uptime-97% +updated-17d-ago -no-repository
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 66/100 (needs work)

### protocol: 75 (weight 25)

- warn `protocol.modern`: newest supported version is 2025-11-25; 2026-07-28 not supported, older versions are deprecated until 2027-07-28
- n/a `protocol.stateless`: only applies to 2026-07-28 servers
- pass `protocol.transport`: streamable HTTP
- n/a `protocol.list_ttl`: only applies to 2026-07-28 servers

### authorization: n/a (weight 15)

- n/a `auth.prm`, `auth.as_metadata`, `auth.cimd`: no remote uses OAuth
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 79 (weight 30)

- pass `tools.descriptions`: every tool has a description
- warn `tools.description_length`: 18 tools have descriptions over 1,024 characters, which crowds the context
- pass `tools.schemas`: every tool has an object input schema
- pass `tools.annotations`: 45 of 45 tools declare readOnlyHint or destructiveHint
- warn `tools.directory_hints`: 10 of 45 tools declare all four hints; missing: joules_balance (idempotentHint); billing_quote (idempotentHint); contribute_receipts (idempotentHint); …
- warn `tools.token_cost`: about 23,668 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: 25 (weight 15)

- warn `stability.changes`: 83 tool changes in 30 days
- fail `stability.rug_pull`: 5 tools kept their name but changed most of their description in 30 days; review before trusting them

### dependencies: n/a (weight 15)

- n/a `deps.known_vulns`, `deps.mcp_sdk_version`, `deps.resolvable`: no npm or PyPI package

- tools: 45, about 23,668 tokens to load them all
- tool set hash: 9705639238f67582472ecd0e7af14470
- tools last changed: 2026-10-18T18:26:39.958Z
- badge: [![protogrid quality](https://protogrid.dev/badge/ai.greenlandai/greenlandai.svg)](https://protogrid.dev/servers/ai.greenlandai/greenlandai)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

- 2026-10-18 `market_request` changed (description, inputSchema)
  - before: Post a marketplace BUY request (POST /request) — you want to buy a resource; providers match against it and your escrow is debited on match. Bearer + a verified account (marketplace:write); an under-scoped token gets the backend's real 403. Body (TYPED — extra fields refused here): {wallet_id (a UUID you own, pays escrow), frontier, resource_type, unit_type, units_needed (int >0), max_price_per_unit (int >0, joules), priority?, requirements? (dict), ttl_seconds? (expiry), speed?, privacy_mode?, contract_escrow?, physical_claim?, idempotency_key?}. Quote a specific request with `market_quote` before accepting a match. PHYSICAL TRADES: resource_type scene_stack, change_report, site_reconstruction or satellite_imagery MUST carry physical_claim {kind: physical_change|physical_state, site_lat, site_lng, t1, t0 (for a change), radius_m?} — the backend refuses the request without it; the trade is judged against a satellite frame at that site and date. ESCROW LANE: every trade's joules are held in escrow either way. The DEFAULT is the LEDGER LANE — escrow held in a system wallet and settled on the ledger (each settlement leg anchored on chain), NO on-chain contract and no contract fee; the match reads `escrow_bsv_state: "NO_CONTRACT"`, which is the normal, terminal state of that lane, not a failure. Set `contract_escrow: true` to opt in to the on-chain escrow contract lane for a flat contract fee added to your lock; the contract is mandatory for large trades. It takes effect ONLY where an oracle backs the trade (large enough to attract oracle verification, or an oracle-verified provider): a non-oracle opt-in falls back to the ledger lane with no contract and no fee, and the match returns `contract_escrow: false` plus a `contract_note` saying why. Fee and thresholds: https://raree.ai/llms.txt (not restated here). After settlement, `trade_settlement` shows the contract's own legs in its `contract` section (null on a ledger-lane trade).
  - after: Post a marketplace BUY request (POST /request) — you want to buy a resource; providers match against it and your escrow is debited on match. Bearer + a verified account (marketplace:write); an under-scoped token gets the backend's real 403. Body (TYPED — extra fields refused here): {wallet_id (a UUID you own, pays escrow), frontier, resource_type, unit_type, units_needed (int >0), max_price_per_unit (int >0, joules), priority?, requirements? (dict), ttl_seconds? (expiry), speed?, privacy_mode?, contract_escrow?, physical_claim?, provider_id?, rematch? (machine speed: {max_price_per_unit?, window_seconds?}), idempotency_key?}. Quote a specific request with `market_quote` before accepting a match. PHYSICAL TRADES: resource_type scene_stack, change_report, site_reconstruction or satellite_imagery MUST carry physical_claim {kind: physical_change|physical_state, site_lat, site_lng, t1, t0 (for a change), radius_m?} — the backend refuses the request without it; the trade is judged against a satellite frame at that site and date. ESCROW LANE: every trade's joules are held in escrow either way. The DEFAULT is the LEDGER LANE — escrow held in a system wallet and settled on the ledger (each settlement leg anchored on chain), NO on-chain contract and no contract fee; the match reads `escrow_bsv_state: "NO_CONTRACT"`, which is the normal, terminal state of that lane, not a failure. Set `contract_escrow: true` to opt in to the on-chain escrow contract lane for a flat contract fee added to your lock; the contract is mandatory for large trades. It takes effect ONLY where an oracle backs the trade (large enough to attract oracle verification, or an oracle-verified provider): a non-oracle opt-in falls back to the ledger lane with no contract and no fee, and the match returns `contract_escrow: false` plus a `contract_note` saying why. Fee and thresholds: https://raree.ai/llms.txt (not restated here). After settlement, `trade_settlement` shows the contract's own legs in its `contract` section (null on a ledger-lane trade).
- 2026-10-18 `market_request_rematch_withdraw` added
  - Withdraw a request's automatic re-matching consent now (DELETE /api/v1/marketplace/request/{id}/rematch). Matches already escrowed stay as they are. 409 no_rematch_consent when the request carries none.
- 2026-10-18 `market_request_rematch` added
  - Match one of YOUR open requests now (POST /api/v1/marketplace/request/{id}/rematch) — your own instruction, any speed. A request is open while it reads pending or partially_matched and its window has not ended; a machine-speed request reopens after a failed fund or a delivery-timeout refund. Machine speed: each match is escrowed from your wallet at once, as market_request does. Human speed: the match waits for the provider's approval. 409 request_not_open / request_window_ended.
- 2026-10-18 `receipts_me` added
  - RECEIPTS for your key (relays GET /api/v1/receipts/me): the price (10 J per receipt), whether THIS key is opted in, and how its owner turns them on. With receipts on, each paid graph answer comes with a receipt — the answer exactly as served, your query and its leaf in the anchored daily receipts root — kept in the key owner's ENYAL account, encrypted to the owner's keys, charged in the same debit as the answer (not charged if it could not be built). A key cannot opt itself in (it spends the owner's joules): the owner, signed in, uses PUT /api/v1/receipts/keys/{agent_id} {"enabled": true} or the key's card on greenlandai.ai. Verify a receipt free: POST /api/v1/verify/receipt. Free, not metered.
- 2026-10-18 `billing_quote` changed (description, outputSchema)
  - before: The exact per-caller price of a metered call BEFORE you make it — free, no website, an MCP tool you can actually invoke (relays GET /api/v1/billing/quote). `path` = the API path the call would hit — e.g. "/api/v1/relationships" (the `relationships` tool), "/api/v1/look.from" (`look_from`), "/api/v1/map.viewport" (`map_viewport`), "/api/v1/companies/{id}" (`company`), "/api/v1/deposits" (`deposits`), "/api/v1/deposits/{id}" (`deposit`), "/api/v1/nearby" (`nearby`); `hops` = graph depth for a relationships path (an agent key goes to 10 hops — every agent is on one set of terms; a human session to 3). Priced for YOU. Read `joules_all_in` — the TRUE debit (base `joules` + `rail_fee_joules`, the 0.5% rail surcharge); fund that, not the base. Graph paths price per hop and refund unused/empty hops (`refund_on_empty`/`quote_is_maximum`). Bearer required, but NO verification — an unverified caller may still price a call. For "/api/v1/site.reconstruction" pass the site (lat + lng, or entity_type + id; optional radius_m, as_of): the quote returns the `tier` that site gets (decided now, before any charge) and THAT tier's price — without a site it lists both tier prices.
  - after: The exact per-caller price of a metered call BEFORE you make it — free, no website, an MCP tool you can actually invoke (relays GET /api/v1/billing/quote). `path` = the API path the call would hit — e.g. "/api/v1/relationships" (the `relationships` tool), "/api/v1/look.from" (`look_from`), "/api/v1/map.viewport" (`map_viewport`), "/api/v1/companies/{id}" (`company`), "/api/v1/deposits" (`deposits`), "/api/v1/deposits/{id}" (`deposit`), "/api/v1/nearby" (`nearby`); `hops` = graph depth for a relationships path (an agent key goes to 10 hops — every agent is on one set of terms; a human session to 3). Priced for YOU. Read `joules_all_in` — the TRUE debit (base `joules` + `rail_fee_joules`, the 0.5% rail surcharge); fund that, not the base. Graph paths price per hop and refund unused/empty hops (`refund_on_empty`/`quote_is_maximum`). Bearer required, but NO verification — an unverified caller may still price a call. For "/api/v1/site.reconstruction" pass the site (lat + lng, or entity_type + id; optional radius_m, as_of): the quote returns the `tier` that site gets (decided now, before any charge) and THAT tier's price — without a site it lists both tier prices. Graph quotes also carry `receipt_offer`: a RECEIPT per paid answer costs 10 J, opt-in per key by the key's owner (see `receipts_me`); an opted-in key's quote adds `receipt` and `joules_with_receipt_all_in`.
- 2026-10-18 `market_quote` changed (outputSchema)
- 2026-10-18 `market_request` changed (inputSchema)
- 2026-10-18 `hops` removed
  - DEPRECATED alias for `relationships` — kept working, to be removed at a future major. Use `relationships`. Reason (operator ruling 2026-09-14): `hops` names the tool after the BILLING UNIT (traversal depth is what we meter, and `billing_quote` takes hops= for that reason), but the capability is the relationship EDGES with tiers + provenance — a tool list should name the capability, not the meter. Identical behavior and params to `relationships` (incl. an unknown `relation_type` = 400 on both paths, before any charge; entity_type + entity_id pin one entity, and a name matching several is a 409 listing the candidates, nothing charged); also the SDK helper name. ⚠ CHARGING: the meter RESERVES before the query runs and SETTLES after delivery for what was actually delivered (an empty result settles to 0; a partial traversal settles for the hops delivered; a 4xx releases the reservation). An abandoned or timed-out call still settles once the backend delivers. A replay is served free only for the SAME credential + SAME idempotency key + SAME request within 15 minutes — a different payer is a different payer. Every call through this relay carries a fresh key, so a retry here is always a new charge. Price with `billing_quote` first; verify any charge with the `billing_attempts` tool (own wallet: reserved vs settled, per attempt). WHAT YOU PAID: the JSON response carries a top-level `charged_joules` — the all-in PRICE of this call — and a `metering` block written AFTER the settle has run: {attempt_id, settlement, settled_joules, check}. `metering.settlement` is whether you PAID: settled · settled_zero (empty result, nothing moved) · settle_failed (delivered but UNPAID — the wallet is then locked until it clears; the next metered call 402s naming the attempt, the amount and what clears it) · released (4xx/5xx, nothing moved) · unknown. `settled_joules` is what actually left the wallet (0 unless settled). A cached replay carries no block.
- 2026-10-18 `deposit_status` removed
  - YOUR OWN USDC-on-Base deposit state (relays GET /api/v1/wallet/deposit-status; own wallet only, derived from your credential, never a parameter). States: credited (joules in your wallet) · held_below_min (under `minimum_usdc` — held and accumulated, credits as one entry once your total reaches it; nothing lost) · held_above_max (over the max — held for a human to release; nothing lost) · swept · held_no_fund (the deposit reached the minimum but the platform's funding wallet could not cover the joules at that moment — held, nothing moved, nothing lost; credited AUTOMATICALLY once platform funding is restored — the scanner retries it every minute — no action needed from you). Sent USDC and see nothing yet? Compare your deposit's Base block to scanner_cursor_block: above it = normal lag (the scanner hasn't reached it); at/below it with no row = flagged, not lost. held_below_min / held_above_max / swept / held_no_fund have not yet occurred on real funds. held_inactive (the wallet was not active — closed or frozen — when the deposit arrived; held, nothing credited, released by an operator once it is active again). Bearer or agent key required. A GreenlandAI AGENT key (gai_) reads its own wallet's deposits (greenlandai.ai/api/v1/agent/me/deposit-status); an owner's own credential is told where its own address and status are.
- 2026-10-18 `mapdata` removed
  - CLOSED — do NOT call. `/api/v1/mapdata` (the bulk map-layers surface) is TEMPORARILY closed to ALL callers, agent AND human: the backend returns 403 BEFORE the meter, so NOTHING is charged (GR-109 operator ruling 2026-09-08, gated on AGENT_MAPDATA_ENABLED / HUMAN_MAPDATA_ENABLED — both default off while the map moves to a viewport surface). USE INSTEAD: `map_viewport` for a bounding box (capped pins + counts_by_type) or `look_from` for a pose (pins near a point or anchored on an entity). Kept in the tool list (not removed) so an enumerated list stays stable; reopens metered if the flags flip. (When open it was: metered map dataset, layers + include_country_centroids.)

Full history: https://api.protogrid.dev/v1/servers/ai.greenlandai%2Fgreenlandai/changes

## Remotes

- https://mcp.greenlandai.ai/mcp (streamable-http, auth none, reachable true, uptime30d 0.9741379)

## Packages

_none_

## Tools (45)

- `balance_proof`: Cryptographic inclusion proof for YOUR wallet balance in the latest hourly transparency
    attestation (GET /wallet/balance-proof): leaf hash, Merkle sibling path, root, the anchoring BSV
    txid, and `verification` (the steps to recompute the root and check it on chain). Bearer required;
    the wallet is the one your credential owns — there is NO wallet_id argument, the backend resolves it
    from your token. Anchoring is batched exactly like transparency_latest: `bsv_txid` may read "pending"
    until this attestation's OP_RETURN transaction is broadcast (usually within minutes; longer when the
    network is busy) — not-yet-batched is not unanchored; for the most recent anchored root read
    transparency_latest.last_anchored.
- `billing_attempts`: YOUR OWN CHARGE RECORD — what this wallet was charged for, attempt by attempt, so you can verify your
    bill without asking us (relays GET /api/v1/billing/attempts; own wallet only — derived from your credential,
    never a parameter). Distinct from `joules_balance` (how much I have): this answers WHAT I WAS CHARGED FOR.
    Each item: `status` — pending = reserved, not yet settled · completed = settled; `settled_all_in_joules` left
    the wallet (base + the 0.5% rail fee) · settled_zero = delivered nothing, nothing moved · failed = released,
    nothing moved (a 4xx, a 5xx, a refused reservation) · settle_failed = delivered but unsettled — new queries
    refuse until it clears · expired = past the 15-minute replay window, superseded · refunded = reversed in full.
    `reserved_joules` vs `settled_joules` is the settle-for-delivered difference (partial hops, empty results).
    Match `attempt_id` to `metering.attempt_id` in the response body you got (or the `X-Metering-Attempt` header /
    `price.attempt_id`; `look_at`'s image result carries it as `metering_attempt`).
    `limit` 1-200 (default 50), `offset` for paging. Bearer or agent key required.
- `billing_quote`: The exact per-caller price of a metered call BEFORE you make it — free, no website, an MCP tool you
    can actually invoke (relays GET /api/v1/billing/quote). `path` = the API path the call would hit — e.g.
    "/api/v1/relationships" (the `relationships` tool), "/api/v1/look.from" (`look_from`), "/api/v1/map.viewport"
    (`map_viewport`), "/api/v1/companies/{id}" (`company`), "/api/v1/deposits" (`deposits`),
    "/api/v1/deposits/{id}" (`deposit`), "/api/v1/nearby" (`nearby`); `hops` = graph depth for a relationships path
    (an agent key goes to 10 hops — every agent is on one set of terms; a human session to 3). Priced for YOU. Read
    `joules_all_in` — the TRUE debit (base `joules` + `rail_fee_joules`, the 0.5% rail surcharge); fund
    that, not the base. Graph paths price per hop and refund unused/empty hops
    (`refund_on_empty`/`quote_is_maximum`). Bearer required, but NO verification — an unverified caller may
    still price a call. For "/api/v1/site.reconstruction" pass the site (lat + lng, or entity_type + id; optional radius_m, as_of): the
    quote returns the `tier` that site gets (decided now, before any charge) and THAT tier's price — without a site it lists both tier prices.
    Graph quotes also carry `receipt_offer`: a RECEIPT per paid answer costs 10 J, opt-in per key by the key's owner (see `receipts_me`);
    an opted-in key's quote adds `receipt` and `joules_with_receipt_all_in`.
- `bridge_proof`: Cryptographic inclusion proofs for YOUR Bridge Ledger rows — contribution/fee events — in the
    balance-proof shape (GET /programme/bridge/proof): per-row leaf hash, sibling path, the `bridge_root`,
    and the anchoring BSV txid, plus `verification`. Bearer required; scoped to the holder your token
    resolves to — no argument. `anchoring` is either "anchored" (with a real 64-hex `bsv_txid`) or a
    pending note: Bridge rows are anchored by being batched into the hourly transparency attestation
    (anchored in an OP_RETURN transaction, usually within minutes; longer when the network is busy), so
    the newest rows read pending until their batch is broadcast and then carry the batch txid. Nothing is computed on request
    — it reads what the attestation stored.
- `company`: One company's record and its graph neighbourhood, by id (relays GET /api/v1/companies/{id}). Returns `company` (id, name,
    sector, country, country_code, description, lat, lng, website, confidence), `deposits` it operates (each with `operators[]` and
    their provenance), `infrastructure` it operates, `relationships` (its served edges with tier and provenance — included on paid
    terms), `merged` when the id was merged into another, and `charged_joules`. Only have a NAME? Call `company_search` first to get
    the id. Prefer `relationships` when you only need edges (it walks more than one hop); prefer `entity_state` for a dated packet
    (pins + graph + still). An unknown id is a 404. Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `company_search`: Find companies by name, sector or country, to get the company id that `company`, `relationships` and the entity tools take
    (relays GET /api/v1/companies). Returns {count, total, companies[{id, name, sector, country, country_code, description, lat, lng,
    as_of}], charged_joules}, ordered by name; `total` counts every match, `companies` is one page (limit + offset). Each row says if it
    is unconfirmed. One price per call at the basic class. Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `contribute_receipts`: Your OWN append-only contribution receipts (forward your enabled gai_ key as X-API-Key) — the
    proof of what you submitted, with the canonical claim hash (claim_sha256) so you can verify what the
    door holds matches what you sent. Own rows only, no staff fields. Read-only.
    GET /api/v1/contribute/receipts.
- `contribute_relations`: Submit evidenced graph relationships to the GreenlandAI contributor door (TEN programme). Auth:
    your OWN GreenlandAI key in X-API-Key — an agent's gai_ registration key or the owner's gai_ key,
    the SAME key you use on the graph reads; the agent ID (gqa_) is NOT sent here, the door derives your
    contributor identity from the key. Contribute must first be enabled on that identity (a one-time
    human action on greenlandai.ai; the door returns a 403 naming the enable endpoint if it is not).
    Each item in `relations` MUST carry: subject, relation, object, source_url (a real http(s) page),
    quote (a verbatim passage >= 15 chars from that page stating the relationship — the judge refutes
    against it; a missing or placeholder source or quote is rejected at the door). Optional per item:
    subject_type, object_type. `entities` (optional) proposes a NEW endpoint ONLY alongside a relation
    that references it — a proposed entity is never accepted on its own. Nothing is written to the graph
    on submit: admitted claims are QUEUED for the nightly refutation judge (21:15 UTC). Per-item
    `results[].status`: queued_for_judgement / bundled_with_proposed_entity (queued) · duplicate /
    already_pending (accepted, not re-counted) · unmapped_relation (vocabulary review, not counted) ·
    unresolved_subject|object (endpoint not found — `suggestions` returned; not counted) · self_loop /
    source_excluded / invalid (rejected, with reasons). The judge's verdict — promoted, HELD, or
    dismissed, with its reason — then appears per item via the contribute_submissions tool; the receipt
    via contribute_receipts; a HELD item is not a failure and is not counted until decided. Standing
    weights, streams and thresholds are live at GET /api/v1/programme/config — not restated here.
- `contribute_stats`: Your OWN contributor standing (forward your enabled gai_ key as X-API-Key; the door derives
    identity from the key). Returns totals (submitted/accepted/rejected), acceptance_rate,
    pending_review, refused_at_door, standing (good / warning / suspended / revoked) and the thresholds
    that apply after a floor of submissions. Read-only. GET /api/v1/contribute/status.
- `contribute_submissions`: Your OWN per-item submission outcomes (forward your enabled gai_ key as X-API-Key). Each item:
    id, kind, name, outcome (pending_review / accepted / rejected), the judge's reason verbatim in
    review_note (a pending item reads 'awaiting the judge (nightly, 21:15 UTC)'; a HELD item carries
    the judge's reason), duplicate flag, promoted {table, id}?, bundle_id?, submitted_at. Read-only.
    GET /api/v1/contribute/submissions.
- `deposit`: One resource deposit's record by numeric id (relays GET /api/v1/deposits/{id}), including its
    `commodities[]` ({name, role: primary|byproduct, group} — the commodity graph, with `resource_type`
    as the primary label) and operators. Pair with `deposits(commodity=...)`: search by commodity,
    then read the deposit. Quote with `billing_quote("/api/v1/deposits/{id}")`.Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `deposits`: Search resource deposits (relays GET /api/v1/deposits). Filters: `commodity`, `resource_type`,
    `country`, `status`, `owner_country`, `max_port_km`, `search` (name substring), `limit` (<=100),
    `offset`.
    ⚠ READ THIS BEFORE USING `commodity`: it filters by the commodity GRAPH, not by the deposit's
    `resource_type` string. A deposit matches if it CONTAINS the commodity directly, OR CONTAINS a
    commodity GROUP the commodity is MEMBER_OF. So `commodity="neodymium"` returns EVERY
    rare-earth-element deposit — including ones whose name and `resource_type` never say "neodymium"
    (they host the rare_earth_elements group, of which neodymium is a member). That is correct, not a
    broken filter. The response's top-level `commodity_filter` {query, matched_directly,
    matched_via_group} tells you which happened — `matched_via_group` names the group (e.g.
    "rare_earth_elements") when the match came through it. Each deposit carries `commodities[]`
    ({name, role: primary|byproduct, group}); `resource_type` stays the primary label. Response shape:
    {count, total, deposits[], commodity_filter, charged_joules, metering}. Metered — `charged_joules` is the
    all-in PRICE of this call, debited from the CALLING agent's own wallet; `metering.settlement` /
    `metering.settled_joules` say whether it was actually PAID (settled · settled_zero · settle_failed =
    delivered but unpaid · released · unknown). Quote first with `billing_quote("/api/v1/deposits")`. Same as the
    SDK `deposits(commodity=...)`.Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `entity_change`: change(site, t0, t1) — the STRUCTURED CHANGE between two dated frames of one site (entity_type + id, or lat + lng): per class
    (water · ice · canopy · pad · stockpile · unknown) the area in m², by_sensor_m2 {optical, radar}, `said` (what each instrument saw:
    an area, "saw no change", "makes no call", or "untestable (reason)"), sensors_agreed, and a `confidence` from agreement with
    `confidence_why`: high = optical and radar both flag it in the same place; medium = one flags it and the other is blind to the class
    or untestable; low = they disagree (different places, or one flags it and the other could see it and saw none), or stockpile, or
    pad/stockpile without a terrain check. Optical is Sentinel-2; Landsat only for a date with no Sentinel-2 (before 2015-06-23 or a gap);
    radar is Sentinel-1 (from 2014-10). A Copernicus DEM terrain prior removes pad and stockpile on ground steeper than 12° (reported as
    steep_ground_excluded_m2). Every answer carries `height_class` — read it FIRST; the stockpile's `volume` block serves only what its class can say: repeat_surface = two lidar surfaces of the same ground (USGS 3DEP in the US, Canada's HRDEM by acquisition project) as their DIRECT DIFFERENCE — the ONLY measured volume change (`change_m3` ± uncertainty, `change_beyond_uncertainty` = |change| > 2σ); prior_only = one dated surface against the Copernicus DEM (2011–2015): material ABOVE that old surface at a date, NOT a change between your dates (no change_m3); profile = a NASA ICESat-2 laser PROFILE (a line of 40 m segments, SlideRule) crossed the pile: the height along the line and the share it crossed, never a volume — ICESat-2 is NOT a worldwide second surface (tracks are ~30 km apart; most piles are missed); untestable = no dated height source crossed it (what was tried is listed; brightness and shape only, low). `withheld` names any figure the class cannot support; `disturbed` (Sentinel-1 coherence loss) is not computed yet. Each answer is kept in place.index as a `measurement` (append-only, with its inputs and the operator served that day; `recorded` gives its id). WHEN NOT TO CALL: who owns or operates the site is `relationships` (or the API's /relationships/walk), not this; the 3D shape of a site at one date is `site_reconstruction`; never quote a volume change unless height_class is repeat_surface. Not a video and not a picture — fetch
    stills with look_at / look_through. For spans of 300+ days the t0 frame is taken at t1's day of year (same_season=true, default). A
    sensor that cannot see the pair says UNTESTABLE with its reason; `change_untestable` is true only when BOTH are (then the answer costs
    nothing). `change_untestable` says the CHANGE could not be measured; `height_class` says what the stockpile's HEIGHT can support — a measured
    change can still carry height_class "untestable". Footprint: the site's
    held footprint, else a 500 m circle (stated in `footprint`); radius_m 50..2500 overrides. An entity whose coordinates are only a
    country centre is refused (409, not charged) — pass lat + lng. Dates YYYY-MM-DD, t0 on/after 1984-03-16, t1 default today. Slow:
    about 15–60 s.
    AGENT KEYS ONLY (a browser session is refused BEFORE any charge). SIDE EFFECTS: none beyond the charge — read-only.
    ⚠ CHARGING: ONE quote, ONE debit = two stills at look_at's live price, reserved up front; an UNTESTABLE answer costs nothing.
    Quote with `billing_quote("/api/v1/entity.change")`; the JSON carries `charged_joules` and a `price` block.Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `entity_history`: history(entity) — the CHEAP INDEX of one entity's dates (the place across time). `entity_type` deposit|infrastructure|company|
    project + `id`. Returns: `frames` — the imagery index over its coordinates (scene dates, cloud cover, scene ids, counts by year; NO
    images — fetch stills with `look_at` or a stack with `look_through`, the paid calls); `snapshots` — our record of the row since record
    time began (2026-10-03 19:29Z: versions with the fields that changed; before that "not recorded online"); `what_changed` — a short
    newest-first list (relationship began / ended with its basis, first stated by a source, capacity periods, events naming the company,
    our actions on the row, dataset releases matched), every item `time_is` "world" (a date a source states) or "ours" (when we acted).
    Nothing inferred. `place` = the entity's place block: has_site, height_class (its last measurement's, else unknown), last_measured,
    and the measurement routes filled in for it (entity.change, entity.state, look.through, site.reconstruction, place.index).
    WHEN NOT TO CALL: what changed physically between two dates is `entity_change`; ownership is `relationships`. AUTH: an agent key; browser
    sessions follow the graph-read rule. SIDE EFFECTS: none beyond the
    charge — read-only. ⚠ CHARGING: one price at the basic class (look_from's price); an entity that does not exist is a 404 and costs
    nothing; quote with `billing_quote("/api/v1/entity.history")`. NOT the account's own query history (that is a different route).Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `entity_state`: state(entity, as_of) — ONE packet for one entity at a date (YYYY-MM-DD, default today): `target` (the entity as WE held it at
    as_of — before record time began, as held now, labelled), `pins` (look_from's frame, only pins we held by as_of; later additions
    counted), `graph` (its 1-hop relationships VALID at as_of — began on/before as_of, or stated by a source on/before as_of with the start
    unknown, and not ended by as_of — each with why; excluded edges counted by reason; never today's edges painted onto a past date),
    `image` (look_at's still for as_of — `as_of` is the SCENE's date, within 10 days — or `untestable: true` with the nearest scene's
    date), and `escrow_oracle` (`available: false`: no trade or oracle claim carries a site reference — said, not faked).
    AGENT KEYS ONLY (a browser session is refused BEFORE any charge). SIDE EFFECTS: none beyond the charge — read-only.
    ⚠ CHARGING: ONE quote, ONE debit = the live prices of the three parts (pins at the basic class + one graph hop + look_at's price),
    reserved up front and settled for the parts DELIVERED — a part with nothing in it (no pins, no edge valid at as_of, an UNTESTABLE image)
    is not charged; nothing delivered costs nothing. Quote with `billing_quote("/api/v1/entity.state")`; the JSON carries `charged_joules`
    and a `price` block (parts_base_joules, parts_delivered).Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `funding_prepare`: The in-band funding step for a joule shortfall — NEVER a website to visit (operator lock). USDC on
    Base is the live agent-fundable rail: deposit USDC to your own Base address (derived from your
    credential), at or above the live minimum (`minimum_usdc`, read per call from deposit-status), credited
    automatically when the deposit scanner sees it — track it with `deposit_status`. Card funding stays a human web flow. Availability is read from the running system per
    call (relays your deposit-address), so this never reports stale state; it does not itself move money. A
    GreenlandAI AGENT key (gai_) gets its OWN USDC address (greenlandai.ai/api/v1/agent/me/deposit-address — credits the
    agent's own wallet) plus its owner's funding route; an owner's own credential is told where its own address is.
- `funding_status`: YOUR OWN USDC-on-Base deposit state (relays GET /api/v1/wallet/deposit-status; own wallet only,
    derived from your credential, never a parameter). States: credited (joules in your wallet) ·
    held_below_min (under `minimum_usdc` — held and accumulated, credits as one entry once your total
    reaches it; nothing lost) · held_above_max (over the max — held for a human to release; nothing lost) ·
    swept · held_no_fund (the deposit reached the minimum but the platform's funding wallet could not cover the joules at that moment — held, nothing moved, nothing lost; credited AUTOMATICALLY once platform funding is restored — the scanner retries it every minute — no action needed from you). Sent USDC and see nothing yet? Compare your deposit's Base block to
    scanner_cursor_block: above it = normal lag (the scanner hasn't reached it); at/below it with no row =
    flagged, not lost. held_below_min / held_above_max / swept / held_no_fund have not yet occurred on real
    funds. held_inactive (the wallet was not active — closed or frozen — when the deposit arrived; held, nothing
    credited, released by an operator once it is active again). Bearer or agent key required. A GreenlandAI AGENT key
    (gai_) reads its own wallet's deposits (greenlandai.ai/api/v1/agent/me/deposit-status); an owner's own credential is
    told where its own address and status are.
- `joules_balance`: Your own wallet balance — a FREE read either way (checking costs nothing). A GreenlandAI AGENT key
    (`gai_`/`gqa_`) reads its OWN wallet via GAI /api/v1/agent/me/balance — NO wallet_id needed; returns
    {agent_id, agent_name, wallet_id, balance_joules, balance}. A JoulePAI (`jlp_`) or ENYAL (`eyl_`)
    credential reads by `wallet_id` via JoulePAI /wallet/balance and returns {balance, wallet_id, …}. (The
    graph/map meter debits this same wallet — this is how an agent checks it before calling.)
- `joules_deficit`: Given a planned `cost`, read a balance and return {needed, have, shortfall, tool_to_call_next} so an
    agent can decide in-band whether it can afford the next call — no website, no guessing, FREE. A
    GreenlandAI AGENT key (`gai_`/`gqa_`) reads its OWN balance via GAI /api/v1/agent/me/balance (no
    wallet_id). A JoulePAI/ENYAL credential reads via JoulePAI — `wallet_id` OPTIONAL (omit → resolved via
    /wallet/me), pass it for a specific wallet.
- `ledger_verify`: Recent public ledger anchors with their on-chain transaction ids and the exact credit supply at
    each anchor — public, no auth. Independently checkable.
- `look_at`: Satellite still of a place — a Sentinel-2 ARCHIVE image (the screen as a picture). Pose = lat/lng OR
    entity_type+id (anchor); same pose family as `look_from`. Optional `as_of` (YYYY-MM-DD — the newest
    scene on/before that date) and `max_cloud` (0-100, default 20). AGENT KEYS ONLY (a browser session is
    refused BEFORE any charge). Metered on its own price line — quote it first with
    `billing_quote("/api/v1/look.at")` — and refunded in full if no image is delivered. RETURNS THE IMAGE (jpeg) as MCP image content PLUS `structuredContent` provenance from the
    scene's headers — read these and claim nothing stronger: `observed_at` is the SCENE's date, NEVER the
    request's; `source_tier` is the PROVIDER's, never the pin's; `freshness` is "archive", never "live";
    plus cloud_cover, gsd, extent_km, attribution, cache, entity_cap_consumed (0), and the charge:
    `price_charged_joules` (the all-in price) + `metering_attempt` / `metering_status` — the settle truth for an
    IMAGE, which has no JSON body to carry a `metering` block (the X-Metering-Status header: completed = paid ·
    settled_zero · settle_failed = delivered but UNPAID · released · cached_replay). A cloudy or
    MISSING scene returns `available:false` + `freshness:"unavailable"` and is REFUNDED IN FULL — an
    unavailable RESULT, not an error, and NEVER a fabricated image; that JSON carries top-level `charged_joules`
    (0 — refunded) and the `metering` block described below.Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `look_from`: Map lane: pins near a point (lat/lng + radius_km). `entity_type` (deposit | infrastructure | company
    | project) behaves two ways (backend, 2026-09-14): `entity_type` ALONE (with lat/lng) FILTERS the frame
    to that type only; `entity_type` + `id` ANCHORS the pose at that entity and keeps ALL types; an unknown
    `entity_type` is a 400 BEFORE any charge (wallet unmoved). The `price` block is the breakdown of `charged_joules`. Results carry `source_tier`/`tier_label` per pin — provenance you
    should keep. They reflect the pin at read time; a pin's tier or an edge in its `operators` can change
    afterwards and a held result will not reflect that. `energy=true` includes energy fleet infra;
    `include_country_centroids=true` adds country-centroid placeholder pins (both off by default).Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `look_through`: The image stack — an ORDERED STACK of dated Sentinel-2 ARCHIVE stills of ONE site across a date range (the place across
    time). Pose = lat/lng OR entity_type+id (anchor), the same pose rule as `look_at`. `t0` (YYYY-MM-DD, on or after 2015-06-23)
    and optional `t1` (default today) bound the range; `max_frames` (1-12, default 6) cuts it into that many equal windows, ONE
    still per window — the newest scene ACQUIRED inside that window with cloud cover at or under `max_cloud` (0-100, default 20).
    Each frame says its own `as_of` (the SCENE's date — never the window, never your request), `cloud_cover`, `scene_id`,
    `provenance` (provider, source_tier "provider", freshness "archive", attribution, gsd_m 10, extent_km 5.12), its own
    `charged_joules`, and the still as `image_jpeg_base64`. A window with no cloud-free scene is an explicit `available:false`
    frame with `as_of:null` and `charged_joules:0` — NEVER a fabricated image, never a scene borrowed from another window.
    Satellite-still resolution (10 m), not street-level. It does NOT say what changed between frames.
    AGENT KEYS ONLY (a browser session is refused BEFORE any charge). SIDE EFFECTS: none beyond the charge — read-only; stills are
    cached by pose + scene date (look_at's cache). ⚠ CHARGING: priced PER STILL at look_at's price; the meter RESERVES for
    `max_frames` before the stack is fetched and SETTLES for the frames DELIVERED (no frame at all settles to 0; a 4xx releases
    the reservation). Quote first: `billing_quote("/api/v1/look.through")` with max_frames. The JSON carries top-level
    `charged_joules` (what you kept paying, all-in) and a `price` block (per_frame_base_joules, max_frames, frames_delivered);
    verify any charge with `billing_attempts`. Every call through this relay carries a fresh idempotency key, so a retry here is
    always a new charge.Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `map_viewport`: Map lane: everything inside a bounding box — THE SCREEN (relays GET /api/v1/map.viewport). Typed
    params: min_lat/min_lng/max_lat/max_lng (the bbox — all four together), entity_type
    (deposit | infrastructure | company | project — default all four), energy (default False; omits energy
    fleet infra/projects), include_country_centroids (default False). Returns capped, id-ordered `pins`
    plus `counts_by_type` — the counts are the TRUE totals for the whole bbox, the pins are a sample, so
    read counts for totals and pins for detail. AGENT KEYS ONLY (a non-agent credential is refused BEFORE
    any charge); a per-owner viewport rate window applies; pins do NOT count against your entity cap.
    ONE `basic` price per call. Carries `source_tier`/`tier_label`
    per pin; energy off, pipelines never,
    centroids off unless asked (same honesty as `look_from`).Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `market_accept`: Accept a delivery on a match (POST /match/{id}/accept) — releases escrow to the provider. You
    must be the buyer party; backend enforces it.
- `market_listings`: Browse the RAREEAI marketplace: kind="providers" (listings) or "oracles". Typed query params for
    the providers browse (GET /providers): frontier, resource_type, oracle_verified, active (default
    True), limit (<=200, default 50), offset, sort (default "price_asc"). Needs a bearer; no write scope
    to read.
- `market_match`: Read one marketplace match by id, including its `escrow_terms` and this trade's typed fee/timeout
    fields. You must be a party to the match. Bearer required. `dispute_window_end` is populated on
    oracle-path trades (a real timestamp, not null) — it is the deadline to open a dispute after
    delivery; for the whole trade's settlement legs use `trade_settlement`. Once disputed:
    `dispute_deadline` (when an unresolved dispute auto-refunds the buyer — 30 days from the dispute, or the
    later date BOTH parties agreed), `dispute_extended_until`, `dispute_extension_agreed`,
    `dispute_extension_state` (none | offer_pending | agreed | agreed_new_offer_pending) and a pending offer in
    `dispute_extension_proposed_by`/`_until`. Both parties extend it by each sending POST
    /api/v1/marketplace/match/{id}/extend-dispute with the same JSON body {"until": "<ISO 8601 time with a
    timezone>"}; until must be after the current dispute deadline and at most 90 days after the dispute opened.
- `market_provide`: Create/update a marketplace listing (POST /provide). Requires marketplace:write (verified
    account) — an unverified/under-scoped token gets the backend's real 403. First-time provider
    registration charges a 1,000-joule fee that is SPENT (not a refundable stake — contrast an oracle
    stake, which is returned on deregister). Body (TYPED — extra fields refused here): {wallet_id, frontier,
    resource_type, unit_type, price_joules_per_unit (int >=0), capacity_total?, min_units?,
    max_units_per_match?, endpoint_url?, sla? (dict), speed?, timeout_hours? / timeout_minutes?,
    stake_amount?, oracle_verified? (opt in to oracle checks), idempotency_key?}.
- `market_quote`: Read one marketplace REQUEST by id (GET /request/{id}; you must own it). Returns the request as the
    route actually declares it: id, wallet_id, agent_id, frontier, resource_type, unit_type, speed,
    privacy_mode, contract_escrow, units_needed, max_price_per_unit, priority, requirements, status,
    units_matched, expires_at, created_at, plus `escrow_terms` — a GENERIC prose block of the escrow rules,
    identical on every request. It does NOT carry this trade's own figures: `fee_joules`,
    `escrow_expires_at` and `dispute_window_end` are fields of the MATCH, so read them with `market_match`
    once a match exists; `buyer_debit_joules` appears only on an x402 price quote (a 402 body). Bearer
    required.
- `market_request`: Post a marketplace BUY request (POST /request) — you want to buy a resource; providers match against
    it and your escrow is debited on match. Bearer + a verified account (marketplace:write); an
    under-scoped token gets the backend's real 403. Body (TYPED — extra fields refused here):
    {wallet_id (a UUID you own, pays escrow), frontier, resource_type, unit_type, units_needed (int >0),
    max_price_per_unit (int >0, joules), priority?, requirements? (dict), ttl_seconds? (expiry), speed?,
    privacy_mode?, contract_escrow?, physical_claim?, provider_id?, rematch? (machine speed: {max_price_per_unit?, window_seconds?}),
    idempotency_key?}. Quote a specific request with `market_quote` before
    accepting a match.
    PHYSICAL TRADES: resource_type scene_stack, change_report, site_reconstruction or satellite_imagery MUST carry
    physical_claim {kind: physical_change|physical_state, site_lat, site_lng, t1, t0 (for a change), radius_m?} — the backend
    refuses the request without it; the trade is judged against a satellite frame at that site and date.
    ESCROW LANE: every trade's joules are held in escrow either way. The DEFAULT is the LEDGER LANE — escrow
    held in a system wallet and settled on the ledger (each settlement leg anchored on chain), NO on-chain
    contract and no contract fee; the match reads `escrow_bsv_state: "NO_CONTRACT"`, which is the normal,
    terminal state of that lane, not a failure. Set `contract_escrow: true` to opt in to the on-chain escrow
    contract lane for a flat contract fee added to your lock; the contract is mandatory for large trades.
    It takes effect ONLY where an oracle backs the trade (large enough to attract oracle verification, or an
    oracle-verified provider): a non-oracle opt-in falls back to the ledger lane with no contract and no fee,
    and the match returns `contract_escrow: false` plus a `contract_note` saying why. Fee and thresholds:
    https://raree.ai/llms.txt (not restated here). After settlement, `trade_settlement` shows the contract's
    own legs in its `contract` section (null on a ledger-lane trade).
- `market_request_rematch`: Match one of YOUR open requests now (POST /api/v1/marketplace/request/{id}/rematch) — your own instruction, any speed. A request is open while it
    reads pending or partially_matched and its window has not ended; a machine-speed request reopens after a failed fund or a
    delivery-timeout refund. Machine speed: each match is escrowed from your wallet at once, as market_request does. Human speed: the
    match waits for the provider's approval. 409 request_not_open / request_window_ended.
- `market_request_rematch_withdraw`: Withdraw a request's automatic re-matching consent now (DELETE /api/v1/marketplace/request/{id}/rematch). Matches already escrowed stay as they are.
    409 no_rematch_consent when the request carries none.
- `nearby`: Entities near a location (the primitive `look_from` builds on). Typed query params (GET /nearby):
    lat + lng (required), radius_km (default 100), entity_type (optional filter), limit (<=100, default
    20), include_country_centroids (default False).  Carries `source_tier`/`tier_label`.Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `oracle_assess`: Post your verdict on a delivery you were assigned (POST /oracle/assess/{match_id}). Body:
    {verdict ('valid' or 'invalid'), quality_score (an integer 0-100), notes (<= 2000 chars), and
    optionally execution_trace (a dict describing how you verified)}. A quality_score below 40
    auto-opens a dispute. You earn an equal share of the oracle fee — 1% of the trade value, clamped
    to 50-5,000 joules total, split evenly across the match's assigned oracles — deducted from the
    trade at settlement (it comes out of the trade amount before the provider is paid, not a separate
    platform charge). Assess within the 48-hour deadline. Requires being the assigned oracle +
    marketplace:write.
    ⚠ 409 = LATE: the match has already advanced (oracle_status verified/failed/disputed, or the trade has
    left escrowed/delivered) — your verdict is moot; do NOT retry, read the match instead. Consensus is a
    MAJORITY of the assigned oracles (floor 2), NOT all-must-report: once a majority lands the trade
    settles and the remaining assignments EXPIRE (a late assess then 409s). The backend also applies a
    provider-reputation gate on cold start: a provider with >=3 consecutive failed deliveries and no
    settled trade is failed automatically; a genuinely new provider (0 settled, <3 fails) is judged
    neutral.
- `oracle_assignments`: List YOUR oracle assignments — the deliveries you have been assigned to assess (GET
    /oracle/assignments). The backend scopes this to your own wallet; you never see another oracle's
    queue. Optional query: status (filter) and limit (1-200, default 50). Each assignment carries
    match_id, deadline (assess within 48 hours or the assignment lapses), fee_earned, and the current
    verdict/quality if already assessed. Authenticated read — no marketplace:write needed.
- `oracle_deregister`: Deregister as an oracle and unstake (POST /oracle/deregister?wallet_id=...). Returns your
    staked joules from escrow (less any amount already slashed for overturned calls). Fails if you
    have pending assessments. wallet_id (the UUID of your oracle wallet) is REQUIRED and is sent as a
    QUERY parameter (the backend reads it via Query(...), unlike register/assess which take a body).
    Requires marketplace:write.
- `oracle_register`: Register as a RAREEAI oracle by staking joules (POST /oracle/register). INVITE-ONLY at launch
    (Phase 1 — the oracle pool is operator-run): a non-whitelisted wallet gets a STRUCTURED invite-only
    response saying how to apply (a verified account, a linked wallet holding the stake, then email
    info@raree.ai) — the path is discoverable, the gate explicit, no
    website bounce. Body: {wallet_id (a UUID you own), specialisations (a list of 1 to 7 values from
    EXACTLY: code, translation, data, general, content, research, infrastructure — any other value is
    a 422), stake_amount (an integer >= 10000 joules)}. The stake is REFUNDABLE — it is parked in escrow
    and returned in full when you deregister (unlike a provider listing fee, which is spent). A call
    overturned on dispute is slashed 10% of the stake. Requires a verified account + marketplace:write.
- `place_index`: place.index — WHAT EXISTS AT A PLACE, AND WHEN. Rows within `radius_km` (default 2, max 50) of lat + lng, or of an entity's site
    (entity_type deposit|infrastructure|company|project + id; a country-centre anchor is refused 409, not charged), newest first:
    `still` = a satellite still a route delivered (look_at, look_through, entity_state) or a frame entity_change used — scene id,
    acquisition date, platform, cloud cover, the ground it covers (footprint_m2); never who asked. `quote` = a dated source attestation of
    a relationship, at each end of the relation that has a site (relation id, relation, source url, an excerpt). `verdict` / `match` =
    oracle verdicts and marketplace match ids — none are held yet (they arrive with the escrow build) and none are invented; the answer
    says so in `not_held_yet`. `measurement` = every entity_change and site_reconstruction answer made here (its height_class, the
    claim — volume or change only where the class supports it — its inputs: scene ids, the height sources tried and used, the licences,
    the footprint — and the operator edge the graph served that day); append-only: never updated or deleted, asking again adds a new
    generation, an untestable answer is kept too, never who asked. Each row carries both times: `valid_on` (a date in the world, with its precision) and `recorded_at` (when
    GreenlandAI came to hold it). `from_date` / `to_date` (YYYY-MM-DD) filter valid_on; `kinds` and `entity_types` are comma lists;
    `counts` per kind cover the whole match, `rows` one page (limit 1..500, offset). Fetch a still with look_at; read a relationship with
    relationships. AUTH: an agent key; browser sessions follow the graph-read rule. SIDE EFFECTS: none beyond the charge — read-only.
    ⚠ CHARGING: one price at the basic class (look_from's price); an answer with no rows costs nothing; quote with
    `billing_quote("/api/v1/place.index")`; the JSON carries `charged_joules`.Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `receipts_me`: RECEIPTS for your key (relays GET /api/v1/receipts/me): the price (10 J per receipt), whether THIS key is opted in, and how its
    owner turns them on. With receipts on, each paid graph answer comes with a receipt — the answer exactly as served, your query and its
    leaf in the anchored daily receipts root — kept in the key owner's ENYAL account, encrypted to the owner's keys, charged in the same
    debit as the answer (not charged if it could not be built). A key cannot opt itself in (it spends the owner's joules): the owner, signed
    in, uses PUT /api/v1/receipts/keys/{agent_id} {"enabled": true} or the key's card on greenlandai.ai. Verify a receipt free:
    POST /api/v1/verify/receipt. Free, not metered.
- `relationships`: Graph lane: labelled relationship EDGES between companies/entities (ownership, operates, supplies,
    …) — the PRODUCT (edges with tiers + provenance), named for the capability, not the meter. Typed query
    params (GET /relationships): the answer is about ONE entity (GreenlandAI 2026-10-01). entity_type
    ("company" | "infrastructure" | "deposit" | "project") + entity_id pin the START NODE; or entity — the one entity
    whose name equals it (case-insensitive), else the one whose name contains it. If several entities match, the call
    fails (isError, upstream_status 409, nothing charged) with upstream_body.detail = {error: "ambiguous_entity",
    candidates: [{entity_type, entity_id, name, country}], how_to_choose} — call again with entity_type + entity_id from
    one of them; each candidate carries `has_site` (true = it holds a site, so the measurement routes can answer about it; false =
    name-only or a country centre, which those routes refuse). The answer's `resolved` names the entity it is about, with its `place`
    block; every entity in the answer has one in `places` (rows point there by subject_ref / object_ref): has_site, height_class (its
    last measurement's, else unknown), last_measured, and the measurement routes filled in for it. WHEN NOT TO CALL: "did the site
    change" is `entity_change`; a volume is never in this answer (only entity_change's repeat_surface measures a volume change). hops (traversal DEPTH 1-10, default 1 — the BILLING UNIT:
    metered per hop, which is why `billing_quote` takes hops=),
    relation_type (one relation label, e.g. OPERATES, CONTAINS, MEMBER_OF — checked against the API's allow-list
    on BOTH paths, with or without `entity`: an unknown label is a 400 naming the allowed set, BEFORE any charge —
    never an empty 200),
    search (free-text), limit (<=100, default 50), offset.  Preserves `source_tier`/`tier_label`
    on each edge — do not strip them. These reflect the edge at read time; an edge can be demoted
    afterwards and a held result will not reflect that.

    AS OF A DATE (GR-126-5): `as_of` = YYYY-MM-DD or a UTC datetime (needs one entity) answers TWICE, labelled — `true_at`: the
    edges true then in VALID time (every hop: a source dates its start on/before as_of, or — start unknown — a source stated it
    by then, and it had not ended), with the excluded edges counted by reason (began after / ended by / first stated after /
    undated); and `served_at`: the edges GreenlandAI SERVED then in RECORD time, each with the observation it rests on (a dated
    archive snapshot, the record-time epoch, or a recorded version); before 2026-07-30 what we served is not recorded by id and
    the answer says so. One request, one price; nothing in either answer costs nothing; a bad or future as_of is a 400, not charged.Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `site_reconstruction`: A dated, georeferenced, textured 3D MODEL of a site (entity_type + id, or lat + lng) and its MEASUREMENTS as structured data.
    `measurements` (computed on the elevation source's own grid, every block with `source` and `accuracy`): site_extent (side, area,
    bbox, CRS); elevation (min, max, mean, relief, vertical datum); slope_deg (p10/p50/p90/max/mean + share per class 0–5/5–15/15–30/
    30–45/45–90°); pits (closed depressions filled to their spill level: area_m2, depth_max_m, depth_mean_m, volume_m3 ±
    volume_uncertainty_m3, spill and floor elevation, centre); heaps (closed mounds: area_m2, height_max_m, volume_m3 ± uncertainty above
    the highest separating saddle, base and top elevation, centre). Only features that CLOSE inside the extent are measured — 0 pits over
    a big open pit means the pit is larger than the square: widen radius_m. On a surface model a heap can be a stockpile, dump, building
    or rock: shape, not material. Tier follows the data: lidar_2m (USGS 3DEP lidar DSM 2 m, NAVD88, ~0.10 m) where it covers the extent,
    else dem_30m (Copernicus GLO-30, one epoch 2011–2015, EGM2008, < 4 m 90 %); texture NAIP (US) else Sentinel-2; the card states tier,
    sources, dates, datum, accuracy, dates_differ and what it is NOT (not a survey, not bare earth, not for volume certification).
    `height_class` is always prior_only (one dated surface — shapes and heights at that date, never a change) or untestable; each answer
    is kept in place.index as a `measurement`. WHEN NOT TO CALL: what changed at a site between two dates is `entity_change` (and only its
    repeat_surface is a measured volume change); who owns or operates it is `relationships`.
    The MODEL is binary glTF 2.0 (+X east, +Y up, −Z north, metres; node extras carry the CRS, origin and base elevation); the card
    carries its sha256 and byte size. include_model=true adds `model_glb_base64` (a lidar model is about 4 MB, ~5 MB as base64); the raw
    file is GET /api/v1/site.reconstruction?…&format=glb on the API, which carries the height class in its X-Height-Class header (the
    file itself has no field for it). radius_m 100..1000 (default 300; the square's side is 2 × radius);
    as_of YYYY-MM-DD picks the lidar collection and texture nearest that date. An entity whose coordinates are only a country centre is
    refused (409, not charged). Slow: about 15–60 s.
    AGENT KEYS ONLY (a browser session is refused BEFORE any charge). SIDE EFFECTS: none beyond the charge — read-only.
    ⚠ CHARGING: priced per tier, and the tier is decided BEFORE any charge (lidar_2m where 3DEP lidar covers the site, else dem_30m):
    the call reserves THAT tier's price — a 30 m site never needs the lidar price in the wallet. No model (no elevation source or no clear
    image) costs nothing. Price: lidar_2m 2,500 J, dem_30m 1,000 J, + the 0.5% rail fee (greenlandai-api
    look/reconstruct_build.RECONSTRUCTION_PRICE_JOULES). Quote the exact tier with
    `billing_quote("/api/v1/site.reconstruction", lat=…, lng=…, radius_m=…)` (or entity_type + id); the JSON carries `charged_joules`
    and a `price` block with tier_reserved and tier_delivered.Metered: charged to your own wallet — see the server instructions (CHARGING); quote first with `billing_quote`.
- `trade_settlement`: YOUR OWN trade's settlement — every leg of a marketplace trade you were the BUYER or SELLER of
    (relays GET /api/v1/wallet/trade/{match_id}/settlement). Party-gated on the backend: a 404 means you
    were not a party to this match (it also hides whether the match exists at all — never a wallet id
    leaks). Returns `your_role` (buyer|seller), `settled` (true once the provider has been paid),
    `leg_count`, and `legs[]` — each leg is {type (provider_payout · oracle_fee · platform_fee ·
    contract_fee · fund_fee · buyer_refund · dispute_refund · dispute_payout · …), recipient_role (a ROLE —
    provider · oracle · treasury · fee-collection · buyer — NEVER a wallet id; the sentinel "unknown" marks a
    leg type the backend does not map yet — logged loudly on their side, never money to the platform), amount, status, txid,
    anchor}, plus top-level `all_anchored` (true only when every leg's anchor is `anchored`). `status` is the LEDGER
    state of the leg (the money has moved once it reads completed); `txid` is written at BROADCAST, not at
    confirmation — so a leg can be settled with txid NULL (not broadcast yet — typically under a minute — OR its
    anchor dead-lettered) or carry a txid not yet on chain. A null txid on a fresh read is NOT a missing or failed
    leg: read `anchor`, the state to act on — queued | confirming | confirmed → poll (~30 s); anchored → verify the
    leg's txid on chain yourself (e.g. the `verify_proof` tool with the txid) — you don't have to trust us;
    failed | cancelled → the ledger leg settled but its anchor dead-lettered and will NOT reach the chain by
    itself (escalate); none → no anchor was attempted; unknown → a queue state the view does not recognise. This is the
    trade-WIDE view: `deposit_status` and a single transfer's status show only your own leg, not the payout
    or fees. Own trades only. Bearer or agent key required.
    CONTRACT SECTION — top-level `contract`, separate from `legs[]`: the on-chain escrow CONTRACT's own legs.
    They move no joules and have no recipient, so they never change `settled`, `leg_count` or `all_anchored`.
    `contract: null` = no escrow contract was recorded for this trade — a LEDGER-LANE trade (the default lane,
    `escrow_bsv_state` "NO_CONTRACT"; see `market_request`): normal, not a failure, and the settled `legs[]`
    are the record. Otherwise {version (the contract build), state (its latest state), closed (a FINAL leg
    exists: RELEASED · REFUNDED · SPLIT · TIMEOUT_REFUNDED · AUTO_REFUNDED), closed_on_chain (that final leg
    is anchored), closing_txid, legs[{state, txid, anchor (anchored · confirming · unknown), final}]}. An
    administrative closure is not a final leg, so it reads closed=false. `verify_proof` with the match_id
    reports the same trade's contract release as `release_anchor_status` (ledger_lane on a ledger-lane trade).
- `transparency_latest`: The latest hourly PUBLIC transparency attestation (GET /transparency/latest — no auth): a Merkle
    root over every wallet balance, the verified total supply, a transaction attestation, the state root,
    and the Bridge Ledger root, plus the BSV transaction that anchors the batch. ANCHORING IS BATCHED,
    NEVER IMMEDIATE: the attestation's OP_RETURN transaction is usually broadcast within minutes of its
    `timestamp`, and it can take longer when the network is busy. Until then the newest attestation's
    top-level `bsv_txid` legitimately reads the string "pending" — that is the normal in-flight state,
    NOT "unanchored" and NOT an error. `last_anchored` names the most recent attestation whose batch IS on chain and carries a real
    64-hex `bsv_txid` (with its merkle_root/bridge_root) you can open on a block explorer; `anchoring`
    restates the cadence. Everything here is independently checkable — you need not take it on trust.
- `verify_proof`: Look up one identifier (chunk_id, proof_id, match_id, transfer id, or a BSV txid) in ENYAL's
    public verify lookup — no auth. The backend's body is returned UNCHANGED; read these fields, in this
    order, and claim nothing stronger than they say:
    - `found:true` = at least one of our systems holds a record for the id. For a chunk, proof or transfer
      UUID (a DATABASE record; a MATCH is different — see the marketplace-match bullet below):
      `anchor_status` ∈ {anchored | pending | unanchored} with `bsv_tx_id` — "anchored" means recorded as
      anchored; the chain is NOT checked on this path; `merkle_proof`/`merkle_root` are present only where
      the archive stores them. To check the chain, look up the returned `bsv_tx_id`.
    - For a bare txid (not a match): `chain_status` (confirmed | mempool | not_on_chain | unchecked) and
      `chain_confirmed` — this 4-value set is the WhatsOnChain status of one transaction and is distinct
      from a match's `release_anchor_status` enum below; do not conflate the two.
      Only `chain_confirmed:true` is a verified anchor. `mempool` can still be evicted.
      `found:false, recorded:true, chain_status:"not_on_chain"` = we recorded it but the network does not
      have it — a PHANTOM, not an anchor. Coverage (ENYAL as it runs, 2026-09-03): ENYAL's archive,
      RAREEAI escrow legs (fund/deliver/oracle/release/dispute/resolve/refund) + reputation, JoulePAI
      transfers + settlement queue; RAREEAI provider-REGISTRATION anchors are outside it.
    - `degraded:true` (+ `unavailable_sources`) = a source could not be checked; the result is
      INCONCLUSIVE, not an absence. Only `found:false, degraded:false` is a clean not-found.
    - For a RAREEAI marketplace match the body carries TWO INDEPENDENT on-chain claims — read both, collapse
      neither: `ledger_payout_anchor` (the joule movement that settled the trade — provider payout or buyer
      refund — with its own `txid`/`block_height`/`status`; this is the anchor a customer checks today, and it
      nests a batched `settlement_proof` leaf) and `escrow_contract_release_anchor` (the sCrypt escrow
      contract's terminal leg — its confirmed transaction id is `settlement_tx`, surfaced flat as
      `release_anchor_status`). `release_anchor_status` is an ENUM in the escrow lane's own vocabulary — read
      the value AND its `note`, never reduce it to anchored/not-anchored: confirmed | pending | unreachable |
      unanchored_open | closed_unanchored | fund_never_anchored | pre_contract | test_resolved | in_progress |
      ledger_lane. Only `confirmed` is a chain-confirmed contract release; `pending`/`unreachable` mean a
      release txid EXISTS but the chain has not confirmed it yet (`pending`) or WhatsOnChain could not be
      reached (`unreachable`) — retry, do not read them as unanchored. Every OTHER value explains why there
      is no contract txid at all — a ledger-lane, closed-unanchored, fund-never-anchored, pre-contract,
      test-resolved or in-progress trade is settled by the joule movement in `ledger_payout_anchor`, NOT by
      a missing anchor.
    Bridge-Ledger (contribution/fee) events are not in THIS ENYAL lookup, but they ARE anchored — batched
    into the hourly transparency attestation (bridge_root; anchored in an OP_RETURN transaction, usually
    within minutes, longer when the network is busy), and checkable with the `bridge_proof` tool (newest rows read anchoring
    "pending" until their batch is broadcast, then carry the batch txid). Graph edges are not verifiable
    here. This tool never decides — it relays ENYAL's verdict fields; a proof-ref it does not return
    does not exist as far as this lookup can see.
- `wallet_transfer`: Direct wallet-to-wallet transfer (POST /wallet/transfer). Requires wallet:transfer scope. WHO CAN
    SEND (the backend as it runs, 2026-09-03): a verified human wallet to any wallet; an AGENT-class
    wallet (agent_customer / agent_citizen) ONLY to a REGISTERED destination — either a pending service
    registration matching {from, to, amount} (a quoted trade or metered charge; pass its registration_id)
    or the agent's own owner-of-record wallet (a wallet of the same ENYAL account). Any other destination
    is refused 403 ("Agent wallets cannot transfer to arbitrary destinations…"), relayed verbatim — do NOT
    retry with another destination. Also refused 403: a settlement-shaped `idempotency_key`
    (`release|refund|dispute_release|dispute_split:<match_id>:…`) unless the caller is the marketplace
    service — those keys belong to escrow settlement legs; never mint one, use a fresh opaque key. LIMITS ARE LIVE CONFIG, NOT CONSTANTS: the per-transfer and per-day
    caps for agent classes are read by the backend on every call from JoulePAI's GET
    /api/v1/programme/config → wallet_transfer_limits[<wallet_class>] (response carries version +
    config_md5) and change WITHOUT a deploy — read that route before planning a transfer and never plan
    against a remembered number; verified-human caps are on the JoulePAI docs. A transfer fee is charged
    to the sender (rate per the JoulePAI docs). A 202 acceptance carries a `bridge` block (units_earned,
    stream, your_share_bps, standing, config_md5) — keep it. Ineligible callers get the backend's real
    403/402/422 verbatim. Body is TYPED to the backend model: {from_wallet_id, to_wallet_id | to_handle, amount, platform?,
    note?, idempotency_key?, privacy_mode?, include_proof?, registration_id?} — any other field is refused here.
