# Risk Graph — Full Agent Reference This is the deep reference for AI agents and programmatic clients consuming Risk Graph's paid `/api/v1/agent/*` API. For the short overview and endpoint catalogue, see [llms.txt](/risk-graph/llms.txt). Risk Graph is an **analytical explorer**: it scores DeFi entities (pools, assets, protocols, chains) and exposes an objective **letter grade** per entity. It is deliberately **not** a bulk data feed — there is no listing, enumeration, or full-dataset export, and the underlying scoring model is not fetchable. You look up specific assets/protocols you already know and read their grade. > **Stability:** `/api/v1/agent/*` is versioned via the `/v1` segment. Breaking > changes ship as `/v2`. Prices and response shapes are stable within a major > version; price changes are announced before they take effect. --- ## 0. Base URL ``` https://risk.yo.xyz ``` Every endpoint below resolves to `https://risk.yo.xyz/api/v1/agent/...`. Prefer the `resource.url` field from the 402 challenge as the canonical source — if the host ever changes, agents reading from the invoice keep working without a code update. --- ## 1. Payment protocol — x402 v2 Every `/api/v1/agent/*` route is monetised via the [x402 payment standard](https://x402.org) (version 2). The unpaid request returns `402 Payment Required`; the paid retry returns the resource and a settlement receipt. ### 1.1 Network and asset | Field | Value | |---|---| | Protocol version | `2` | | Scheme | `exact` | | Network | `eip155:8453` (Base mainnet) | | Asset | USDC at `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | | Asset decimals | `6` | | Settlement | EIP-3009 `transferWithAuthorization` via Coinbase CDP facilitator — the **payer pays no gas**, only USDC | Amounts in the invoice are USDC atomic units (six decimals). `"1000"` = `$0.001`, `"50000"` = `$0.05`, `"1000000"` = `$1.00`. ### 1.2 The 402 handshake **Step 1 — unpaid request:** ```http GET /api/v1/agent/node/pool:base:0x8eff… HTTP/1.1 Host: risk.yo.xyz Accept: application/json ``` **Step 2 — server responds with the invoice.** The body is empty; the invoice lives in the `PAYMENT-REQUIRED` header as base64-encoded JSON: ```http HTTP/1.1 402 Payment Required PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6Mi… ``` Decoded: ```json { "x402Version": 2, "error": "Payment required", "resource": { "url": "https://risk.yo.xyz/api/v1/agent/node/pool:base:0x8eff…", "description": "Single node — properties + risk grade only (no neighborhood)", "mimeType": "" }, "accepts": [ { "scheme": "exact", "network": "eip155:8453", "amount": "50000", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "payTo": "0x", "maxTimeoutSeconds": 300, "extra": { "name": "USD Coin", "version": "2" } } ] } ``` `resource.url` is the canonical, self-describing URL — use it instead of hard-coding any host. > **Note — the invoice amount can vary by payer.** The price is resolved per > request (see [§5 Per-payer economics](#5-per-payer-economics)): heavy > cumulative usage escalates the price (there is **no** onboarding fee). Always > sign the amount in the invoice you receive; if the amount changed since a prior > call, the server re-issues a `402` with the correct amount. **Step 3 — sign the payment** (EIP-3009 `transferWithAuthorization` over USDC) and retry the same request with an `X-PAYMENT` header. Use a client library ([`@x402/fetch`](https://www.npmjs.com/package/@x402/fetch), [`@x402/core`](https://www.npmjs.com/package/@x402/core), [`@x402/evm`](https://www.npmjs.com/package/@x402/evm)) — these handle the signature for you. **Step 4 — server returns the resource** with a `PAYMENT-RESPONSE` header proving settlement: ```http HTTP/1.1 200 OK PAYMENT-RESPONSE: eyJzdWNjZXNzIjp0cnVlLCJwYXllciI6IjB4… Content-Type: application/json { "data": { … }, "message": "OK", "statusCode": 200 } ``` The `transaction` field in the decoded receipt is the on-chain Base mainnet transaction hash — verifiable on [Basescan](https://basescan.org). ### 1.3 No-charge guarantee on failure The paywall settles **after** the handler responds, and **only on `2xx` responses**. Any rejection — `400` (bad query), `403` (provenance), `404` (unknown id or removed endpoint), `429` (rate limit), `5xx` — returns **no `PAYMENT-RESPONSE` header and no on-chain settlement**. So the point lookups are safe to probe: a `/node` or `/dependencies` miss returns `404` and is free. `/search` is the exception — it always settles, **including a zero-result query** (`200` with an empty `nodes` array), because the targeted scan is the billable work. Spend `$0.05`+ point lookups only on ids you already hold. --- ## 2. The only risk signal: letter grade The single risk signal exposed on this surface is the letter grade **`_riskTier`** (`A` safest → `F` riskiest), present on the `properties` of every node returned by `/node` and `/dependencies`. (The `/search` teaser is leaner and **omits** the grade — read it from `/node`.) `/node` additionally returns **`riskBreakdown`**: the grade's rationale as plain `{ question, answer }` pairs. Numeric scores, penalties, composites, the scoring rubric, and the grade score-thresholds are **intentionally not provided** anywhere — in any payload, error, or the schema. Do not present or infer a numeric risk score; quote the grade. ```ts type NodeId = string; // e.g. "pool:base:0x8eff…" type NodeLabel = "Pool" | "Asset" | "Protocol" | "Chain"; type PropertyValue = string | number | boolean | null; type RiskFactor = { question: string; answer: string }; // one scrubbed scorecard line interface GraphNode { id: NodeId; labels: NodeLabel[]; properties: Record & { _riskTier?: string; // letter grade A–F (on /node + /dependencies; absent on /search teasers) riskBreakdown?: RiskFactor[]; // grade rationale (Q&A only) — on /node lastUpdatedAt?: string; // ISO freshness stamp — on /dependencies neighbors }; // allow-listed public fields per label; no numeric `_risk*`, no rubric inputs (`derived*`, `_override_*`, peg/backing), no internal/infra fields } interface GraphEdge { type: string; // e.g. "ACCEPTS_DEPOSITS_IN", "BACKED_BY" sourceId: NodeId; targetId: NodeId; properties: Record; } ``` `NodeId` follows a deterministic convention: `