From 98b752d9626a7168b46b3be9901551b14ae37c95 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 10:08:02 +0000 Subject: [PATCH 01/21] generate-openapi script --- apps/ensapi/package.json | 3 +- apps/ensapi/scripts/generate-openapi.ts | 53 + docs/docs.ensnode.io/docs.json | 8 +- openapi/ensapi-openapi.json | 2812 +++++++++++++++++++++++ package.json | 3 +- 5 files changed, 2876 insertions(+), 3 deletions(-) create mode 100644 apps/ensapi/scripts/generate-openapi.ts create mode 100644 openapi/ensapi-openapi.json diff --git a/apps/ensapi/package.json b/apps/ensapi/package.json index 8aefb096f..028a27ba1 100644 --- a/apps/ensapi/package.json +++ b/apps/ensapi/package.json @@ -18,7 +18,8 @@ "test:integration": "vitest run --config vitest.integration.config.ts", "lint": "biome check --write .", "lint:ci": "biome ci", - "typecheck": "tsgo --noEmit" + "typecheck": "tsgo --noEmit", + "generate:openapi": "tsx scripts/generate-openapi.ts" }, "dependencies": { "@ensdomains/ensjs": "^4.0.2", diff --git a/apps/ensapi/scripts/generate-openapi.ts b/apps/ensapi/scripts/generate-openapi.ts new file mode 100644 index 000000000..3b00a153b --- /dev/null +++ b/apps/ensapi/scripts/generate-openapi.ts @@ -0,0 +1,53 @@ +/** + * Generates a static OpenAPI 3.1 JSON document for ENSApi. + * + * Usage: tsx scripts/generate-openapi.ts + * + * Output: /openapi/ensapi-openapi.json + * + * This script has no runtime dependencies — it calls generateOpenApi31Document() + * which uses only stub route handlers and static metadata. + */ + +import { execFileSync } from "node:child_process"; +import { mkdirSync, writeFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +import { generateOpenApi31Document } from "@/openapi-document"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const outputPath = resolve(__dirname, "..", "..", "..", "openapi", "ensapi-openapi.json"); + +// Generate the document (no additional servers for the static spec) +const document = generateOpenApi31Document(); + +// Ensure output directory exists +mkdirSync(dirname(outputPath), { recursive: true }); + +// Write JSON +writeFileSync(outputPath, JSON.stringify(document, null, 2) + "\n"); + +console.log(`OpenAPI spec written to ${outputPath}`); + +// Format with Biome for consistency +console.log("Formatting with Biome..."); +try { + execFileSync("pnpm", ["biome", "format", "--write", outputPath], { + stdio: "inherit", + }); +} catch (error) { + console.error("Error: Failed to format with Biome."); + if (error instanceof Error) { + const err = error as NodeJS.ErrnoException & { status?: number }; + if (err.code === "ENOENT") { + console.error("'pnpm' or 'biome' is not available on your PATH."); + } else if (err.status !== undefined) { + console.error(`Biome exited with code ${err.status}.`); + console.error("Try running 'pnpm biome format --write' manually to debug."); + } else if (err.message) { + console.error(err.message); + } + } + process.exit(1); +} diff --git a/docs/docs.ensnode.io/docs.json b/docs/docs.ensnode.io/docs.json index 8f4554902..d4594771e 100644 --- a/docs/docs.ensnode.io/docs.json +++ b/docs/docs.ensnode.io/docs.json @@ -24,7 +24,13 @@ }, { "group": "API Reference", - "openapi": "https://gist.githubusercontent.com/notrab/94b637e77468cbddd895d7933ce88f64/raw/12cb5ed183558a9bdda5d1c7004db6c794dbd13e/green-ensnode-openapi.json" + "openapi": "https://api.alpha.ensnode.io/openapi.json" + }, + { + "group": "Preview", + "pages": ["ensapi/preview"], + "openapi": "../../openapi/ensapi-openapi.json", + "hidden": true } ] } diff --git a/openapi/ensapi-openapi.json b/openapi/ensapi-openapi.json new file mode 100644 index 000000000..b6f591496 --- /dev/null +++ b/openapi/ensapi-openapi.json @@ -0,0 +1,2812 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "ENSApi APIs", + "version": "1.5.1", + "description": "APIs for ENS resolution, navigating the ENS nameforest, and metadata about an ENSNode" + }, + "servers": [ + { + "url": "https://api.alpha.ensnode.io", + "description": "ENSNode Alpha (Mainnet)" + }, + { + "url": "https://api.alpha-sepolia.ensnode.io", + "description": "ENSNode Alpha (Sepolia Testnet)" + } + ], + "tags": [ + { + "name": "Resolution", + "description": "APIs for resolving ENS names and addresses" + }, + { + "name": "Meta", + "description": "APIs for indexing status, configuration, and realtime monitoring" + }, + { + "name": "Explore", + "description": "APIs for exploring the indexed state of ENS, including name tokens and registrar actions" + }, + { + "name": "ENSAwards", + "description": "APIs for ENSAwards functionality, including referrer data" + } + ], + "components": { + "schemas": {}, + "parameters": {} + }, + "paths": { + "/amirealtime": { + "get": { + "operationId": "isRealtime", + "tags": ["Meta"], + "summary": "Check indexing progress", + "description": "Checks if the indexing progress is guaranteed to be within a requested worst-case distance of realtime", + "parameters": [ + { + "schema": { + "description": "Maximum acceptable worst-case indexing distance in seconds" + }, + "required": false, + "description": "Maximum acceptable worst-case indexing distance in seconds", + "name": "maxWorstCaseDistance", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Indexing progress is guaranteed to be within the requested distance of realtime" + }, + "503": { + "description": "Indexing progress is not guaranteed to be within the requested distance of realtime or indexing status unavailable" + } + } + } + }, + "/api/config": { + "get": { + "operationId": "getConfig", + "tags": ["Meta"], + "summary": "Get ENSApi Public Config", + "description": "Gets the public config of the ENSApi instance", + "responses": { + "200": { + "description": "Successfully retrieved ENSApi public config", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { + "type": "string", + "minLength": 1 + }, + "theGraphFallback": { + "oneOf": [ + { + "type": "object", + "properties": { + "canFallback": { + "type": "boolean", + "enum": [true] + }, + "url": { + "type": "string" + } + }, + "required": ["canFallback", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "canFallback": { + "type": "boolean", + "enum": [false] + }, + "reason": { + "type": "string", + "enum": [ + "not-subgraph-compatible", + "no-api-key", + "no-subgraph-url" + ] + } + }, + "required": ["canFallback", "reason"], + "additionalProperties": false + } + ] + }, + "ensIndexerPublicConfig": { + "type": "object", + "properties": { + "labelSet": { + "type": "object", + "properties": { + "labelSetId": { + "type": "string", + "minLength": 1, + "maxLength": 50, + "pattern": "^[a-z-]+$" + }, + "labelSetVersion": { + "type": ["number", "null"] + } + }, + "required": ["labelSetId", "labelSetVersion"] + }, + "indexedChainIds": { + "type": "array", + "items": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "minItems": 1 + }, + "isSubgraphCompatible": { + "type": "boolean" + }, + "namespace": { + "type": "string", + "enum": [ + "mainnet", + "sepolia", + "sepolia-v2", + "ens-test-env" + ] + }, + "plugins": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1 + }, + "databaseSchemaName": { + "type": "string", + "minLength": 1 + }, + "versionInfo": { + "type": "object", + "properties": { + "nodejs": { + "type": "string", + "minLength": 1 + }, + "ponder": { + "type": "string", + "minLength": 1 + }, + "ensDb": { + "type": "string", + "minLength": 1 + }, + "ensIndexer": { + "type": "string", + "minLength": 1 + }, + "ensNormalize": { + "type": "string", + "minLength": 1 + }, + "ensRainbow": { + "type": "string", + "minLength": 1 + }, + "ensRainbowSchema": { + "type": "integer", + "exclusiveMinimum": 0 + } + }, + "required": [ + "nodejs", + "ponder", + "ensDb", + "ensIndexer", + "ensNormalize", + "ensRainbow", + "ensRainbowSchema" + ], + "additionalProperties": false + } + }, + "required": [ + "labelSet", + "indexedChainIds", + "isSubgraphCompatible", + "namespace", + "plugins", + "databaseSchemaName", + "versionInfo" + ] + } + }, + "required": [ + "version", + "theGraphFallback", + "ensIndexerPublicConfig" + ] + } + } + } + } + } + } + }, + "/api/indexing-status": { + "get": { + "operationId": "getIndexingStatus", + "tags": ["Meta"], + "summary": "Get ENSIndexer Indexing Status", + "description": "Returns the indexing status snapshot most recently captured from ENSIndexer", + "responses": { + "200": { + "description": "Successfully retrieved indexing status", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["ok"] + }, + "realtimeProjection": { + "type": "object", + "properties": { + "snapshot": { + "type": "object", + "properties": { + "strategy": { + "type": "string", + "enum": ["omnichain"] + }, + "slowestChainIndexingCursor": { + "type": "integer" + }, + "snapshotTime": { + "type": "integer" + }, + "omnichainSnapshot": { + "oneOf": [ + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-unstarted"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-queued"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock" + ] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + } + }, + "required": [ + "chainStatus", + "config" + ] + } + ] + } + }, + "omnichainIndexingCursor": { + "type": "integer" + } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + }, + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-backfill"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-queued"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock" + ] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + } + }, + "required": [ + "chainStatus", + "config" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-backfill"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock" + ] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "backfillEndBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock", + "backfillEndBlock" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-completed"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock" + ] + } + ] + } + }, + "omnichainIndexingCursor": { + "type": "integer" + } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + }, + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-completed"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-completed"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock" + ] + } + ] + } + }, + "omnichainIndexingCursor": { + "type": "integer" + } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + }, + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-following"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-queued"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock" + ] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + } + }, + "required": [ + "chainStatus", + "config" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-backfill"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock" + ] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "backfillEndBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock", + "backfillEndBlock" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-following"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock" + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "latestKnownBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock", + "latestKnownBlock" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-completed"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { + "type": "integer" + }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "timestamp", + "number" + ], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock" + ] + } + ] + } + }, + "omnichainIndexingCursor": { + "type": "integer" + } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + } + ] + } + }, + "required": [ + "strategy", + "slowestChainIndexingCursor", + "snapshotTime", + "omnichainSnapshot" + ] + }, + "projectedAt": { + "type": "integer" + }, + "worstCaseDistance": { + "type": "number" + } + }, + "required": [ + "snapshot", + "projectedAt", + "worstCaseDistance" + ] + } + }, + "required": ["responseCode", "realtimeProjection"], + "additionalProperties": false + } + } + } + }, + "503": { + "description": "Indexing status snapshot unavailable", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + } + }, + "required": ["responseCode"], + "additionalProperties": false + } + } + } + } + } + } + }, + "/v1/ensanalytics/referral-leaderboard": { + "get": { + "operationId": "getReferralLeaderboard_v1", + "tags": ["ENSAwards"], + "summary": "Get Referrer Leaderboard (v1)", + "description": "Returns a paginated page from the referrer leaderboard for a specific edition", + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" + }, + "required": true, + "name": "edition", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number for pagination" + }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "description": "Number of referrers per page" + }, + "required": false, + "description": "Number of referrers per page", + "name": "recordsPerPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved referrer leaderboard page" + }, + "404": { + "description": "Unknown edition slug" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Service unavailable" + } + } + } + }, + "/v1/ensanalytics/referrer/{referrer}": { + "get": { + "operationId": "getReferrerDetail_v1", + "tags": ["ENSAwards"], + "summary": "Get Referrer Detail for Editions (v1)", + "description": "Returns detailed information for a specific referrer for the requested editions. Requires 1-20 distinct edition slugs. All requested editions must be recognized and have cached data, or the request fails.", + "parameters": [ + { + "schema": { + "type": "string", + "description": "Referrer Ethereum address" + }, + "required": true, + "description": "Referrer Ethereum address", + "name": "referrer", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of edition slugs" + }, + "required": true, + "description": "Comma-separated list of edition slugs", + "name": "editions", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved referrer detail for requested editions" + }, + "400": { + "description": "Invalid request" + }, + "404": { + "description": "Unknown edition slug" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Service unavailable" + } + } + } + }, + "/v1/ensanalytics/editions": { + "get": { + "operationId": "getEditions_v1", + "tags": ["ENSAwards"], + "summary": "Get Edition Config Set (v1)", + "description": "Returns the currently configured referral program edition config set. Editions are sorted in descending order by start timestamp (most recent first).", + "responses": { + "200": { + "description": "Successfully retrieved edition config set" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Service unavailable" + } + } + } + }, + "/ensanalytics/referrers": { + "get": { + "operationId": "getReferrerLeaderboard", + "tags": ["ENSAwards"], + "summary": "Get Referrer Leaderboard", + "description": "Returns a paginated page from the referrer leaderboard", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number for pagination" + }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "description": "Number of referrers per page" + }, + "required": false, + "description": "Number of referrers per page", + "name": "recordsPerPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved referrer leaderboard page" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/ensanalytics/referrers/{referrer}": { + "get": { + "operationId": "getReferrerDetail", + "tags": ["ENSAwards"], + "summary": "Get Referrer Detail", + "description": "Returns detailed information for a specific referrer by address", + "parameters": [ + { + "schema": { + "type": "string", + "description": "Referrer Ethereum address" + }, + "required": true, + "description": "Referrer Ethereum address", + "name": "referrer", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved referrer detail" + }, + "500": { + "description": "Internal server error" + }, + "503": { + "description": "Service unavailable - referrer leaderboard data not yet cached" + } + } + } + }, + "/api/name-tokens": { + "get": { + "operationId": "getNameTokens", + "tags": ["Explore"], + "summary": "Get Name Tokens", + "description": "Returns name tokens for the requested identifier (domainId or name)", + "parameters": [ + { + "schema": { + "type": "string", + "description": "Domain node hash identifier" + }, + "required": false, + "description": "Domain node hash identifier", + "name": "domainId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "ENS name to look up tokens for" + }, + "required": false, + "description": "ENS name to look up tokens for", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Name tokens known", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["ok"] + }, + "registeredNameTokens": { + "type": "object", + "properties": { + "domainId": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "type": "object", + "properties": { + "assetNamespace": { + "type": "string", + "enum": ["erc721", "erc1155"] + }, + "contract": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + }, + "tokenId": { + "type": "string" + } + }, + "required": [ + "assetNamespace", + "contract", + "tokenId" + ] + }, + "ownership": { + "oneOf": [ + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["namewrapper"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["fully-onchain"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["burned"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["unknown"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + } + ] + }, + "mintStatus": { + "type": "string", + "enum": ["minted", "burned"] + } + }, + "required": ["token", "ownership", "mintStatus"] + }, + "minItems": 1 + }, + "expiresAt": { + "type": "integer" + }, + "accurateAsOf": { + "type": "integer" + } + }, + "required": [ + "domainId", + "name", + "tokens", + "expiresAt", + "accurateAsOf" + ] + } + }, + "required": ["responseCode", "registeredNameTokens"], + "additionalProperties": false + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + }, + "errorCode": { + "type": "string", + "enum": ["name-tokens-not-indexed"] + }, + "error": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + }, + "errorCode": { + "type": "string", + "enum": ["unsupported-ensindexer-config"] + }, + "error": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + }, + "errorCode": { + "type": "string", + "enum": ["unsupported-indexing-status"] + }, + "error": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + } + ] + } + ] + } + } + } + }, + "400": { + "description": "Invalid input", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + } + } + }, + "404": { + "description": "Name tokens not indexed", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["ok"] + }, + "registeredNameTokens": { + "type": "object", + "properties": { + "domainId": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "type": "object", + "properties": { + "assetNamespace": { + "type": "string", + "enum": ["erc721", "erc1155"] + }, + "contract": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + }, + "tokenId": { + "type": "string" + } + }, + "required": [ + "assetNamespace", + "contract", + "tokenId" + ] + }, + "ownership": { + "oneOf": [ + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["namewrapper"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["fully-onchain"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["burned"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["unknown"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + } + ] + }, + "mintStatus": { + "type": "string", + "enum": ["minted", "burned"] + } + }, + "required": ["token", "ownership", "mintStatus"] + }, + "minItems": 1 + }, + "expiresAt": { + "type": "integer" + }, + "accurateAsOf": { + "type": "integer" + } + }, + "required": [ + "domainId", + "name", + "tokens", + "expiresAt", + "accurateAsOf" + ] + } + }, + "required": ["responseCode", "registeredNameTokens"], + "additionalProperties": false + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + }, + "errorCode": { + "type": "string", + "enum": ["name-tokens-not-indexed"] + }, + "error": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + }, + "errorCode": { + "type": "string", + "enum": ["unsupported-ensindexer-config"] + }, + "error": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + }, + "errorCode": { + "type": "string", + "enum": ["unsupported-indexing-status"] + }, + "error": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + } + ] + } + ] + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + } + } + }, + "503": { + "description": "Service unavailable - Name Tokens API prerequisites not met (indexing status not ready or required plugins not activated)", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["ok"] + }, + "registeredNameTokens": { + "type": "object", + "properties": { + "domainId": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "type": "object", + "properties": { + "assetNamespace": { + "type": "string", + "enum": ["erc721", "erc1155"] + }, + "contract": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + }, + "tokenId": { + "type": "string" + } + }, + "required": [ + "assetNamespace", + "contract", + "tokenId" + ] + }, + "ownership": { + "oneOf": [ + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["namewrapper"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["fully-onchain"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["burned"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["unknown"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { + "type": "string" + } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + } + ] + }, + "mintStatus": { + "type": "string", + "enum": ["minted", "burned"] + } + }, + "required": ["token", "ownership", "mintStatus"] + }, + "minItems": 1 + }, + "expiresAt": { + "type": "integer" + }, + "accurateAsOf": { + "type": "integer" + } + }, + "required": [ + "domainId", + "name", + "tokens", + "expiresAt", + "accurateAsOf" + ] + } + }, + "required": ["responseCode", "registeredNameTokens"], + "additionalProperties": false + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + }, + "errorCode": { + "type": "string", + "enum": ["name-tokens-not-indexed"] + }, + "error": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + }, + "errorCode": { + "type": "string", + "enum": ["unsupported-ensindexer-config"] + }, + "error": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { + "type": "string", + "enum": ["error"] + }, + "errorCode": { + "type": "string", + "enum": ["unsupported-indexing-status"] + }, + "error": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "details": {} + }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + } + ] + } + ] + } + } + } + } + } + } + }, + "/api/registrar-actions": { + "get": { + "operationId": "getRegistrarActions", + "tags": ["Explore"], + "summary": "Get Registrar Actions", + "description": "Returns all registrar actions with optional filtering and pagination", + "parameters": [ + { + "schema": { + "type": "string", + "enum": ["orderBy[timestamp]=desc"], + "default": "orderBy[timestamp]=desc", + "description": "Order of results" + }, + "required": false, + "description": "Order of results", + "name": "orderBy", + "in": "query" + }, + { + "schema": { + "description": "Page number for pagination" + }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { + "description": "Number of records per page" + }, + "required": false, + "description": "Number of records per page", + "name": "recordsPerPage", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false, + "description": "Filter to only include actions with referrals" + }, + "required": false, + "description": "Filter to only include actions with referrals", + "name": "withReferral", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by decoded referrer address" + }, + "required": false, + "description": "Filter by decoded referrer address", + "name": "decodedReferrer", + "in": "query" + }, + { + "schema": { + "description": "Filter actions at or after this Unix timestamp" + }, + "required": false, + "description": "Filter actions at or after this Unix timestamp", + "name": "beginTimestamp", + "in": "query" + }, + { + "schema": { + "description": "Filter actions at or before this Unix timestamp" + }, + "required": false, + "description": "Filter actions at or before this Unix timestamp", + "name": "endTimestamp", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved registrar actions" + }, + "400": { + "description": "Invalid query" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/api/registrar-actions/{parentNode}": { + "get": { + "operationId": "getRegistrarActionsByParentNode", + "tags": ["Explore"], + "summary": "Get Registrar Actions by Parent Node", + "description": "Returns registrar actions filtered by parent node hash with optional additional filtering and pagination", + "parameters": [ + { + "schema": { + "type": "string", + "description": "Parent node to filter registrar actions" + }, + "required": true, + "description": "Parent node to filter registrar actions", + "name": "parentNode", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": ["orderBy[timestamp]=desc"], + "default": "orderBy[timestamp]=desc", + "description": "Order of results" + }, + "required": false, + "description": "Order of results", + "name": "orderBy", + "in": "query" + }, + { + "schema": { + "description": "Page number for pagination" + }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { + "description": "Number of records per page" + }, + "required": false, + "description": "Number of records per page", + "name": "recordsPerPage", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false, + "description": "Filter to only include actions with referrals" + }, + "required": false, + "description": "Filter to only include actions with referrals", + "name": "withReferral", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by decoded referrer address" + }, + "required": false, + "description": "Filter by decoded referrer address", + "name": "decodedReferrer", + "in": "query" + }, + { + "schema": { + "description": "Filter actions at or after this Unix timestamp" + }, + "required": false, + "description": "Filter actions at or after this Unix timestamp", + "name": "beginTimestamp", + "in": "query" + }, + { + "schema": { + "description": "Filter actions at or before this Unix timestamp" + }, + "required": false, + "description": "Filter actions at or before this Unix timestamp", + "name": "endTimestamp", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved registrar actions" + }, + "400": { + "description": "Invalid input" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/api/resolve/records/{name}": { + "get": { + "operationId": "resolveRecords", + "tags": ["Resolution"], + "summary": "Resolve ENS Records", + "description": "Resolves ENS records for a given name", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "name", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "name", + "in": "query" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "addresses", + "in": "query" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "texts", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false + }, + "required": false, + "name": "trace", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false + }, + "required": false, + "name": "accelerate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully resolved records", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "records": { + "type": "object", + "properties": { + "name": { + "type": ["string", "null"] + }, + "addresses": { + "type": "object", + "additionalProperties": { + "type": ["string", "null"] + } + }, + "texts": { + "type": "object", + "additionalProperties": { + "type": ["string", "null"] + } + } + } + }, + "accelerationRequested": { + "type": "boolean" + }, + "accelerationAttempted": { + "type": "boolean" + }, + "trace": { + "type": "array", + "items": {} + } + }, + "required": [ + "records", + "accelerationRequested", + "accelerationAttempted" + ] + } + } + } + } + } + } + }, + "/api/resolve/primary-name/{address}/{chainId}": { + "get": { + "operationId": "resolvePrimaryName", + "tags": ["Resolution"], + "summary": "Resolve Primary Name", + "description": "Resolves a primary name for a given `address` and `chainId`", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "address", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": true, + "name": "chainId", + "in": "path" + }, + { + "schema": { + "type": "string", + "default": false + }, + "required": false, + "name": "trace", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false + }, + "required": false, + "name": "accelerate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully resolved name", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": ["string", "null"] + }, + "accelerationRequested": { + "type": "boolean" + }, + "accelerationAttempted": { + "type": "boolean" + }, + "trace": { + "type": "array", + "items": {} + } + }, + "required": [ + "name", + "accelerationRequested", + "accelerationAttempted" + ] + } + } + } + } + } + } + }, + "/api/resolve/primary-names/{address}": { + "get": { + "operationId": "resolvePrimaryNames", + "tags": ["Resolution"], + "summary": "Resolve Primary Names", + "description": "Resolves all primary names for a given address across multiple chains", + "parameters": [ + { + "schema": { + "type": "string" + }, + "required": true, + "name": "address", + "in": "path" + }, + { + "schema": { + "type": "string" + }, + "required": false, + "name": "chainIds", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false + }, + "required": false, + "name": "trace", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false + }, + "required": false, + "name": "accelerate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully resolved records", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "names": { + "type": "object", + "additionalProperties": { + "type": ["string", "null"] + } + }, + "accelerationRequested": { + "type": "boolean" + }, + "accelerationAttempted": { + "type": "boolean" + }, + "trace": { + "type": "array", + "items": {} + } + }, + "required": [ + "names", + "accelerationRequested", + "accelerationAttempted" + ] + } + } + } + } + } + } + } + }, + "webhooks": {} +} diff --git a/package.json b/package.json index 83f2da0c0..6923a4bc8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "ensnode-monorepo", "version": "0.0.1", "private": true, - "packageManager": "pnpm@10.28.0", + "packageManager": "pnpm@10.30.3", "scripts": { "lint": "biome check --write .", "lint:ci": "biome ci", @@ -19,6 +19,7 @@ "docker:build:ensadmin": "docker build -f apps/ensadmin/Dockerfile -t ghcr.io/namehash/ensnode/ensadmin:latest .", "docker:build:ensrainbow": "docker build -f apps/ensrainbow/Dockerfile -t ghcr.io/namehash/ensnode/ensrainbow:latest .", "docker:build:ensapi": "docker build -f apps/ensapi/Dockerfile -t ghcr.io/namehash/ensnode/ensapi:latest .", + "generate:openapi": "pnpm -r generate:openapi", "otel-desktop-viewer": "docker run -p 8000:8000 -p 4317:4317 -p 4318:4318 davetron5000/otel-desktop-viewer:alpine-3" }, "devDependencies": { From c295e979ca1bd4e7e7d859b955fee09cca0a286d Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 10:14:12 +0000 Subject: [PATCH 02/21] add symlink to enable mintlify to build correct file --- docs/docs.ensnode.io/docs.json | 2 +- docs/docs.ensnode.io/ensapi-openapi.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 120000 docs/docs.ensnode.io/ensapi-openapi.json diff --git a/docs/docs.ensnode.io/docs.json b/docs/docs.ensnode.io/docs.json index d4594771e..5502080c8 100644 --- a/docs/docs.ensnode.io/docs.json +++ b/docs/docs.ensnode.io/docs.json @@ -29,7 +29,7 @@ { "group": "Preview", "pages": ["ensapi/preview"], - "openapi": "../../openapi/ensapi-openapi.json", + "openapi": "ensapi-openapi.json", "hidden": true } ] diff --git a/docs/docs.ensnode.io/ensapi-openapi.json b/docs/docs.ensnode.io/ensapi-openapi.json new file mode 120000 index 000000000..127c2ab37 --- /dev/null +++ b/docs/docs.ensnode.io/ensapi-openapi.json @@ -0,0 +1 @@ +../../openapi/ensapi-openapi.json \ No newline at end of file From 859e9d80bd6c8a25affb5f38f7b4dcd74ed6694e Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 12:21:08 +0000 Subject: [PATCH 03/21] remove unnecessary newline --- apps/ensapi/scripts/generate-openapi.ts | 4 +- openapi/ensapi-openapi.json | 303 +++++------------------- 2 files changed, 58 insertions(+), 249 deletions(-) diff --git a/apps/ensapi/scripts/generate-openapi.ts b/apps/ensapi/scripts/generate-openapi.ts index 3b00a153b..a022df20b 100644 --- a/apps/ensapi/scripts/generate-openapi.ts +++ b/apps/ensapi/scripts/generate-openapi.ts @@ -25,8 +25,8 @@ const document = generateOpenApi31Document(); // Ensure output directory exists mkdirSync(dirname(outputPath), { recursive: true }); -// Write JSON -writeFileSync(outputPath, JSON.stringify(document, null, 2) + "\n"); +// Write JSON (Biome handles formatting) +writeFileSync(outputPath, JSON.stringify(document)); console.log(`OpenAPI spec written to ${outputPath}`); diff --git a/openapi/ensapi-openapi.json b/openapi/ensapi-openapi.json index b6f591496..6648afe8d 100644 --- a/openapi/ensapi-openapi.json +++ b/openapi/ensapi-openapi.json @@ -108,11 +108,7 @@ }, "reason": { "type": "string", - "enum": [ - "not-subgraph-compatible", - "no-api-key", - "no-subgraph-url" - ] + "enum": ["not-subgraph-compatible", "no-api-key", "no-subgraph-url"] } }, "required": ["canFallback", "reason"], @@ -151,12 +147,7 @@ }, "namespace": { "type": "string", - "enum": [ - "mainnet", - "sepolia", - "sepolia-v2", - "ens-test-env" - ] + "enum": ["mainnet", "sepolia", "sepolia-v2", "ens-test-env"] }, "plugins": { "type": "array", @@ -224,11 +215,7 @@ ] } }, - "required": [ - "version", - "theGraphFallback", - "ensIndexerPublicConfig" - ] + "required": ["version", "theGraphFallback", "ensIndexerPublicConfig"] } } } @@ -310,17 +297,11 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, - "required": [ - "rangeType", - "startBlock" - ] + "required": ["rangeType", "startBlock"] }, { "type": "object", @@ -340,10 +321,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "endBlock": { @@ -357,10 +335,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -373,10 +348,7 @@ ] } }, - "required": [ - "chainStatus", - "config" - ] + "required": ["chainStatus", "config"] } ] } @@ -429,17 +401,11 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, - "required": [ - "rangeType", - "startBlock" - ] + "required": ["rangeType", "startBlock"] }, { "type": "object", @@ -459,10 +425,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "endBlock": { @@ -476,10 +439,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -492,10 +452,7 @@ ] } }, - "required": [ - "chainStatus", - "config" - ] + "required": ["chainStatus", "config"] }, { "type": "object", @@ -524,17 +481,11 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, - "required": [ - "rangeType", - "startBlock" - ] + "required": ["rangeType", "startBlock"] }, { "type": "object", @@ -554,10 +505,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "endBlock": { @@ -571,10 +519,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -597,10 +542,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "backfillEndBlock": { @@ -614,10 +556,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -653,10 +592,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "endBlock": { @@ -670,18 +606,11 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] + "required": ["rangeType", "startBlock", "endBlock"] }, "latestIndexedBlock": { "type": "object", @@ -694,10 +623,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -756,10 +682,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "endBlock": { @@ -773,18 +696,11 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] + "required": ["rangeType", "startBlock", "endBlock"] }, "latestIndexedBlock": { "type": "object", @@ -797,10 +713,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -861,17 +774,11 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, - "required": [ - "rangeType", - "startBlock" - ] + "required": ["rangeType", "startBlock"] }, { "type": "object", @@ -891,10 +798,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "endBlock": { @@ -908,10 +812,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -924,10 +825,7 @@ ] } }, - "required": [ - "chainStatus", - "config" - ] + "required": ["chainStatus", "config"] }, { "type": "object", @@ -956,17 +854,11 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, - "required": [ - "rangeType", - "startBlock" - ] + "required": ["rangeType", "startBlock"] }, { "type": "object", @@ -986,10 +878,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "endBlock": { @@ -1003,10 +892,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -1029,10 +915,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "backfillEndBlock": { @@ -1046,10 +929,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -1085,17 +965,11 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, - "required": [ - "rangeType", - "startBlock" - ] + "required": ["rangeType", "startBlock"] }, "latestIndexedBlock": { "type": "object", @@ -1108,10 +982,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "latestKnownBlock": { @@ -1125,10 +996,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -1164,10 +1032,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false }, "endBlock": { @@ -1181,18 +1046,11 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] + "required": ["rangeType", "startBlock", "endBlock"] }, "latestIndexedBlock": { "type": "object", @@ -1205,10 +1063,7 @@ "minimum": 0 } }, - "required": [ - "timestamp", - "number" - ], + "required": ["timestamp", "number"], "additionalProperties": false } }, @@ -1248,11 +1103,7 @@ "type": "number" } }, - "required": [ - "snapshot", - "projectedAt", - "worstCaseDistance" - ] + "required": ["snapshot", "projectedAt", "worstCaseDistance"] } }, "required": ["responseCode", "realtimeProjection"], @@ -1558,11 +1409,7 @@ "type": "string" } }, - "required": [ - "assetNamespace", - "contract", - "tokenId" - ] + "required": ["assetNamespace", "contract", "tokenId"] }, "ownership": { "oneOf": [ @@ -1680,13 +1527,7 @@ "type": "integer" } }, - "required": [ - "domainId", - "name", - "tokens", - "expiresAt", - "accurateAsOf" - ] + "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] } }, "required": ["responseCode", "registeredNameTokens"], @@ -1845,11 +1686,7 @@ "type": "string" } }, - "required": [ - "assetNamespace", - "contract", - "tokenId" - ] + "required": ["assetNamespace", "contract", "tokenId"] }, "ownership": { "oneOf": [ @@ -1967,13 +1804,7 @@ "type": "integer" } }, - "required": [ - "domainId", - "name", - "tokens", - "expiresAt", - "accurateAsOf" - ] + "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] } }, "required": ["responseCode", "registeredNameTokens"], @@ -2132,11 +1963,7 @@ "type": "string" } }, - "required": [ - "assetNamespace", - "contract", - "tokenId" - ] + "required": ["assetNamespace", "contract", "tokenId"] }, "ownership": { "oneOf": [ @@ -2254,13 +2081,7 @@ "type": "integer" } }, - "required": [ - "domainId", - "name", - "tokens", - "expiresAt", - "accurateAsOf" - ] + "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] } }, "required": ["responseCode", "registeredNameTokens"], @@ -2640,11 +2461,7 @@ "items": {} } }, - "required": [ - "records", - "accelerationRequested", - "accelerationAttempted" - ] + "required": ["records", "accelerationRequested", "accelerationAttempted"] } } } @@ -2716,11 +2533,7 @@ "items": {} } }, - "required": [ - "name", - "accelerationRequested", - "accelerationAttempted" - ] + "required": ["name", "accelerationRequested", "accelerationAttempted"] } } } @@ -2795,11 +2608,7 @@ "items": {} } }, - "required": [ - "names", - "accelerationRequested", - "accelerationAttempted" - ] + "required": ["names", "accelerationRequested", "accelerationAttempted"] } } } From a93559ad612e3f67baf1a0810c1165d4dac5023b Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 12:22:25 +0000 Subject: [PATCH 04/21] apply code suggestions --- apps/ensapi/scripts/generate-openapi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ensapi/scripts/generate-openapi.ts b/apps/ensapi/scripts/generate-openapi.ts index a022df20b..d289bd23d 100644 --- a/apps/ensapi/scripts/generate-openapi.ts +++ b/apps/ensapi/scripts/generate-openapi.ts @@ -33,7 +33,7 @@ console.log(`OpenAPI spec written to ${outputPath}`); // Format with Biome for consistency console.log("Formatting with Biome..."); try { - execFileSync("pnpm", ["biome", "format", "--write", outputPath], { + execFileSync("pnpm", ["exec", "-w", "biome", "format", "--write", outputPath], { stdio: "inherit", }); } catch (error) { From 942d9c97727d54704add4a41d1b0bf7b4e9efbc3 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 12:32:30 +0000 Subject: [PATCH 05/21] fix relative paths for mintlify --- apps/ensapi/scripts/generate-openapi.ts | 18 +- docs/docs.ensnode.io/ensapi-openapi.json | 2053 ++++++++++++++++- docs/docs.ensnode.io/ensapi/preview.mdx | 9 + openapi/ensapi-openapi.json | 2622 +--------------------- 4 files changed, 2074 insertions(+), 2628 deletions(-) mode change 120000 => 100644 docs/docs.ensnode.io/ensapi-openapi.json create mode 100644 docs/docs.ensnode.io/ensapi/preview.mdx mode change 100644 => 120000 openapi/ensapi-openapi.json diff --git a/apps/ensapi/scripts/generate-openapi.ts b/apps/ensapi/scripts/generate-openapi.ts index d289bd23d..07ab718dc 100644 --- a/apps/ensapi/scripts/generate-openapi.ts +++ b/apps/ensapi/scripts/generate-openapi.ts @@ -3,7 +3,7 @@ * * Usage: tsx scripts/generate-openapi.ts * - * Output: /openapi/ensapi-openapi.json + * Output: /docs/docs.ensnode.io/ensapi-openapi.json * * This script has no runtime dependencies — it calls generateOpenApi31Document() * which uses only stub route handlers and static metadata. @@ -17,15 +17,21 @@ import { fileURLToPath } from "node:url"; import { generateOpenApi31Document } from "@/openapi-document"; const __dirname = dirname(fileURLToPath(import.meta.url)); -const outputPath = resolve(__dirname, "..", "..", "..", "openapi", "ensapi-openapi.json"); +const outputPath = resolve( + __dirname, + "..", + "..", + "..", + "docs", + "docs.ensnode.io", + "ensapi-openapi.json", +); // Generate the document (no additional servers for the static spec) const document = generateOpenApi31Document(); -// Ensure output directory exists -mkdirSync(dirname(outputPath), { recursive: true }); - // Write JSON (Biome handles formatting) +mkdirSync(dirname(outputPath), { recursive: true }); writeFileSync(outputPath, JSON.stringify(document)); console.log(`OpenAPI spec written to ${outputPath}`); @@ -33,7 +39,7 @@ console.log(`OpenAPI spec written to ${outputPath}`); // Format with Biome for consistency console.log("Formatting with Biome..."); try { - execFileSync("pnpm", ["exec", "-w", "biome", "format", "--write", outputPath], { + execFileSync("pnpm", ["exec", "biome", "format", "--write", outputPath], { stdio: "inherit", }); } catch (error) { diff --git a/docs/docs.ensnode.io/ensapi-openapi.json b/docs/docs.ensnode.io/ensapi-openapi.json deleted file mode 120000 index 127c2ab37..000000000 --- a/docs/docs.ensnode.io/ensapi-openapi.json +++ /dev/null @@ -1 +0,0 @@ -../../openapi/ensapi-openapi.json \ No newline at end of file diff --git a/docs/docs.ensnode.io/ensapi-openapi.json b/docs/docs.ensnode.io/ensapi-openapi.json new file mode 100644 index 000000000..b6f97802d --- /dev/null +++ b/docs/docs.ensnode.io/ensapi-openapi.json @@ -0,0 +1,2052 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "ENSApi APIs", + "version": "1.5.1", + "description": "APIs for ENS resolution, navigating the ENS nameforest, and metadata about an ENSNode" + }, + "servers": [ + { "url": "https://api.alpha.ensnode.io", "description": "ENSNode Alpha (Mainnet)" }, + { + "url": "https://api.alpha-sepolia.ensnode.io", + "description": "ENSNode Alpha (Sepolia Testnet)" + } + ], + "tags": [ + { "name": "Resolution", "description": "APIs for resolving ENS names and addresses" }, + { + "name": "Meta", + "description": "APIs for indexing status, configuration, and realtime monitoring" + }, + { + "name": "Explore", + "description": "APIs for exploring the indexed state of ENS, including name tokens and registrar actions" + }, + { + "name": "ENSAwards", + "description": "APIs for ENSAwards functionality, including referrer data" + } + ], + "components": { "schemas": {}, "parameters": {} }, + "paths": { + "/amirealtime": { + "get": { + "operationId": "isRealtime", + "tags": ["Meta"], + "summary": "Check indexing progress", + "description": "Checks if the indexing progress is guaranteed to be within a requested worst-case distance of realtime", + "parameters": [ + { + "schema": { + "description": "Maximum acceptable worst-case indexing distance in seconds" + }, + "required": false, + "description": "Maximum acceptable worst-case indexing distance in seconds", + "name": "maxWorstCaseDistance", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Indexing progress is guaranteed to be within the requested distance of realtime" + }, + "503": { + "description": "Indexing progress is not guaranteed to be within the requested distance of realtime or indexing status unavailable" + } + } + } + }, + "/api/config": { + "get": { + "operationId": "getConfig", + "tags": ["Meta"], + "summary": "Get ENSApi Public Config", + "description": "Gets the public config of the ENSApi instance", + "responses": { + "200": { + "description": "Successfully retrieved ENSApi public config", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { "type": "string", "minLength": 1 }, + "theGraphFallback": { + "oneOf": [ + { + "type": "object", + "properties": { + "canFallback": { "type": "boolean", "enum": [true] }, + "url": { "type": "string" } + }, + "required": ["canFallback", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "canFallback": { "type": "boolean", "enum": [false] }, + "reason": { + "type": "string", + "enum": ["not-subgraph-compatible", "no-api-key", "no-subgraph-url"] + } + }, + "required": ["canFallback", "reason"], + "additionalProperties": false + } + ] + }, + "ensIndexerPublicConfig": { + "type": "object", + "properties": { + "labelSet": { + "type": "object", + "properties": { + "labelSetId": { + "type": "string", + "minLength": 1, + "maxLength": 50, + "pattern": "^[a-z-]+$" + }, + "labelSetVersion": { "type": ["number", "null"] } + }, + "required": ["labelSetId", "labelSetVersion"] + }, + "indexedChainIds": { + "type": "array", + "items": { "type": "integer", "exclusiveMinimum": 0 }, + "minItems": 1 + }, + "isSubgraphCompatible": { "type": "boolean" }, + "namespace": { + "type": "string", + "enum": ["mainnet", "sepolia", "sepolia-v2", "ens-test-env"] + }, + "plugins": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "databaseSchemaName": { "type": "string", "minLength": 1 }, + "versionInfo": { + "type": "object", + "properties": { + "nodejs": { "type": "string", "minLength": 1 }, + "ponder": { "type": "string", "minLength": 1 }, + "ensDb": { "type": "string", "minLength": 1 }, + "ensIndexer": { "type": "string", "minLength": 1 }, + "ensNormalize": { "type": "string", "minLength": 1 }, + "ensRainbow": { "type": "string", "minLength": 1 }, + "ensRainbowSchema": { "type": "integer", "exclusiveMinimum": 0 } + }, + "required": [ + "nodejs", + "ponder", + "ensDb", + "ensIndexer", + "ensNormalize", + "ensRainbow", + "ensRainbowSchema" + ], + "additionalProperties": false + } + }, + "required": [ + "labelSet", + "indexedChainIds", + "isSubgraphCompatible", + "namespace", + "plugins", + "databaseSchemaName", + "versionInfo" + ] + } + }, + "required": ["version", "theGraphFallback", "ensIndexerPublicConfig"] + } + } + } + } + } + } + }, + "/api/indexing-status": { + "get": { + "operationId": "getIndexingStatus", + "tags": ["Meta"], + "summary": "Get ENSIndexer Indexing Status", + "description": "Returns the indexing status snapshot most recently captured from ENSIndexer", + "responses": { + "200": { + "description": "Successfully retrieved indexing status", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["ok"] }, + "realtimeProjection": { + "type": "object", + "properties": { + "snapshot": { + "type": "object", + "properties": { + "strategy": { "type": "string", "enum": ["omnichain"] }, + "slowestChainIndexingCursor": { "type": "integer" }, + "snapshotTime": { "type": "integer" }, + "omnichainSnapshot": { + "oneOf": [ + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-unstarted"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-queued"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + } + }, + "required": ["chainStatus", "config"] + } + ] + } + }, + "omnichainIndexingCursor": { "type": "integer" } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + }, + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-backfill"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-queued"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + } + }, + "required": ["chainStatus", "config"] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-backfill"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "backfillEndBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock", + "backfillEndBlock" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-completed"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock", "endBlock"] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock" + ] + } + ] + } + }, + "omnichainIndexingCursor": { "type": "integer" } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + }, + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-completed"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-completed"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock", "endBlock"] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock" + ] + } + ] + } + }, + "omnichainIndexingCursor": { "type": "integer" } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + }, + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-following"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-queued"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + } + }, + "required": ["chainStatus", "config"] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-backfill"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "backfillEndBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock", + "backfillEndBlock" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-following"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "latestKnownBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock", + "latestKnownBlock" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-completed"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock", "endBlock"] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock" + ] + } + ] + } + }, + "omnichainIndexingCursor": { "type": "integer" } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + } + ] + } + }, + "required": [ + "strategy", + "slowestChainIndexingCursor", + "snapshotTime", + "omnichainSnapshot" + ] + }, + "projectedAt": { "type": "integer" }, + "worstCaseDistance": { "type": "number" } + }, + "required": ["snapshot", "projectedAt", "worstCaseDistance"] + } + }, + "required": ["responseCode", "realtimeProjection"], + "additionalProperties": false + } + } + } + }, + "503": { + "description": "Indexing status snapshot unavailable", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "responseCode": { "type": "string", "enum": ["error"] } }, + "required": ["responseCode"], + "additionalProperties": false + } + } + } + } + } + } + }, + "/v1/ensanalytics/referral-leaderboard": { + "get": { + "operationId": "getReferralLeaderboard_v1", + "tags": ["ENSAwards"], + "summary": "Get Referrer Leaderboard (v1)", + "description": "Returns a paginated page from the referrer leaderboard for a specific edition", + "parameters": [ + { + "schema": { "type": "string", "minLength": 1, "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" }, + "required": true, + "name": "edition", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number for pagination" + }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "description": "Number of referrers per page" + }, + "required": false, + "description": "Number of referrers per page", + "name": "recordsPerPage", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved referrer leaderboard page" }, + "404": { "description": "Unknown edition slug" }, + "500": { "description": "Internal server error" }, + "503": { "description": "Service unavailable" } + } + } + }, + "/v1/ensanalytics/referrer/{referrer}": { + "get": { + "operationId": "getReferrerDetail_v1", + "tags": ["ENSAwards"], + "summary": "Get Referrer Detail for Editions (v1)", + "description": "Returns detailed information for a specific referrer for the requested editions. Requires 1-20 distinct edition slugs. All requested editions must be recognized and have cached data, or the request fails.", + "parameters": [ + { + "schema": { "type": "string", "description": "Referrer Ethereum address" }, + "required": true, + "description": "Referrer Ethereum address", + "name": "referrer", + "in": "path" + }, + { + "schema": { "type": "string", "description": "Comma-separated list of edition slugs" }, + "required": true, + "description": "Comma-separated list of edition slugs", + "name": "editions", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved referrer detail for requested editions" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Unknown edition slug" }, + "500": { "description": "Internal server error" }, + "503": { "description": "Service unavailable" } + } + } + }, + "/v1/ensanalytics/editions": { + "get": { + "operationId": "getEditions_v1", + "tags": ["ENSAwards"], + "summary": "Get Edition Config Set (v1)", + "description": "Returns the currently configured referral program edition config set. Editions are sorted in descending order by start timestamp (most recent first).", + "responses": { + "200": { "description": "Successfully retrieved edition config set" }, + "500": { "description": "Internal server error" }, + "503": { "description": "Service unavailable" } + } + } + }, + "/ensanalytics/referrers": { + "get": { + "operationId": "getReferrerLeaderboard", + "tags": ["ENSAwards"], + "summary": "Get Referrer Leaderboard", + "description": "Returns a paginated page from the referrer leaderboard", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number for pagination" + }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "description": "Number of referrers per page" + }, + "required": false, + "description": "Number of referrers per page", + "name": "recordsPerPage", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved referrer leaderboard page" }, + "500": { "description": "Internal server error" } + } + } + }, + "/ensanalytics/referrers/{referrer}": { + "get": { + "operationId": "getReferrerDetail", + "tags": ["ENSAwards"], + "summary": "Get Referrer Detail", + "description": "Returns detailed information for a specific referrer by address", + "parameters": [ + { + "schema": { "type": "string", "description": "Referrer Ethereum address" }, + "required": true, + "description": "Referrer Ethereum address", + "name": "referrer", + "in": "path" + } + ], + "responses": { + "200": { "description": "Successfully retrieved referrer detail" }, + "500": { "description": "Internal server error" }, + "503": { "description": "Service unavailable - referrer leaderboard data not yet cached" } + } + } + }, + "/api/name-tokens": { + "get": { + "operationId": "getNameTokens", + "tags": ["Explore"], + "summary": "Get Name Tokens", + "description": "Returns name tokens for the requested identifier (domainId or name)", + "parameters": [ + { + "schema": { "type": "string", "description": "Domain node hash identifier" }, + "required": false, + "description": "Domain node hash identifier", + "name": "domainId", + "in": "query" + }, + { + "schema": { "type": "string", "description": "ENS name to look up tokens for" }, + "required": false, + "description": "ENS name to look up tokens for", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Name tokens known", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["ok"] }, + "registeredNameTokens": { + "type": "object", + "properties": { + "domainId": { "type": "string" }, + "name": { "type": "string" }, + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "type": "object", + "properties": { + "assetNamespace": { + "type": "string", + "enum": ["erc721", "erc1155"] + }, + "contract": { + "type": "object", + "properties": { + "chainId": { "type": "integer", "exclusiveMinimum": 0 }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + }, + "tokenId": { "type": "string" } + }, + "required": ["assetNamespace", "contract", "tokenId"] + }, + "ownership": { + "oneOf": [ + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["namewrapper"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["fully-onchain"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { "type": "string", "enum": ["burned"] }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["unknown"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + } + ] + }, + "mintStatus": { "type": "string", "enum": ["minted", "burned"] } + }, + "required": ["token", "ownership", "mintStatus"] + }, + "minItems": 1 + }, + "expiresAt": { "type": "integer" }, + "accurateAsOf": { "type": "integer" } + }, + "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] + } + }, + "required": ["responseCode", "registeredNameTokens"], + "additionalProperties": false + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { "type": "string", "enum": ["name-tokens-not-indexed"] }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-ensindexer-config"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-indexing-status"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + } + ] + } + ] + } + } + } + }, + "400": { + "description": "Invalid input", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + } + } + }, + "404": { + "description": "Name tokens not indexed", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["ok"] }, + "registeredNameTokens": { + "type": "object", + "properties": { + "domainId": { "type": "string" }, + "name": { "type": "string" }, + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "type": "object", + "properties": { + "assetNamespace": { + "type": "string", + "enum": ["erc721", "erc1155"] + }, + "contract": { + "type": "object", + "properties": { + "chainId": { "type": "integer", "exclusiveMinimum": 0 }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + }, + "tokenId": { "type": "string" } + }, + "required": ["assetNamespace", "contract", "tokenId"] + }, + "ownership": { + "oneOf": [ + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["namewrapper"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["fully-onchain"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { "type": "string", "enum": ["burned"] }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["unknown"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + } + ] + }, + "mintStatus": { "type": "string", "enum": ["minted", "burned"] } + }, + "required": ["token", "ownership", "mintStatus"] + }, + "minItems": 1 + }, + "expiresAt": { "type": "integer" }, + "accurateAsOf": { "type": "integer" } + }, + "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] + } + }, + "required": ["responseCode", "registeredNameTokens"], + "additionalProperties": false + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { "type": "string", "enum": ["name-tokens-not-indexed"] }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-ensindexer-config"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-indexing-status"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + } + ] + } + ] + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + } + } + }, + "503": { + "description": "Service unavailable - Name Tokens API prerequisites not met (indexing status not ready or required plugins not activated)", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["ok"] }, + "registeredNameTokens": { + "type": "object", + "properties": { + "domainId": { "type": "string" }, + "name": { "type": "string" }, + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "type": "object", + "properties": { + "assetNamespace": { + "type": "string", + "enum": ["erc721", "erc1155"] + }, + "contract": { + "type": "object", + "properties": { + "chainId": { "type": "integer", "exclusiveMinimum": 0 }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + }, + "tokenId": { "type": "string" } + }, + "required": ["assetNamespace", "contract", "tokenId"] + }, + "ownership": { + "oneOf": [ + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["namewrapper"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["fully-onchain"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { "type": "string", "enum": ["burned"] }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["unknown"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + } + ] + }, + "mintStatus": { "type": "string", "enum": ["minted", "burned"] } + }, + "required": ["token", "ownership", "mintStatus"] + }, + "minItems": 1 + }, + "expiresAt": { "type": "integer" }, + "accurateAsOf": { "type": "integer" } + }, + "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] + } + }, + "required": ["responseCode", "registeredNameTokens"], + "additionalProperties": false + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { "type": "string", "enum": ["name-tokens-not-indexed"] }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-ensindexer-config"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-indexing-status"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + } + ] + } + ] + } + } + } + } + } + } + }, + "/api/registrar-actions": { + "get": { + "operationId": "getRegistrarActions", + "tags": ["Explore"], + "summary": "Get Registrar Actions", + "description": "Returns all registrar actions with optional filtering and pagination", + "parameters": [ + { + "schema": { + "type": "string", + "enum": ["orderBy[timestamp]=desc"], + "default": "orderBy[timestamp]=desc", + "description": "Order of results" + }, + "required": false, + "description": "Order of results", + "name": "orderBy", + "in": "query" + }, + { + "schema": { "description": "Page number for pagination" }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { "description": "Number of records per page" }, + "required": false, + "description": "Number of records per page", + "name": "recordsPerPage", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false, + "description": "Filter to only include actions with referrals" + }, + "required": false, + "description": "Filter to only include actions with referrals", + "name": "withReferral", + "in": "query" + }, + { + "schema": { "type": "string", "description": "Filter by decoded referrer address" }, + "required": false, + "description": "Filter by decoded referrer address", + "name": "decodedReferrer", + "in": "query" + }, + { + "schema": { "description": "Filter actions at or after this Unix timestamp" }, + "required": false, + "description": "Filter actions at or after this Unix timestamp", + "name": "beginTimestamp", + "in": "query" + }, + { + "schema": { "description": "Filter actions at or before this Unix timestamp" }, + "required": false, + "description": "Filter actions at or before this Unix timestamp", + "name": "endTimestamp", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved registrar actions" }, + "400": { "description": "Invalid query" }, + "500": { "description": "Internal server error" } + } + } + }, + "/api/registrar-actions/{parentNode}": { + "get": { + "operationId": "getRegistrarActionsByParentNode", + "tags": ["Explore"], + "summary": "Get Registrar Actions by Parent Node", + "description": "Returns registrar actions filtered by parent node hash with optional additional filtering and pagination", + "parameters": [ + { + "schema": { + "type": "string", + "description": "Parent node to filter registrar actions" + }, + "required": true, + "description": "Parent node to filter registrar actions", + "name": "parentNode", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": ["orderBy[timestamp]=desc"], + "default": "orderBy[timestamp]=desc", + "description": "Order of results" + }, + "required": false, + "description": "Order of results", + "name": "orderBy", + "in": "query" + }, + { + "schema": { "description": "Page number for pagination" }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { "description": "Number of records per page" }, + "required": false, + "description": "Number of records per page", + "name": "recordsPerPage", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false, + "description": "Filter to only include actions with referrals" + }, + "required": false, + "description": "Filter to only include actions with referrals", + "name": "withReferral", + "in": "query" + }, + { + "schema": { "type": "string", "description": "Filter by decoded referrer address" }, + "required": false, + "description": "Filter by decoded referrer address", + "name": "decodedReferrer", + "in": "query" + }, + { + "schema": { "description": "Filter actions at or after this Unix timestamp" }, + "required": false, + "description": "Filter actions at or after this Unix timestamp", + "name": "beginTimestamp", + "in": "query" + }, + { + "schema": { "description": "Filter actions at or before this Unix timestamp" }, + "required": false, + "description": "Filter actions at or before this Unix timestamp", + "name": "endTimestamp", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved registrar actions" }, + "400": { "description": "Invalid input" }, + "500": { "description": "Internal server error" } + } + } + }, + "/api/resolve/records/{name}": { + "get": { + "operationId": "resolveRecords", + "tags": ["Resolution"], + "summary": "Resolve ENS Records", + "description": "Resolves ENS records for a given name", + "parameters": [ + { "schema": { "type": "string" }, "required": true, "name": "name", "in": "path" }, + { "schema": { "type": "string" }, "required": false, "name": "name", "in": "query" }, + { "schema": { "type": "string" }, "required": false, "name": "addresses", "in": "query" }, + { "schema": { "type": "string" }, "required": false, "name": "texts", "in": "query" }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "trace", + "in": "query" + }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "accelerate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully resolved records", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "records": { + "type": "object", + "properties": { + "name": { "type": ["string", "null"] }, + "addresses": { + "type": "object", + "additionalProperties": { "type": ["string", "null"] } + }, + "texts": { + "type": "object", + "additionalProperties": { "type": ["string", "null"] } + } + } + }, + "accelerationRequested": { "type": "boolean" }, + "accelerationAttempted": { "type": "boolean" }, + "trace": { "type": "array", "items": {} } + }, + "required": ["records", "accelerationRequested", "accelerationAttempted"] + } + } + } + } + } + } + }, + "/api/resolve/primary-name/{address}/{chainId}": { + "get": { + "operationId": "resolvePrimaryName", + "tags": ["Resolution"], + "summary": "Resolve Primary Name", + "description": "Resolves a primary name for a given `address` and `chainId`", + "parameters": [ + { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, + { "schema": { "type": "string" }, "required": true, "name": "chainId", "in": "path" }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "trace", + "in": "query" + }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "accelerate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully resolved name", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": ["string", "null"] }, + "accelerationRequested": { "type": "boolean" }, + "accelerationAttempted": { "type": "boolean" }, + "trace": { "type": "array", "items": {} } + }, + "required": ["name", "accelerationRequested", "accelerationAttempted"] + } + } + } + } + } + } + }, + "/api/resolve/primary-names/{address}": { + "get": { + "operationId": "resolvePrimaryNames", + "tags": ["Resolution"], + "summary": "Resolve Primary Names", + "description": "Resolves all primary names for a given address across multiple chains", + "parameters": [ + { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, + { "schema": { "type": "string" }, "required": false, "name": "chainIds", "in": "query" }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "trace", + "in": "query" + }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "accelerate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully resolved records", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "names": { + "type": "object", + "additionalProperties": { "type": ["string", "null"] } + }, + "accelerationRequested": { "type": "boolean" }, + "accelerationAttempted": { "type": "boolean" }, + "trace": { "type": "array", "items": {} } + }, + "required": ["names", "accelerationRequested", "accelerationAttempted"] + } + } + } + } + } + } + } + }, + "webhooks": {} +} diff --git a/docs/docs.ensnode.io/ensapi/preview.mdx b/docs/docs.ensnode.io/ensapi/preview.mdx new file mode 100644 index 000000000..8907e98cd --- /dev/null +++ b/docs/docs.ensnode.io/ensapi/preview.mdx @@ -0,0 +1,9 @@ +--- +title: API Preview +sidebarTitle: Preview +description: Preview upcoming API changes from this branch. +--- + +This page provides a preview of the committed OpenAPI specification from the branch this docs site was built from (for pull requests, the PR's head branch), which may include unreleased API changes. + +For the production API documentation, see the [API Reference](/ensapi). diff --git a/openapi/ensapi-openapi.json b/openapi/ensapi-openapi.json deleted file mode 100644 index 6648afe8d..000000000 --- a/openapi/ensapi-openapi.json +++ /dev/null @@ -1,2621 +0,0 @@ -{ - "openapi": "3.1.0", - "info": { - "title": "ENSApi APIs", - "version": "1.5.1", - "description": "APIs for ENS resolution, navigating the ENS nameforest, and metadata about an ENSNode" - }, - "servers": [ - { - "url": "https://api.alpha.ensnode.io", - "description": "ENSNode Alpha (Mainnet)" - }, - { - "url": "https://api.alpha-sepolia.ensnode.io", - "description": "ENSNode Alpha (Sepolia Testnet)" - } - ], - "tags": [ - { - "name": "Resolution", - "description": "APIs for resolving ENS names and addresses" - }, - { - "name": "Meta", - "description": "APIs for indexing status, configuration, and realtime monitoring" - }, - { - "name": "Explore", - "description": "APIs for exploring the indexed state of ENS, including name tokens and registrar actions" - }, - { - "name": "ENSAwards", - "description": "APIs for ENSAwards functionality, including referrer data" - } - ], - "components": { - "schemas": {}, - "parameters": {} - }, - "paths": { - "/amirealtime": { - "get": { - "operationId": "isRealtime", - "tags": ["Meta"], - "summary": "Check indexing progress", - "description": "Checks if the indexing progress is guaranteed to be within a requested worst-case distance of realtime", - "parameters": [ - { - "schema": { - "description": "Maximum acceptable worst-case indexing distance in seconds" - }, - "required": false, - "description": "Maximum acceptable worst-case indexing distance in seconds", - "name": "maxWorstCaseDistance", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Indexing progress is guaranteed to be within the requested distance of realtime" - }, - "503": { - "description": "Indexing progress is not guaranteed to be within the requested distance of realtime or indexing status unavailable" - } - } - } - }, - "/api/config": { - "get": { - "operationId": "getConfig", - "tags": ["Meta"], - "summary": "Get ENSApi Public Config", - "description": "Gets the public config of the ENSApi instance", - "responses": { - "200": { - "description": "Successfully retrieved ENSApi public config", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "version": { - "type": "string", - "minLength": 1 - }, - "theGraphFallback": { - "oneOf": [ - { - "type": "object", - "properties": { - "canFallback": { - "type": "boolean", - "enum": [true] - }, - "url": { - "type": "string" - } - }, - "required": ["canFallback", "url"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "canFallback": { - "type": "boolean", - "enum": [false] - }, - "reason": { - "type": "string", - "enum": ["not-subgraph-compatible", "no-api-key", "no-subgraph-url"] - } - }, - "required": ["canFallback", "reason"], - "additionalProperties": false - } - ] - }, - "ensIndexerPublicConfig": { - "type": "object", - "properties": { - "labelSet": { - "type": "object", - "properties": { - "labelSetId": { - "type": "string", - "minLength": 1, - "maxLength": 50, - "pattern": "^[a-z-]+$" - }, - "labelSetVersion": { - "type": ["number", "null"] - } - }, - "required": ["labelSetId", "labelSetVersion"] - }, - "indexedChainIds": { - "type": "array", - "items": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "minItems": 1 - }, - "isSubgraphCompatible": { - "type": "boolean" - }, - "namespace": { - "type": "string", - "enum": ["mainnet", "sepolia", "sepolia-v2", "ens-test-env"] - }, - "plugins": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "databaseSchemaName": { - "type": "string", - "minLength": 1 - }, - "versionInfo": { - "type": "object", - "properties": { - "nodejs": { - "type": "string", - "minLength": 1 - }, - "ponder": { - "type": "string", - "minLength": 1 - }, - "ensDb": { - "type": "string", - "minLength": 1 - }, - "ensIndexer": { - "type": "string", - "minLength": 1 - }, - "ensNormalize": { - "type": "string", - "minLength": 1 - }, - "ensRainbow": { - "type": "string", - "minLength": 1 - }, - "ensRainbowSchema": { - "type": "integer", - "exclusiveMinimum": 0 - } - }, - "required": [ - "nodejs", - "ponder", - "ensDb", - "ensIndexer", - "ensNormalize", - "ensRainbow", - "ensRainbowSchema" - ], - "additionalProperties": false - } - }, - "required": [ - "labelSet", - "indexedChainIds", - "isSubgraphCompatible", - "namespace", - "plugins", - "databaseSchemaName", - "versionInfo" - ] - } - }, - "required": ["version", "theGraphFallback", "ensIndexerPublicConfig"] - } - } - } - } - } - } - }, - "/api/indexing-status": { - "get": { - "operationId": "getIndexingStatus", - "tags": ["Meta"], - "summary": "Get ENSIndexer Indexing Status", - "description": "Returns the indexing status snapshot most recently captured from ENSIndexer", - "responses": { - "200": { - "description": "Successfully retrieved indexing status", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["ok"] - }, - "realtimeProjection": { - "type": "object", - "properties": { - "snapshot": { - "type": "object", - "properties": { - "strategy": { - "type": "string", - "enum": ["omnichain"] - }, - "slowestChainIndexingCursor": { - "type": "integer" - }, - "snapshotTime": { - "type": "integer" - }, - "omnichainSnapshot": { - "oneOf": [ - { - "type": "object", - "properties": { - "omnichainStatus": { - "type": "string", - "enum": ["omnichain-unstarted"] - }, - "chains": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-queued"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - } - }, - "required": ["chainStatus", "config"] - } - ] - } - }, - "omnichainIndexingCursor": { - "type": "integer" - } - }, - "required": [ - "omnichainStatus", - "chains", - "omnichainIndexingCursor" - ] - }, - { - "type": "object", - "properties": { - "omnichainStatus": { - "type": "string", - "enum": ["omnichain-backfill"] - }, - "chains": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-queued"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - } - }, - "required": ["chainStatus", "config"] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-backfill"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "backfillEndBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock", - "backfillEndBlock" - ] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-completed"] - }, - "config": { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock", "endBlock"] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock" - ] - } - ] - } - }, - "omnichainIndexingCursor": { - "type": "integer" - } - }, - "required": [ - "omnichainStatus", - "chains", - "omnichainIndexingCursor" - ] - }, - { - "type": "object", - "properties": { - "omnichainStatus": { - "type": "string", - "enum": ["omnichain-completed"] - }, - "chains": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-completed"] - }, - "config": { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock", "endBlock"] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock" - ] - } - ] - } - }, - "omnichainIndexingCursor": { - "type": "integer" - } - }, - "required": [ - "omnichainStatus", - "chains", - "omnichainIndexingCursor" - ] - }, - { - "type": "object", - "properties": { - "omnichainStatus": { - "type": "string", - "enum": ["omnichain-following"] - }, - "chains": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-queued"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - } - }, - "required": ["chainStatus", "config"] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-backfill"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "backfillEndBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock", - "backfillEndBlock" - ] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-following"] - }, - "config": { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "latestKnownBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock", - "latestKnownBlock" - ] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-completed"] - }, - "config": { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock", "endBlock"] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { - "type": "integer" - }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock" - ] - } - ] - } - }, - "omnichainIndexingCursor": { - "type": "integer" - } - }, - "required": [ - "omnichainStatus", - "chains", - "omnichainIndexingCursor" - ] - } - ] - } - }, - "required": [ - "strategy", - "slowestChainIndexingCursor", - "snapshotTime", - "omnichainSnapshot" - ] - }, - "projectedAt": { - "type": "integer" - }, - "worstCaseDistance": { - "type": "number" - } - }, - "required": ["snapshot", "projectedAt", "worstCaseDistance"] - } - }, - "required": ["responseCode", "realtimeProjection"], - "additionalProperties": false - } - } - } - }, - "503": { - "description": "Indexing status snapshot unavailable", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - } - }, - "required": ["responseCode"], - "additionalProperties": false - } - } - } - } - } - } - }, - "/v1/ensanalytics/referral-leaderboard": { - "get": { - "operationId": "getReferralLeaderboard_v1", - "tags": ["ENSAwards"], - "summary": "Get Referrer Leaderboard (v1)", - "description": "Returns a paginated page from the referrer leaderboard for a specific edition", - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 1, - "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" - }, - "required": true, - "name": "edition", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "description": "Page number for pagination" - }, - "required": false, - "description": "Page number for pagination", - "name": "page", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "description": "Number of referrers per page" - }, - "required": false, - "description": "Number of referrers per page", - "name": "recordsPerPage", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully retrieved referrer leaderboard page" - }, - "404": { - "description": "Unknown edition slug" - }, - "500": { - "description": "Internal server error" - }, - "503": { - "description": "Service unavailable" - } - } - } - }, - "/v1/ensanalytics/referrer/{referrer}": { - "get": { - "operationId": "getReferrerDetail_v1", - "tags": ["ENSAwards"], - "summary": "Get Referrer Detail for Editions (v1)", - "description": "Returns detailed information for a specific referrer for the requested editions. Requires 1-20 distinct edition slugs. All requested editions must be recognized and have cached data, or the request fails.", - "parameters": [ - { - "schema": { - "type": "string", - "description": "Referrer Ethereum address" - }, - "required": true, - "description": "Referrer Ethereum address", - "name": "referrer", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of edition slugs" - }, - "required": true, - "description": "Comma-separated list of edition slugs", - "name": "editions", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully retrieved referrer detail for requested editions" - }, - "400": { - "description": "Invalid request" - }, - "404": { - "description": "Unknown edition slug" - }, - "500": { - "description": "Internal server error" - }, - "503": { - "description": "Service unavailable" - } - } - } - }, - "/v1/ensanalytics/editions": { - "get": { - "operationId": "getEditions_v1", - "tags": ["ENSAwards"], - "summary": "Get Edition Config Set (v1)", - "description": "Returns the currently configured referral program edition config set. Editions are sorted in descending order by start timestamp (most recent first).", - "responses": { - "200": { - "description": "Successfully retrieved edition config set" - }, - "500": { - "description": "Internal server error" - }, - "503": { - "description": "Service unavailable" - } - } - } - }, - "/ensanalytics/referrers": { - "get": { - "operationId": "getReferrerLeaderboard", - "tags": ["ENSAwards"], - "summary": "Get Referrer Leaderboard", - "description": "Returns a paginated page from the referrer leaderboard", - "parameters": [ - { - "schema": { - "type": "integer", - "minimum": 1, - "description": "Page number for pagination" - }, - "required": false, - "description": "Page number for pagination", - "name": "page", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "description": "Number of referrers per page" - }, - "required": false, - "description": "Number of referrers per page", - "name": "recordsPerPage", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully retrieved referrer leaderboard page" - }, - "500": { - "description": "Internal server error" - } - } - } - }, - "/ensanalytics/referrers/{referrer}": { - "get": { - "operationId": "getReferrerDetail", - "tags": ["ENSAwards"], - "summary": "Get Referrer Detail", - "description": "Returns detailed information for a specific referrer by address", - "parameters": [ - { - "schema": { - "type": "string", - "description": "Referrer Ethereum address" - }, - "required": true, - "description": "Referrer Ethereum address", - "name": "referrer", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Successfully retrieved referrer detail" - }, - "500": { - "description": "Internal server error" - }, - "503": { - "description": "Service unavailable - referrer leaderboard data not yet cached" - } - } - } - }, - "/api/name-tokens": { - "get": { - "operationId": "getNameTokens", - "tags": ["Explore"], - "summary": "Get Name Tokens", - "description": "Returns name tokens for the requested identifier (domainId or name)", - "parameters": [ - { - "schema": { - "type": "string", - "description": "Domain node hash identifier" - }, - "required": false, - "description": "Domain node hash identifier", - "name": "domainId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "ENS name to look up tokens for" - }, - "required": false, - "description": "ENS name to look up tokens for", - "name": "name", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Name tokens known", - "content": { - "application/json": { - "schema": { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["ok"] - }, - "registeredNameTokens": { - "type": "object", - "properties": { - "domainId": { - "type": "string" - }, - "name": { - "type": "string" - }, - "tokens": { - "type": "array", - "items": { - "type": "object", - "properties": { - "token": { - "type": "object", - "properties": { - "assetNamespace": { - "type": "string", - "enum": ["erc721", "erc1155"] - }, - "contract": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - }, - "tokenId": { - "type": "string" - } - }, - "required": ["assetNamespace", "contract", "tokenId"] - }, - "ownership": { - "oneOf": [ - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["namewrapper"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["fully-onchain"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["burned"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["unknown"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - } - ] - }, - "mintStatus": { - "type": "string", - "enum": ["minted", "burned"] - } - }, - "required": ["token", "ownership", "mintStatus"] - }, - "minItems": 1 - }, - "expiresAt": { - "type": "integer" - }, - "accurateAsOf": { - "type": "integer" - } - }, - "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] - } - }, - "required": ["responseCode", "registeredNameTokens"], - "additionalProperties": false - }, - { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - }, - "errorCode": { - "type": "string", - "enum": ["name-tokens-not-indexed"] - }, - "error": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - }, - "errorCode": { - "type": "string", - "enum": ["unsupported-ensindexer-config"] - }, - "error": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - }, - "errorCode": { - "type": "string", - "enum": ["unsupported-indexing-status"] - }, - "error": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - } - ] - } - ] - } - } - } - }, - "400": { - "description": "Invalid input", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - } - } - }, - "404": { - "description": "Name tokens not indexed", - "content": { - "application/json": { - "schema": { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["ok"] - }, - "registeredNameTokens": { - "type": "object", - "properties": { - "domainId": { - "type": "string" - }, - "name": { - "type": "string" - }, - "tokens": { - "type": "array", - "items": { - "type": "object", - "properties": { - "token": { - "type": "object", - "properties": { - "assetNamespace": { - "type": "string", - "enum": ["erc721", "erc1155"] - }, - "contract": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - }, - "tokenId": { - "type": "string" - } - }, - "required": ["assetNamespace", "contract", "tokenId"] - }, - "ownership": { - "oneOf": [ - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["namewrapper"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["fully-onchain"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["burned"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["unknown"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - } - ] - }, - "mintStatus": { - "type": "string", - "enum": ["minted", "burned"] - } - }, - "required": ["token", "ownership", "mintStatus"] - }, - "minItems": 1 - }, - "expiresAt": { - "type": "integer" - }, - "accurateAsOf": { - "type": "integer" - } - }, - "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] - } - }, - "required": ["responseCode", "registeredNameTokens"], - "additionalProperties": false - }, - { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - }, - "errorCode": { - "type": "string", - "enum": ["name-tokens-not-indexed"] - }, - "error": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - }, - "errorCode": { - "type": "string", - "enum": ["unsupported-ensindexer-config"] - }, - "error": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - }, - "errorCode": { - "type": "string", - "enum": ["unsupported-indexing-status"] - }, - "error": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - } - ] - } - ] - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - } - } - }, - "503": { - "description": "Service unavailable - Name Tokens API prerequisites not met (indexing status not ready or required plugins not activated)", - "content": { - "application/json": { - "schema": { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["ok"] - }, - "registeredNameTokens": { - "type": "object", - "properties": { - "domainId": { - "type": "string" - }, - "name": { - "type": "string" - }, - "tokens": { - "type": "array", - "items": { - "type": "object", - "properties": { - "token": { - "type": "object", - "properties": { - "assetNamespace": { - "type": "string", - "enum": ["erc721", "erc1155"] - }, - "contract": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - }, - "tokenId": { - "type": "string" - } - }, - "required": ["assetNamespace", "contract", "tokenId"] - }, - "ownership": { - "oneOf": [ - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["namewrapper"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["fully-onchain"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["burned"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["unknown"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { - "type": "string" - } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - } - ] - }, - "mintStatus": { - "type": "string", - "enum": ["minted", "burned"] - } - }, - "required": ["token", "ownership", "mintStatus"] - }, - "minItems": 1 - }, - "expiresAt": { - "type": "integer" - }, - "accurateAsOf": { - "type": "integer" - } - }, - "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] - } - }, - "required": ["responseCode", "registeredNameTokens"], - "additionalProperties": false - }, - { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - }, - "errorCode": { - "type": "string", - "enum": ["name-tokens-not-indexed"] - }, - "error": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - }, - "errorCode": { - "type": "string", - "enum": ["unsupported-ensindexer-config"] - }, - "error": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { - "type": "string", - "enum": ["error"] - }, - "errorCode": { - "type": "string", - "enum": ["unsupported-indexing-status"] - }, - "error": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "details": {} - }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - } - ] - } - ] - } - } - } - } - } - } - }, - "/api/registrar-actions": { - "get": { - "operationId": "getRegistrarActions", - "tags": ["Explore"], - "summary": "Get Registrar Actions", - "description": "Returns all registrar actions with optional filtering and pagination", - "parameters": [ - { - "schema": { - "type": "string", - "enum": ["orderBy[timestamp]=desc"], - "default": "orderBy[timestamp]=desc", - "description": "Order of results" - }, - "required": false, - "description": "Order of results", - "name": "orderBy", - "in": "query" - }, - { - "schema": { - "description": "Page number for pagination" - }, - "required": false, - "description": "Page number for pagination", - "name": "page", - "in": "query" - }, - { - "schema": { - "description": "Number of records per page" - }, - "required": false, - "description": "Number of records per page", - "name": "recordsPerPage", - "in": "query" - }, - { - "schema": { - "type": "string", - "default": false, - "description": "Filter to only include actions with referrals" - }, - "required": false, - "description": "Filter to only include actions with referrals", - "name": "withReferral", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by decoded referrer address" - }, - "required": false, - "description": "Filter by decoded referrer address", - "name": "decodedReferrer", - "in": "query" - }, - { - "schema": { - "description": "Filter actions at or after this Unix timestamp" - }, - "required": false, - "description": "Filter actions at or after this Unix timestamp", - "name": "beginTimestamp", - "in": "query" - }, - { - "schema": { - "description": "Filter actions at or before this Unix timestamp" - }, - "required": false, - "description": "Filter actions at or before this Unix timestamp", - "name": "endTimestamp", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully retrieved registrar actions" - }, - "400": { - "description": "Invalid query" - }, - "500": { - "description": "Internal server error" - } - } - } - }, - "/api/registrar-actions/{parentNode}": { - "get": { - "operationId": "getRegistrarActionsByParentNode", - "tags": ["Explore"], - "summary": "Get Registrar Actions by Parent Node", - "description": "Returns registrar actions filtered by parent node hash with optional additional filtering and pagination", - "parameters": [ - { - "schema": { - "type": "string", - "description": "Parent node to filter registrar actions" - }, - "required": true, - "description": "Parent node to filter registrar actions", - "name": "parentNode", - "in": "path" - }, - { - "schema": { - "type": "string", - "enum": ["orderBy[timestamp]=desc"], - "default": "orderBy[timestamp]=desc", - "description": "Order of results" - }, - "required": false, - "description": "Order of results", - "name": "orderBy", - "in": "query" - }, - { - "schema": { - "description": "Page number for pagination" - }, - "required": false, - "description": "Page number for pagination", - "name": "page", - "in": "query" - }, - { - "schema": { - "description": "Number of records per page" - }, - "required": false, - "description": "Number of records per page", - "name": "recordsPerPage", - "in": "query" - }, - { - "schema": { - "type": "string", - "default": false, - "description": "Filter to only include actions with referrals" - }, - "required": false, - "description": "Filter to only include actions with referrals", - "name": "withReferral", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by decoded referrer address" - }, - "required": false, - "description": "Filter by decoded referrer address", - "name": "decodedReferrer", - "in": "query" - }, - { - "schema": { - "description": "Filter actions at or after this Unix timestamp" - }, - "required": false, - "description": "Filter actions at or after this Unix timestamp", - "name": "beginTimestamp", - "in": "query" - }, - { - "schema": { - "description": "Filter actions at or before this Unix timestamp" - }, - "required": false, - "description": "Filter actions at or before this Unix timestamp", - "name": "endTimestamp", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully retrieved registrar actions" - }, - "400": { - "description": "Invalid input" - }, - "500": { - "description": "Internal server error" - } - } - } - }, - "/api/resolve/records/{name}": { - "get": { - "operationId": "resolveRecords", - "tags": ["Resolution"], - "summary": "Resolve ENS Records", - "description": "Resolves ENS records for a given name", - "parameters": [ - { - "schema": { - "type": "string" - }, - "required": true, - "name": "name", - "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": false, - "name": "name", - "in": "query" - }, - { - "schema": { - "type": "string" - }, - "required": false, - "name": "addresses", - "in": "query" - }, - { - "schema": { - "type": "string" - }, - "required": false, - "name": "texts", - "in": "query" - }, - { - "schema": { - "type": "string", - "default": false - }, - "required": false, - "name": "trace", - "in": "query" - }, - { - "schema": { - "type": "string", - "default": false - }, - "required": false, - "name": "accelerate", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully resolved records", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "records": { - "type": "object", - "properties": { - "name": { - "type": ["string", "null"] - }, - "addresses": { - "type": "object", - "additionalProperties": { - "type": ["string", "null"] - } - }, - "texts": { - "type": "object", - "additionalProperties": { - "type": ["string", "null"] - } - } - } - }, - "accelerationRequested": { - "type": "boolean" - }, - "accelerationAttempted": { - "type": "boolean" - }, - "trace": { - "type": "array", - "items": {} - } - }, - "required": ["records", "accelerationRequested", "accelerationAttempted"] - } - } - } - } - } - } - }, - "/api/resolve/primary-name/{address}/{chainId}": { - "get": { - "operationId": "resolvePrimaryName", - "tags": ["Resolution"], - "summary": "Resolve Primary Name", - "description": "Resolves a primary name for a given `address` and `chainId`", - "parameters": [ - { - "schema": { - "type": "string" - }, - "required": true, - "name": "address", - "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": true, - "name": "chainId", - "in": "path" - }, - { - "schema": { - "type": "string", - "default": false - }, - "required": false, - "name": "trace", - "in": "query" - }, - { - "schema": { - "type": "string", - "default": false - }, - "required": false, - "name": "accelerate", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully resolved name", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": ["string", "null"] - }, - "accelerationRequested": { - "type": "boolean" - }, - "accelerationAttempted": { - "type": "boolean" - }, - "trace": { - "type": "array", - "items": {} - } - }, - "required": ["name", "accelerationRequested", "accelerationAttempted"] - } - } - } - } - } - } - }, - "/api/resolve/primary-names/{address}": { - "get": { - "operationId": "resolvePrimaryNames", - "tags": ["Resolution"], - "summary": "Resolve Primary Names", - "description": "Resolves all primary names for a given address across multiple chains", - "parameters": [ - { - "schema": { - "type": "string" - }, - "required": true, - "name": "address", - "in": "path" - }, - { - "schema": { - "type": "string" - }, - "required": false, - "name": "chainIds", - "in": "query" - }, - { - "schema": { - "type": "string", - "default": false - }, - "required": false, - "name": "trace", - "in": "query" - }, - { - "schema": { - "type": "string", - "default": false - }, - "required": false, - "name": "accelerate", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully resolved records", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "names": { - "type": "object", - "additionalProperties": { - "type": ["string", "null"] - } - }, - "accelerationRequested": { - "type": "boolean" - }, - "accelerationAttempted": { - "type": "boolean" - }, - "trace": { - "type": "array", - "items": {} - } - }, - "required": ["names", "accelerationRequested", "accelerationAttempted"] - } - } - } - } - } - } - } - }, - "webhooks": {} -} diff --git a/openapi/ensapi-openapi.json b/openapi/ensapi-openapi.json new file mode 120000 index 000000000..e6f03df02 --- /dev/null +++ b/openapi/ensapi-openapi.json @@ -0,0 +1 @@ +../docs/docs.ensnode.io/ensapi-openapi.json \ No newline at end of file From 64a70ad587fcf0d4a8807e34454835478333f9fc Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 12:34:47 +0000 Subject: [PATCH 06/21] update readme --- docs/docs.ensnode.io/README.md | 26 ++++++-------------------- package.json | 2 +- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/docs/docs.ensnode.io/README.md b/docs/docs.ensnode.io/README.md index de8f99ab7..8ac284af3 100644 --- a/docs/docs.ensnode.io/README.md +++ b/docs/docs.ensnode.io/README.md @@ -2,28 +2,13 @@ [docs.ensnode.io](https://docs.ensnode.io) runs on [Mintlify](https://mintlify.com). -## Local Development - -### Getting Started - -1. Clone the repository: - - ```bash - git clone https://github.com/namehash/ensnode.git - ``` +Learn more about [ENSNode](https://ensnode.io) from [the "Starlight" ENSNode docs](https://ensnode.io/docs/). Everything from these "Starlight" docs is planned to be transitioned into these Mintlify docs soon. -2. Navigate to the docs directory: - - ```bash - cd ensnode/docs/docs.ensnode.io - ``` - -3. Start the local development server: - - ```bash - pnpm mint dev - ``` +## Local Development +1. `git clone https://github.com/namehash/ensnode.git` +2. `cd docs/docs.ensnode.io` +3. `pnpm mint dev` 4. Open [http://localhost:3000](http://localhost:3000) in your browser ### Troubleshooting @@ -38,3 +23,4 @@ Changes pushed to the main branch are automatically deployed to production. ## Resources - [Mintlify documentation](https://mintlify.com/docs) +- [ENSNode "Starlight" docs](https://ensnode.io/docs/) diff --git a/package.json b/package.json index 6923a4bc8..37a12e583 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "ensnode-monorepo", "version": "0.0.1", "private": true, - "packageManager": "pnpm@10.30.3", + "packageManager": "pnpm@10.28.0", "scripts": { "lint": "biome check --write .", "lint:ci": "biome ci", From 2913a3ae34af3ab4ba290334e9a31f930fb06803 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 12:51:53 +0000 Subject: [PATCH 07/21] clean up implementation to remove docs --- apps/ensapi/package.json | 3 +- docs/docs.ensnode.io/ensapi-openapi.json | 2052 ----------------- docs/docs.ensnode.io/ensapi/preview.mdx | 9 - openapi/ensapi-openapi.json | 1 - package.json | 4 +- .../generate-ensapi-openapi.ts | 14 +- 6 files changed, 6 insertions(+), 2077 deletions(-) delete mode 100644 docs/docs.ensnode.io/ensapi-openapi.json delete mode 100644 docs/docs.ensnode.io/ensapi/preview.mdx delete mode 120000 openapi/ensapi-openapi.json rename apps/ensapi/scripts/generate-openapi.ts => scripts/generate-ensapi-openapi.ts (87%) diff --git a/apps/ensapi/package.json b/apps/ensapi/package.json index 028a27ba1..8aefb096f 100644 --- a/apps/ensapi/package.json +++ b/apps/ensapi/package.json @@ -18,8 +18,7 @@ "test:integration": "vitest run --config vitest.integration.config.ts", "lint": "biome check --write .", "lint:ci": "biome ci", - "typecheck": "tsgo --noEmit", - "generate:openapi": "tsx scripts/generate-openapi.ts" + "typecheck": "tsgo --noEmit" }, "dependencies": { "@ensdomains/ensjs": "^4.0.2", diff --git a/docs/docs.ensnode.io/ensapi-openapi.json b/docs/docs.ensnode.io/ensapi-openapi.json deleted file mode 100644 index b6f97802d..000000000 --- a/docs/docs.ensnode.io/ensapi-openapi.json +++ /dev/null @@ -1,2052 +0,0 @@ -{ - "openapi": "3.1.0", - "info": { - "title": "ENSApi APIs", - "version": "1.5.1", - "description": "APIs for ENS resolution, navigating the ENS nameforest, and metadata about an ENSNode" - }, - "servers": [ - { "url": "https://api.alpha.ensnode.io", "description": "ENSNode Alpha (Mainnet)" }, - { - "url": "https://api.alpha-sepolia.ensnode.io", - "description": "ENSNode Alpha (Sepolia Testnet)" - } - ], - "tags": [ - { "name": "Resolution", "description": "APIs for resolving ENS names and addresses" }, - { - "name": "Meta", - "description": "APIs for indexing status, configuration, and realtime monitoring" - }, - { - "name": "Explore", - "description": "APIs for exploring the indexed state of ENS, including name tokens and registrar actions" - }, - { - "name": "ENSAwards", - "description": "APIs for ENSAwards functionality, including referrer data" - } - ], - "components": { "schemas": {}, "parameters": {} }, - "paths": { - "/amirealtime": { - "get": { - "operationId": "isRealtime", - "tags": ["Meta"], - "summary": "Check indexing progress", - "description": "Checks if the indexing progress is guaranteed to be within a requested worst-case distance of realtime", - "parameters": [ - { - "schema": { - "description": "Maximum acceptable worst-case indexing distance in seconds" - }, - "required": false, - "description": "Maximum acceptable worst-case indexing distance in seconds", - "name": "maxWorstCaseDistance", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Indexing progress is guaranteed to be within the requested distance of realtime" - }, - "503": { - "description": "Indexing progress is not guaranteed to be within the requested distance of realtime or indexing status unavailable" - } - } - } - }, - "/api/config": { - "get": { - "operationId": "getConfig", - "tags": ["Meta"], - "summary": "Get ENSApi Public Config", - "description": "Gets the public config of the ENSApi instance", - "responses": { - "200": { - "description": "Successfully retrieved ENSApi public config", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "version": { "type": "string", "minLength": 1 }, - "theGraphFallback": { - "oneOf": [ - { - "type": "object", - "properties": { - "canFallback": { "type": "boolean", "enum": [true] }, - "url": { "type": "string" } - }, - "required": ["canFallback", "url"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "canFallback": { "type": "boolean", "enum": [false] }, - "reason": { - "type": "string", - "enum": ["not-subgraph-compatible", "no-api-key", "no-subgraph-url"] - } - }, - "required": ["canFallback", "reason"], - "additionalProperties": false - } - ] - }, - "ensIndexerPublicConfig": { - "type": "object", - "properties": { - "labelSet": { - "type": "object", - "properties": { - "labelSetId": { - "type": "string", - "minLength": 1, - "maxLength": 50, - "pattern": "^[a-z-]+$" - }, - "labelSetVersion": { "type": ["number", "null"] } - }, - "required": ["labelSetId", "labelSetVersion"] - }, - "indexedChainIds": { - "type": "array", - "items": { "type": "integer", "exclusiveMinimum": 0 }, - "minItems": 1 - }, - "isSubgraphCompatible": { "type": "boolean" }, - "namespace": { - "type": "string", - "enum": ["mainnet", "sepolia", "sepolia-v2", "ens-test-env"] - }, - "plugins": { - "type": "array", - "items": { "type": "string" }, - "minItems": 1 - }, - "databaseSchemaName": { "type": "string", "minLength": 1 }, - "versionInfo": { - "type": "object", - "properties": { - "nodejs": { "type": "string", "minLength": 1 }, - "ponder": { "type": "string", "minLength": 1 }, - "ensDb": { "type": "string", "minLength": 1 }, - "ensIndexer": { "type": "string", "minLength": 1 }, - "ensNormalize": { "type": "string", "minLength": 1 }, - "ensRainbow": { "type": "string", "minLength": 1 }, - "ensRainbowSchema": { "type": "integer", "exclusiveMinimum": 0 } - }, - "required": [ - "nodejs", - "ponder", - "ensDb", - "ensIndexer", - "ensNormalize", - "ensRainbow", - "ensRainbowSchema" - ], - "additionalProperties": false - } - }, - "required": [ - "labelSet", - "indexedChainIds", - "isSubgraphCompatible", - "namespace", - "plugins", - "databaseSchemaName", - "versionInfo" - ] - } - }, - "required": ["version", "theGraphFallback", "ensIndexerPublicConfig"] - } - } - } - } - } - } - }, - "/api/indexing-status": { - "get": { - "operationId": "getIndexingStatus", - "tags": ["Meta"], - "summary": "Get ENSIndexer Indexing Status", - "description": "Returns the indexing status snapshot most recently captured from ENSIndexer", - "responses": { - "200": { - "description": "Successfully retrieved indexing status", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["ok"] }, - "realtimeProjection": { - "type": "object", - "properties": { - "snapshot": { - "type": "object", - "properties": { - "strategy": { "type": "string", "enum": ["omnichain"] }, - "slowestChainIndexingCursor": { "type": "integer" }, - "snapshotTime": { "type": "integer" }, - "omnichainSnapshot": { - "oneOf": [ - { - "type": "object", - "properties": { - "omnichainStatus": { - "type": "string", - "enum": ["omnichain-unstarted"] - }, - "chains": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-queued"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - } - }, - "required": ["chainStatus", "config"] - } - ] - } - }, - "omnichainIndexingCursor": { "type": "integer" } - }, - "required": [ - "omnichainStatus", - "chains", - "omnichainIndexingCursor" - ] - }, - { - "type": "object", - "properties": { - "omnichainStatus": { - "type": "string", - "enum": ["omnichain-backfill"] - }, - "chains": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-queued"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - } - }, - "required": ["chainStatus", "config"] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-backfill"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "backfillEndBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock", - "backfillEndBlock" - ] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-completed"] - }, - "config": { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock", "endBlock"] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock" - ] - } - ] - } - }, - "omnichainIndexingCursor": { "type": "integer" } - }, - "required": [ - "omnichainStatus", - "chains", - "omnichainIndexingCursor" - ] - }, - { - "type": "object", - "properties": { - "omnichainStatus": { - "type": "string", - "enum": ["omnichain-completed"] - }, - "chains": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-completed"] - }, - "config": { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock", "endBlock"] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock" - ] - } - ] - } - }, - "omnichainIndexingCursor": { "type": "integer" } - }, - "required": [ - "omnichainStatus", - "chains", - "omnichainIndexingCursor" - ] - }, - { - "type": "object", - "properties": { - "omnichainStatus": { - "type": "string", - "enum": ["omnichain-following"] - }, - "chains": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-queued"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - } - }, - "required": ["chainStatus", "config"] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-backfill"] - }, - "config": { - "oneOf": [ - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { - "type": "integer", - "minimum": 0 - } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "rangeType", - "startBlock", - "endBlock" - ] - } - ] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "backfillEndBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock", - "backfillEndBlock" - ] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-following"] - }, - "config": { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["left-bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock"] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "latestKnownBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock", - "latestKnownBlock" - ] - }, - { - "type": "object", - "properties": { - "chainStatus": { - "type": "string", - "enum": ["chain-completed"] - }, - "config": { - "type": "object", - "properties": { - "rangeType": { - "type": "string", - "enum": ["bounded"] - }, - "startBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - }, - "endBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": ["rangeType", "startBlock", "endBlock"] - }, - "latestIndexedBlock": { - "type": "object", - "properties": { - "timestamp": { "type": "integer" }, - "number": { "type": "integer", "minimum": 0 } - }, - "required": ["timestamp", "number"], - "additionalProperties": false - } - }, - "required": [ - "chainStatus", - "config", - "latestIndexedBlock" - ] - } - ] - } - }, - "omnichainIndexingCursor": { "type": "integer" } - }, - "required": [ - "omnichainStatus", - "chains", - "omnichainIndexingCursor" - ] - } - ] - } - }, - "required": [ - "strategy", - "slowestChainIndexingCursor", - "snapshotTime", - "omnichainSnapshot" - ] - }, - "projectedAt": { "type": "integer" }, - "worstCaseDistance": { "type": "number" } - }, - "required": ["snapshot", "projectedAt", "worstCaseDistance"] - } - }, - "required": ["responseCode", "realtimeProjection"], - "additionalProperties": false - } - } - } - }, - "503": { - "description": "Indexing status snapshot unavailable", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "responseCode": { "type": "string", "enum": ["error"] } }, - "required": ["responseCode"], - "additionalProperties": false - } - } - } - } - } - } - }, - "/v1/ensanalytics/referral-leaderboard": { - "get": { - "operationId": "getReferralLeaderboard_v1", - "tags": ["ENSAwards"], - "summary": "Get Referrer Leaderboard (v1)", - "description": "Returns a paginated page from the referrer leaderboard for a specific edition", - "parameters": [ - { - "schema": { "type": "string", "minLength": 1, "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" }, - "required": true, - "name": "edition", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "description": "Page number for pagination" - }, - "required": false, - "description": "Page number for pagination", - "name": "page", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "description": "Number of referrers per page" - }, - "required": false, - "description": "Number of referrers per page", - "name": "recordsPerPage", - "in": "query" - } - ], - "responses": { - "200": { "description": "Successfully retrieved referrer leaderboard page" }, - "404": { "description": "Unknown edition slug" }, - "500": { "description": "Internal server error" }, - "503": { "description": "Service unavailable" } - } - } - }, - "/v1/ensanalytics/referrer/{referrer}": { - "get": { - "operationId": "getReferrerDetail_v1", - "tags": ["ENSAwards"], - "summary": "Get Referrer Detail for Editions (v1)", - "description": "Returns detailed information for a specific referrer for the requested editions. Requires 1-20 distinct edition slugs. All requested editions must be recognized and have cached data, or the request fails.", - "parameters": [ - { - "schema": { "type": "string", "description": "Referrer Ethereum address" }, - "required": true, - "description": "Referrer Ethereum address", - "name": "referrer", - "in": "path" - }, - { - "schema": { "type": "string", "description": "Comma-separated list of edition slugs" }, - "required": true, - "description": "Comma-separated list of edition slugs", - "name": "editions", - "in": "query" - } - ], - "responses": { - "200": { "description": "Successfully retrieved referrer detail for requested editions" }, - "400": { "description": "Invalid request" }, - "404": { "description": "Unknown edition slug" }, - "500": { "description": "Internal server error" }, - "503": { "description": "Service unavailable" } - } - } - }, - "/v1/ensanalytics/editions": { - "get": { - "operationId": "getEditions_v1", - "tags": ["ENSAwards"], - "summary": "Get Edition Config Set (v1)", - "description": "Returns the currently configured referral program edition config set. Editions are sorted in descending order by start timestamp (most recent first).", - "responses": { - "200": { "description": "Successfully retrieved edition config set" }, - "500": { "description": "Internal server error" }, - "503": { "description": "Service unavailable" } - } - } - }, - "/ensanalytics/referrers": { - "get": { - "operationId": "getReferrerLeaderboard", - "tags": ["ENSAwards"], - "summary": "Get Referrer Leaderboard", - "description": "Returns a paginated page from the referrer leaderboard", - "parameters": [ - { - "schema": { - "type": "integer", - "minimum": 1, - "description": "Page number for pagination" - }, - "required": false, - "description": "Page number for pagination", - "name": "page", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "description": "Number of referrers per page" - }, - "required": false, - "description": "Number of referrers per page", - "name": "recordsPerPage", - "in": "query" - } - ], - "responses": { - "200": { "description": "Successfully retrieved referrer leaderboard page" }, - "500": { "description": "Internal server error" } - } - } - }, - "/ensanalytics/referrers/{referrer}": { - "get": { - "operationId": "getReferrerDetail", - "tags": ["ENSAwards"], - "summary": "Get Referrer Detail", - "description": "Returns detailed information for a specific referrer by address", - "parameters": [ - { - "schema": { "type": "string", "description": "Referrer Ethereum address" }, - "required": true, - "description": "Referrer Ethereum address", - "name": "referrer", - "in": "path" - } - ], - "responses": { - "200": { "description": "Successfully retrieved referrer detail" }, - "500": { "description": "Internal server error" }, - "503": { "description": "Service unavailable - referrer leaderboard data not yet cached" } - } - } - }, - "/api/name-tokens": { - "get": { - "operationId": "getNameTokens", - "tags": ["Explore"], - "summary": "Get Name Tokens", - "description": "Returns name tokens for the requested identifier (domainId or name)", - "parameters": [ - { - "schema": { "type": "string", "description": "Domain node hash identifier" }, - "required": false, - "description": "Domain node hash identifier", - "name": "domainId", - "in": "query" - }, - { - "schema": { "type": "string", "description": "ENS name to look up tokens for" }, - "required": false, - "description": "ENS name to look up tokens for", - "name": "name", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Name tokens known", - "content": { - "application/json": { - "schema": { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["ok"] }, - "registeredNameTokens": { - "type": "object", - "properties": { - "domainId": { "type": "string" }, - "name": { "type": "string" }, - "tokens": { - "type": "array", - "items": { - "type": "object", - "properties": { - "token": { - "type": "object", - "properties": { - "assetNamespace": { - "type": "string", - "enum": ["erc721", "erc1155"] - }, - "contract": { - "type": "object", - "properties": { - "chainId": { "type": "integer", "exclusiveMinimum": 0 }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - }, - "tokenId": { "type": "string" } - }, - "required": ["assetNamespace", "contract", "tokenId"] - }, - "ownership": { - "oneOf": [ - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["namewrapper"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["fully-onchain"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { "type": "string", "enum": ["burned"] }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["unknown"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - } - ] - }, - "mintStatus": { "type": "string", "enum": ["minted", "burned"] } - }, - "required": ["token", "ownership", "mintStatus"] - }, - "minItems": 1 - }, - "expiresAt": { "type": "integer" }, - "accurateAsOf": { "type": "integer" } - }, - "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] - } - }, - "required": ["responseCode", "registeredNameTokens"], - "additionalProperties": false - }, - { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["error"] }, - "errorCode": { "type": "string", "enum": ["name-tokens-not-indexed"] }, - "error": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["error"] }, - "errorCode": { - "type": "string", - "enum": ["unsupported-ensindexer-config"] - }, - "error": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["error"] }, - "errorCode": { - "type": "string", - "enum": ["unsupported-indexing-status"] - }, - "error": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - } - ] - } - ] - } - } - } - }, - "400": { - "description": "Invalid input", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - } - } - }, - "404": { - "description": "Name tokens not indexed", - "content": { - "application/json": { - "schema": { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["ok"] }, - "registeredNameTokens": { - "type": "object", - "properties": { - "domainId": { "type": "string" }, - "name": { "type": "string" }, - "tokens": { - "type": "array", - "items": { - "type": "object", - "properties": { - "token": { - "type": "object", - "properties": { - "assetNamespace": { - "type": "string", - "enum": ["erc721", "erc1155"] - }, - "contract": { - "type": "object", - "properties": { - "chainId": { "type": "integer", "exclusiveMinimum": 0 }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - }, - "tokenId": { "type": "string" } - }, - "required": ["assetNamespace", "contract", "tokenId"] - }, - "ownership": { - "oneOf": [ - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["namewrapper"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["fully-onchain"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { "type": "string", "enum": ["burned"] }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["unknown"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - } - ] - }, - "mintStatus": { "type": "string", "enum": ["minted", "burned"] } - }, - "required": ["token", "ownership", "mintStatus"] - }, - "minItems": 1 - }, - "expiresAt": { "type": "integer" }, - "accurateAsOf": { "type": "integer" } - }, - "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] - } - }, - "required": ["responseCode", "registeredNameTokens"], - "additionalProperties": false - }, - { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["error"] }, - "errorCode": { "type": "string", "enum": ["name-tokens-not-indexed"] }, - "error": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["error"] }, - "errorCode": { - "type": "string", - "enum": ["unsupported-ensindexer-config"] - }, - "error": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["error"] }, - "errorCode": { - "type": "string", - "enum": ["unsupported-indexing-status"] - }, - "error": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - } - ] - } - ] - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - } - } - }, - "503": { - "description": "Service unavailable - Name Tokens API prerequisites not met (indexing status not ready or required plugins not activated)", - "content": { - "application/json": { - "schema": { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["ok"] }, - "registeredNameTokens": { - "type": "object", - "properties": { - "domainId": { "type": "string" }, - "name": { "type": "string" }, - "tokens": { - "type": "array", - "items": { - "type": "object", - "properties": { - "token": { - "type": "object", - "properties": { - "assetNamespace": { - "type": "string", - "enum": ["erc721", "erc1155"] - }, - "contract": { - "type": "object", - "properties": { - "chainId": { "type": "integer", "exclusiveMinimum": 0 }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - }, - "tokenId": { "type": "string" } - }, - "required": ["assetNamespace", "contract", "tokenId"] - }, - "ownership": { - "oneOf": [ - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["namewrapper"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["fully-onchain"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { "type": "string", "enum": ["burned"] }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - }, - { - "type": "object", - "properties": { - "ownershipType": { - "type": "string", - "enum": ["unknown"] - }, - "owner": { - "type": "object", - "properties": { - "chainId": { - "type": "integer", - "exclusiveMinimum": 0 - }, - "address": { "type": "string" } - }, - "required": ["chainId", "address"], - "additionalProperties": false - } - }, - "required": ["ownershipType", "owner"] - } - ] - }, - "mintStatus": { "type": "string", "enum": ["minted", "burned"] } - }, - "required": ["token", "ownership", "mintStatus"] - }, - "minItems": 1 - }, - "expiresAt": { "type": "integer" }, - "accurateAsOf": { "type": "integer" } - }, - "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] - } - }, - "required": ["responseCode", "registeredNameTokens"], - "additionalProperties": false - }, - { - "oneOf": [ - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["error"] }, - "errorCode": { "type": "string", "enum": ["name-tokens-not-indexed"] }, - "error": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["error"] }, - "errorCode": { - "type": "string", - "enum": ["unsupported-ensindexer-config"] - }, - "error": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "responseCode": { "type": "string", "enum": ["error"] }, - "errorCode": { - "type": "string", - "enum": ["unsupported-indexing-status"] - }, - "error": { - "type": "object", - "properties": { "message": { "type": "string" }, "details": {} }, - "required": ["message"] - } - }, - "required": ["responseCode", "errorCode", "error"], - "additionalProperties": false - } - ] - } - ] - } - } - } - } - } - } - }, - "/api/registrar-actions": { - "get": { - "operationId": "getRegistrarActions", - "tags": ["Explore"], - "summary": "Get Registrar Actions", - "description": "Returns all registrar actions with optional filtering and pagination", - "parameters": [ - { - "schema": { - "type": "string", - "enum": ["orderBy[timestamp]=desc"], - "default": "orderBy[timestamp]=desc", - "description": "Order of results" - }, - "required": false, - "description": "Order of results", - "name": "orderBy", - "in": "query" - }, - { - "schema": { "description": "Page number for pagination" }, - "required": false, - "description": "Page number for pagination", - "name": "page", - "in": "query" - }, - { - "schema": { "description": "Number of records per page" }, - "required": false, - "description": "Number of records per page", - "name": "recordsPerPage", - "in": "query" - }, - { - "schema": { - "type": "string", - "default": false, - "description": "Filter to only include actions with referrals" - }, - "required": false, - "description": "Filter to only include actions with referrals", - "name": "withReferral", - "in": "query" - }, - { - "schema": { "type": "string", "description": "Filter by decoded referrer address" }, - "required": false, - "description": "Filter by decoded referrer address", - "name": "decodedReferrer", - "in": "query" - }, - { - "schema": { "description": "Filter actions at or after this Unix timestamp" }, - "required": false, - "description": "Filter actions at or after this Unix timestamp", - "name": "beginTimestamp", - "in": "query" - }, - { - "schema": { "description": "Filter actions at or before this Unix timestamp" }, - "required": false, - "description": "Filter actions at or before this Unix timestamp", - "name": "endTimestamp", - "in": "query" - } - ], - "responses": { - "200": { "description": "Successfully retrieved registrar actions" }, - "400": { "description": "Invalid query" }, - "500": { "description": "Internal server error" } - } - } - }, - "/api/registrar-actions/{parentNode}": { - "get": { - "operationId": "getRegistrarActionsByParentNode", - "tags": ["Explore"], - "summary": "Get Registrar Actions by Parent Node", - "description": "Returns registrar actions filtered by parent node hash with optional additional filtering and pagination", - "parameters": [ - { - "schema": { - "type": "string", - "description": "Parent node to filter registrar actions" - }, - "required": true, - "description": "Parent node to filter registrar actions", - "name": "parentNode", - "in": "path" - }, - { - "schema": { - "type": "string", - "enum": ["orderBy[timestamp]=desc"], - "default": "orderBy[timestamp]=desc", - "description": "Order of results" - }, - "required": false, - "description": "Order of results", - "name": "orderBy", - "in": "query" - }, - { - "schema": { "description": "Page number for pagination" }, - "required": false, - "description": "Page number for pagination", - "name": "page", - "in": "query" - }, - { - "schema": { "description": "Number of records per page" }, - "required": false, - "description": "Number of records per page", - "name": "recordsPerPage", - "in": "query" - }, - { - "schema": { - "type": "string", - "default": false, - "description": "Filter to only include actions with referrals" - }, - "required": false, - "description": "Filter to only include actions with referrals", - "name": "withReferral", - "in": "query" - }, - { - "schema": { "type": "string", "description": "Filter by decoded referrer address" }, - "required": false, - "description": "Filter by decoded referrer address", - "name": "decodedReferrer", - "in": "query" - }, - { - "schema": { "description": "Filter actions at or after this Unix timestamp" }, - "required": false, - "description": "Filter actions at or after this Unix timestamp", - "name": "beginTimestamp", - "in": "query" - }, - { - "schema": { "description": "Filter actions at or before this Unix timestamp" }, - "required": false, - "description": "Filter actions at or before this Unix timestamp", - "name": "endTimestamp", - "in": "query" - } - ], - "responses": { - "200": { "description": "Successfully retrieved registrar actions" }, - "400": { "description": "Invalid input" }, - "500": { "description": "Internal server error" } - } - } - }, - "/api/resolve/records/{name}": { - "get": { - "operationId": "resolveRecords", - "tags": ["Resolution"], - "summary": "Resolve ENS Records", - "description": "Resolves ENS records for a given name", - "parameters": [ - { "schema": { "type": "string" }, "required": true, "name": "name", "in": "path" }, - { "schema": { "type": "string" }, "required": false, "name": "name", "in": "query" }, - { "schema": { "type": "string" }, "required": false, "name": "addresses", "in": "query" }, - { "schema": { "type": "string" }, "required": false, "name": "texts", "in": "query" }, - { - "schema": { "type": "string", "default": false }, - "required": false, - "name": "trace", - "in": "query" - }, - { - "schema": { "type": "string", "default": false }, - "required": false, - "name": "accelerate", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully resolved records", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "records": { - "type": "object", - "properties": { - "name": { "type": ["string", "null"] }, - "addresses": { - "type": "object", - "additionalProperties": { "type": ["string", "null"] } - }, - "texts": { - "type": "object", - "additionalProperties": { "type": ["string", "null"] } - } - } - }, - "accelerationRequested": { "type": "boolean" }, - "accelerationAttempted": { "type": "boolean" }, - "trace": { "type": "array", "items": {} } - }, - "required": ["records", "accelerationRequested", "accelerationAttempted"] - } - } - } - } - } - } - }, - "/api/resolve/primary-name/{address}/{chainId}": { - "get": { - "operationId": "resolvePrimaryName", - "tags": ["Resolution"], - "summary": "Resolve Primary Name", - "description": "Resolves a primary name for a given `address` and `chainId`", - "parameters": [ - { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, - { "schema": { "type": "string" }, "required": true, "name": "chainId", "in": "path" }, - { - "schema": { "type": "string", "default": false }, - "required": false, - "name": "trace", - "in": "query" - }, - { - "schema": { "type": "string", "default": false }, - "required": false, - "name": "accelerate", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully resolved name", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { "type": ["string", "null"] }, - "accelerationRequested": { "type": "boolean" }, - "accelerationAttempted": { "type": "boolean" }, - "trace": { "type": "array", "items": {} } - }, - "required": ["name", "accelerationRequested", "accelerationAttempted"] - } - } - } - } - } - } - }, - "/api/resolve/primary-names/{address}": { - "get": { - "operationId": "resolvePrimaryNames", - "tags": ["Resolution"], - "summary": "Resolve Primary Names", - "description": "Resolves all primary names for a given address across multiple chains", - "parameters": [ - { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, - { "schema": { "type": "string" }, "required": false, "name": "chainIds", "in": "query" }, - { - "schema": { "type": "string", "default": false }, - "required": false, - "name": "trace", - "in": "query" - }, - { - "schema": { "type": "string", "default": false }, - "required": false, - "name": "accelerate", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successfully resolved records", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "names": { - "type": "object", - "additionalProperties": { "type": ["string", "null"] } - }, - "accelerationRequested": { "type": "boolean" }, - "accelerationAttempted": { "type": "boolean" }, - "trace": { "type": "array", "items": {} } - }, - "required": ["names", "accelerationRequested", "accelerationAttempted"] - } - } - } - } - } - } - } - }, - "webhooks": {} -} diff --git a/docs/docs.ensnode.io/ensapi/preview.mdx b/docs/docs.ensnode.io/ensapi/preview.mdx deleted file mode 100644 index 8907e98cd..000000000 --- a/docs/docs.ensnode.io/ensapi/preview.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: API Preview -sidebarTitle: Preview -description: Preview upcoming API changes from this branch. ---- - -This page provides a preview of the committed OpenAPI specification from the branch this docs site was built from (for pull requests, the PR's head branch), which may include unreleased API changes. - -For the production API documentation, see the [API Reference](/ensapi). diff --git a/openapi/ensapi-openapi.json b/openapi/ensapi-openapi.json deleted file mode 120000 index e6f03df02..000000000 --- a/openapi/ensapi-openapi.json +++ /dev/null @@ -1 +0,0 @@ -../docs/docs.ensnode.io/ensapi-openapi.json \ No newline at end of file diff --git a/package.json b/package.json index 37a12e583..7d85222a7 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "docker:build:ensadmin": "docker build -f apps/ensadmin/Dockerfile -t ghcr.io/namehash/ensnode/ensadmin:latest .", "docker:build:ensrainbow": "docker build -f apps/ensrainbow/Dockerfile -t ghcr.io/namehash/ensnode/ensrainbow:latest .", "docker:build:ensapi": "docker build -f apps/ensapi/Dockerfile -t ghcr.io/namehash/ensnode/ensapi:latest .", - "generate:openapi": "pnpm -r generate:openapi", - "otel-desktop-viewer": "docker run -p 8000:8000 -p 4317:4317 -p 4318:4318 davetron5000/otel-desktop-viewer:alpine-3" + "otel-desktop-viewer": "docker run -p 8000:8000 -p 4317:4317 -p 4318:4318 davetron5000/otel-desktop-viewer:alpine-3", + "generate:openapi": "tsx --tsconfig apps/ensapi/tsconfig.json scripts/generate-ensapi-openapi.ts" }, "devDependencies": { "@biomejs/biome": "^2.3.1", diff --git a/apps/ensapi/scripts/generate-openapi.ts b/scripts/generate-ensapi-openapi.ts similarity index 87% rename from apps/ensapi/scripts/generate-openapi.ts rename to scripts/generate-ensapi-openapi.ts index 07ab718dc..74be343b8 100644 --- a/apps/ensapi/scripts/generate-openapi.ts +++ b/scripts/generate-ensapi-openapi.ts @@ -1,9 +1,9 @@ /** * Generates a static OpenAPI 3.1 JSON document for ENSApi. * - * Usage: tsx scripts/generate-openapi.ts + * Usage: tsx --tsconfig apps/ensapi/tsconfig.json scripts/generate-ensapi-openapi.ts * - * Output: /docs/docs.ensnode.io/ensapi-openapi.json + * Output: docs/docs.ensnode.io/ensapi-openapi.json * * This script has no runtime dependencies — it calls generateOpenApi31Document() * which uses only stub route handlers and static metadata. @@ -17,15 +17,7 @@ import { fileURLToPath } from "node:url"; import { generateOpenApi31Document } from "@/openapi-document"; const __dirname = dirname(fileURLToPath(import.meta.url)); -const outputPath = resolve( - __dirname, - "..", - "..", - "..", - "docs", - "docs.ensnode.io", - "ensapi-openapi.json", -); +const outputPath = resolve(__dirname, "..", "docs", "docs.ensnode.io", "ensapi-openapi.json"); // Generate the document (no additional servers for the static spec) const document = generateOpenApi31Document(); From 9aee061c7b5c4e891bb76477248652d1a383bc07 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 12:55:35 +0000 Subject: [PATCH 08/21] remove preview page --- docs/docs.ensnode.io/docs.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/docs.ensnode.io/docs.json b/docs/docs.ensnode.io/docs.json index 5502080c8..8552c1a97 100644 --- a/docs/docs.ensnode.io/docs.json +++ b/docs/docs.ensnode.io/docs.json @@ -25,12 +25,6 @@ { "group": "API Reference", "openapi": "https://api.alpha.ensnode.io/openapi.json" - }, - { - "group": "Preview", - "pages": ["ensapi/preview"], - "openapi": "ensapi-openapi.json", - "hidden": true } ] } From fa4f296f57688f8a7678fa7e1ab44670f9bb57fc Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 12:56:54 +0000 Subject: [PATCH 09/21] trigger mintlify build --- docs/docs.ensnode.io/docs.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/docs.ensnode.io/docs.json b/docs/docs.ensnode.io/docs.json index 8552c1a97..5502080c8 100644 --- a/docs/docs.ensnode.io/docs.json +++ b/docs/docs.ensnode.io/docs.json @@ -25,6 +25,12 @@ { "group": "API Reference", "openapi": "https://api.alpha.ensnode.io/openapi.json" + }, + { + "group": "Preview", + "pages": ["ensapi/preview"], + "openapi": "ensapi-openapi.json", + "hidden": true } ] } From 2ec78dfbae356f939288c32b561c4351bfdc9a46 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 12:59:20 +0000 Subject: [PATCH 10/21] add preview page --- docs/docs.ensnode.io/ensapi/preview.mdx | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/docs.ensnode.io/ensapi/preview.mdx diff --git a/docs/docs.ensnode.io/ensapi/preview.mdx b/docs/docs.ensnode.io/ensapi/preview.mdx new file mode 100644 index 000000000..8907e98cd --- /dev/null +++ b/docs/docs.ensnode.io/ensapi/preview.mdx @@ -0,0 +1,9 @@ +--- +title: API Preview +sidebarTitle: Preview +description: Preview upcoming API changes from this branch. +--- + +This page provides a preview of the committed OpenAPI specification from the branch this docs site was built from (for pull requests, the PR's head branch), which may include unreleased API changes. + +For the production API documentation, see the [API Reference](/ensapi). From 538b97c5755fafcbb9056f14705c391df3f637c5 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Sun, 1 Mar 2026 13:01:24 +0000 Subject: [PATCH 11/21] Update docs/docs.ensnode.io/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/docs.ensnode.io/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/docs.ensnode.io/README.md b/docs/docs.ensnode.io/README.md index 8ac284af3..e206e856d 100644 --- a/docs/docs.ensnode.io/README.md +++ b/docs/docs.ensnode.io/README.md @@ -7,9 +7,10 @@ Learn more about [ENSNode](https://ensnode.io) from [the "Starlight" ENSNode doc ## Local Development 1. `git clone https://github.com/namehash/ensnode.git` -2. `cd docs/docs.ensnode.io` -3. `pnpm mint dev` -4. Open [http://localhost:3000](http://localhost:3000) in your browser +2. `cd ensnode` +3. `cd docs/docs.ensnode.io` +4. `pnpm mint dev` +5. Open [http://localhost:3000](http://localhost:3000) in your browser ### Troubleshooting From 233fb5e820b42dda0d0f68cceabbd8ba65ca4013 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Mon, 2 Mar 2026 11:49:46 +0000 Subject: [PATCH 12/21] add spec --- apps/ensapi/src/index.ts | 4 +- apps/ensapi/src/openapi-document.ts | 11 +- docs/docs.ensnode.io/ensapi-openapi.json | 2052 ++++++++++++++++++++++ 3 files changed, 2055 insertions(+), 12 deletions(-) create mode 100644 docs/docs.ensnode.io/ensapi-openapi.json diff --git a/apps/ensapi/src/index.ts b/apps/ensapi/src/index.ts index 87fdcb2a1..778ab816c 100644 --- a/apps/ensapi/src/index.ts +++ b/apps/ensapi/src/index.ts @@ -75,9 +75,7 @@ app.route("/v1/ensanalytics", ensanalyticsApiV1); app.route("/amirealtime", amIRealtimeApi); // serve pre-generated OpenAPI 3.1 document -const openApi31Document = generateOpenApi31Document([ - { url: `http://localhost:${config.port}`, description: "Local Development" }, -]); +const openApi31Document = generateOpenApi31Document(); app.get("/openapi.json", (c) => { return c.json(openApi31Document); }); diff --git a/apps/ensapi/src/openapi-document.ts b/apps/ensapi/src/openapi-document.ts index e1e26dc7c..7a45968e0 100644 --- a/apps/ensapi/src/openapi-document.ts +++ b/apps/ensapi/src/openapi-document.ts @@ -44,14 +44,7 @@ function createStubRoutesForSpec() { /** * Generates an OpenAPI 3.1 document from stub route definitions. - * Accepts optional additional servers (e.g. a localhost entry derived from - * runtime config) so that the core generation has no runtime dependencies. */ -export function generateOpenApi31Document( - additionalServers: { url: string; description: string }[] = [], -): ReturnType { - return createStubRoutesForSpec().getOpenAPI31Document({ - ...openapiMeta, - servers: [...openapiMeta.servers, ...additionalServers], - }); +export function generateOpenApi31Document(): ReturnType { + return createStubRoutesForSpec().getOpenAPI31Document(openapiMeta); } diff --git a/docs/docs.ensnode.io/ensapi-openapi.json b/docs/docs.ensnode.io/ensapi-openapi.json new file mode 100644 index 000000000..b6f97802d --- /dev/null +++ b/docs/docs.ensnode.io/ensapi-openapi.json @@ -0,0 +1,2052 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "ENSApi APIs", + "version": "1.5.1", + "description": "APIs for ENS resolution, navigating the ENS nameforest, and metadata about an ENSNode" + }, + "servers": [ + { "url": "https://api.alpha.ensnode.io", "description": "ENSNode Alpha (Mainnet)" }, + { + "url": "https://api.alpha-sepolia.ensnode.io", + "description": "ENSNode Alpha (Sepolia Testnet)" + } + ], + "tags": [ + { "name": "Resolution", "description": "APIs for resolving ENS names and addresses" }, + { + "name": "Meta", + "description": "APIs for indexing status, configuration, and realtime monitoring" + }, + { + "name": "Explore", + "description": "APIs for exploring the indexed state of ENS, including name tokens and registrar actions" + }, + { + "name": "ENSAwards", + "description": "APIs for ENSAwards functionality, including referrer data" + } + ], + "components": { "schemas": {}, "parameters": {} }, + "paths": { + "/amirealtime": { + "get": { + "operationId": "isRealtime", + "tags": ["Meta"], + "summary": "Check indexing progress", + "description": "Checks if the indexing progress is guaranteed to be within a requested worst-case distance of realtime", + "parameters": [ + { + "schema": { + "description": "Maximum acceptable worst-case indexing distance in seconds" + }, + "required": false, + "description": "Maximum acceptable worst-case indexing distance in seconds", + "name": "maxWorstCaseDistance", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Indexing progress is guaranteed to be within the requested distance of realtime" + }, + "503": { + "description": "Indexing progress is not guaranteed to be within the requested distance of realtime or indexing status unavailable" + } + } + } + }, + "/api/config": { + "get": { + "operationId": "getConfig", + "tags": ["Meta"], + "summary": "Get ENSApi Public Config", + "description": "Gets the public config of the ENSApi instance", + "responses": { + "200": { + "description": "Successfully retrieved ENSApi public config", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "version": { "type": "string", "minLength": 1 }, + "theGraphFallback": { + "oneOf": [ + { + "type": "object", + "properties": { + "canFallback": { "type": "boolean", "enum": [true] }, + "url": { "type": "string" } + }, + "required": ["canFallback", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "canFallback": { "type": "boolean", "enum": [false] }, + "reason": { + "type": "string", + "enum": ["not-subgraph-compatible", "no-api-key", "no-subgraph-url"] + } + }, + "required": ["canFallback", "reason"], + "additionalProperties": false + } + ] + }, + "ensIndexerPublicConfig": { + "type": "object", + "properties": { + "labelSet": { + "type": "object", + "properties": { + "labelSetId": { + "type": "string", + "minLength": 1, + "maxLength": 50, + "pattern": "^[a-z-]+$" + }, + "labelSetVersion": { "type": ["number", "null"] } + }, + "required": ["labelSetId", "labelSetVersion"] + }, + "indexedChainIds": { + "type": "array", + "items": { "type": "integer", "exclusiveMinimum": 0 }, + "minItems": 1 + }, + "isSubgraphCompatible": { "type": "boolean" }, + "namespace": { + "type": "string", + "enum": ["mainnet", "sepolia", "sepolia-v2", "ens-test-env"] + }, + "plugins": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + }, + "databaseSchemaName": { "type": "string", "minLength": 1 }, + "versionInfo": { + "type": "object", + "properties": { + "nodejs": { "type": "string", "minLength": 1 }, + "ponder": { "type": "string", "minLength": 1 }, + "ensDb": { "type": "string", "minLength": 1 }, + "ensIndexer": { "type": "string", "minLength": 1 }, + "ensNormalize": { "type": "string", "minLength": 1 }, + "ensRainbow": { "type": "string", "minLength": 1 }, + "ensRainbowSchema": { "type": "integer", "exclusiveMinimum": 0 } + }, + "required": [ + "nodejs", + "ponder", + "ensDb", + "ensIndexer", + "ensNormalize", + "ensRainbow", + "ensRainbowSchema" + ], + "additionalProperties": false + } + }, + "required": [ + "labelSet", + "indexedChainIds", + "isSubgraphCompatible", + "namespace", + "plugins", + "databaseSchemaName", + "versionInfo" + ] + } + }, + "required": ["version", "theGraphFallback", "ensIndexerPublicConfig"] + } + } + } + } + } + } + }, + "/api/indexing-status": { + "get": { + "operationId": "getIndexingStatus", + "tags": ["Meta"], + "summary": "Get ENSIndexer Indexing Status", + "description": "Returns the indexing status snapshot most recently captured from ENSIndexer", + "responses": { + "200": { + "description": "Successfully retrieved indexing status", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["ok"] }, + "realtimeProjection": { + "type": "object", + "properties": { + "snapshot": { + "type": "object", + "properties": { + "strategy": { "type": "string", "enum": ["omnichain"] }, + "slowestChainIndexingCursor": { "type": "integer" }, + "snapshotTime": { "type": "integer" }, + "omnichainSnapshot": { + "oneOf": [ + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-unstarted"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-queued"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + } + }, + "required": ["chainStatus", "config"] + } + ] + } + }, + "omnichainIndexingCursor": { "type": "integer" } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + }, + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-backfill"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-queued"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + } + }, + "required": ["chainStatus", "config"] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-backfill"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "backfillEndBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock", + "backfillEndBlock" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-completed"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock", "endBlock"] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock" + ] + } + ] + } + }, + "omnichainIndexingCursor": { "type": "integer" } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + }, + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-completed"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-completed"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock", "endBlock"] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock" + ] + } + ] + } + }, + "omnichainIndexingCursor": { "type": "integer" } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + }, + { + "type": "object", + "properties": { + "omnichainStatus": { + "type": "string", + "enum": ["omnichain-following"] + }, + "chains": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-queued"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + } + }, + "required": ["chainStatus", "config"] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-backfill"] + }, + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "rangeType", + "startBlock", + "endBlock" + ] + } + ] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "backfillEndBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock", + "backfillEndBlock" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-following"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["left-bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock"] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "latestKnownBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock", + "latestKnownBlock" + ] + }, + { + "type": "object", + "properties": { + "chainStatus": { + "type": "string", + "enum": ["chain-completed"] + }, + "config": { + "type": "object", + "properties": { + "rangeType": { + "type": "string", + "enum": ["bounded"] + }, + "startBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + }, + "endBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": ["rangeType", "startBlock", "endBlock"] + }, + "latestIndexedBlock": { + "type": "object", + "properties": { + "timestamp": { "type": "integer" }, + "number": { "type": "integer", "minimum": 0 } + }, + "required": ["timestamp", "number"], + "additionalProperties": false + } + }, + "required": [ + "chainStatus", + "config", + "latestIndexedBlock" + ] + } + ] + } + }, + "omnichainIndexingCursor": { "type": "integer" } + }, + "required": [ + "omnichainStatus", + "chains", + "omnichainIndexingCursor" + ] + } + ] + } + }, + "required": [ + "strategy", + "slowestChainIndexingCursor", + "snapshotTime", + "omnichainSnapshot" + ] + }, + "projectedAt": { "type": "integer" }, + "worstCaseDistance": { "type": "number" } + }, + "required": ["snapshot", "projectedAt", "worstCaseDistance"] + } + }, + "required": ["responseCode", "realtimeProjection"], + "additionalProperties": false + } + } + } + }, + "503": { + "description": "Indexing status snapshot unavailable", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "responseCode": { "type": "string", "enum": ["error"] } }, + "required": ["responseCode"], + "additionalProperties": false + } + } + } + } + } + } + }, + "/v1/ensanalytics/referral-leaderboard": { + "get": { + "operationId": "getReferralLeaderboard_v1", + "tags": ["ENSAwards"], + "summary": "Get Referrer Leaderboard (v1)", + "description": "Returns a paginated page from the referrer leaderboard for a specific edition", + "parameters": [ + { + "schema": { "type": "string", "minLength": 1, "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" }, + "required": true, + "name": "edition", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number for pagination" + }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "description": "Number of referrers per page" + }, + "required": false, + "description": "Number of referrers per page", + "name": "recordsPerPage", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved referrer leaderboard page" }, + "404": { "description": "Unknown edition slug" }, + "500": { "description": "Internal server error" }, + "503": { "description": "Service unavailable" } + } + } + }, + "/v1/ensanalytics/referrer/{referrer}": { + "get": { + "operationId": "getReferrerDetail_v1", + "tags": ["ENSAwards"], + "summary": "Get Referrer Detail for Editions (v1)", + "description": "Returns detailed information for a specific referrer for the requested editions. Requires 1-20 distinct edition slugs. All requested editions must be recognized and have cached data, or the request fails.", + "parameters": [ + { + "schema": { "type": "string", "description": "Referrer Ethereum address" }, + "required": true, + "description": "Referrer Ethereum address", + "name": "referrer", + "in": "path" + }, + { + "schema": { "type": "string", "description": "Comma-separated list of edition slugs" }, + "required": true, + "description": "Comma-separated list of edition slugs", + "name": "editions", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved referrer detail for requested editions" }, + "400": { "description": "Invalid request" }, + "404": { "description": "Unknown edition slug" }, + "500": { "description": "Internal server error" }, + "503": { "description": "Service unavailable" } + } + } + }, + "/v1/ensanalytics/editions": { + "get": { + "operationId": "getEditions_v1", + "tags": ["ENSAwards"], + "summary": "Get Edition Config Set (v1)", + "description": "Returns the currently configured referral program edition config set. Editions are sorted in descending order by start timestamp (most recent first).", + "responses": { + "200": { "description": "Successfully retrieved edition config set" }, + "500": { "description": "Internal server error" }, + "503": { "description": "Service unavailable" } + } + } + }, + "/ensanalytics/referrers": { + "get": { + "operationId": "getReferrerLeaderboard", + "tags": ["ENSAwards"], + "summary": "Get Referrer Leaderboard", + "description": "Returns a paginated page from the referrer leaderboard", + "parameters": [ + { + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number for pagination" + }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "description": "Number of referrers per page" + }, + "required": false, + "description": "Number of referrers per page", + "name": "recordsPerPage", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved referrer leaderboard page" }, + "500": { "description": "Internal server error" } + } + } + }, + "/ensanalytics/referrers/{referrer}": { + "get": { + "operationId": "getReferrerDetail", + "tags": ["ENSAwards"], + "summary": "Get Referrer Detail", + "description": "Returns detailed information for a specific referrer by address", + "parameters": [ + { + "schema": { "type": "string", "description": "Referrer Ethereum address" }, + "required": true, + "description": "Referrer Ethereum address", + "name": "referrer", + "in": "path" + } + ], + "responses": { + "200": { "description": "Successfully retrieved referrer detail" }, + "500": { "description": "Internal server error" }, + "503": { "description": "Service unavailable - referrer leaderboard data not yet cached" } + } + } + }, + "/api/name-tokens": { + "get": { + "operationId": "getNameTokens", + "tags": ["Explore"], + "summary": "Get Name Tokens", + "description": "Returns name tokens for the requested identifier (domainId or name)", + "parameters": [ + { + "schema": { "type": "string", "description": "Domain node hash identifier" }, + "required": false, + "description": "Domain node hash identifier", + "name": "domainId", + "in": "query" + }, + { + "schema": { "type": "string", "description": "ENS name to look up tokens for" }, + "required": false, + "description": "ENS name to look up tokens for", + "name": "name", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Name tokens known", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["ok"] }, + "registeredNameTokens": { + "type": "object", + "properties": { + "domainId": { "type": "string" }, + "name": { "type": "string" }, + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "type": "object", + "properties": { + "assetNamespace": { + "type": "string", + "enum": ["erc721", "erc1155"] + }, + "contract": { + "type": "object", + "properties": { + "chainId": { "type": "integer", "exclusiveMinimum": 0 }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + }, + "tokenId": { "type": "string" } + }, + "required": ["assetNamespace", "contract", "tokenId"] + }, + "ownership": { + "oneOf": [ + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["namewrapper"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["fully-onchain"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { "type": "string", "enum": ["burned"] }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["unknown"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + } + ] + }, + "mintStatus": { "type": "string", "enum": ["minted", "burned"] } + }, + "required": ["token", "ownership", "mintStatus"] + }, + "minItems": 1 + }, + "expiresAt": { "type": "integer" }, + "accurateAsOf": { "type": "integer" } + }, + "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] + } + }, + "required": ["responseCode", "registeredNameTokens"], + "additionalProperties": false + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { "type": "string", "enum": ["name-tokens-not-indexed"] }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-ensindexer-config"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-indexing-status"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + } + ] + } + ] + } + } + } + }, + "400": { + "description": "Invalid input", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + } + } + }, + "404": { + "description": "Name tokens not indexed", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["ok"] }, + "registeredNameTokens": { + "type": "object", + "properties": { + "domainId": { "type": "string" }, + "name": { "type": "string" }, + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "type": "object", + "properties": { + "assetNamespace": { + "type": "string", + "enum": ["erc721", "erc1155"] + }, + "contract": { + "type": "object", + "properties": { + "chainId": { "type": "integer", "exclusiveMinimum": 0 }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + }, + "tokenId": { "type": "string" } + }, + "required": ["assetNamespace", "contract", "tokenId"] + }, + "ownership": { + "oneOf": [ + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["namewrapper"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["fully-onchain"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { "type": "string", "enum": ["burned"] }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["unknown"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + } + ] + }, + "mintStatus": { "type": "string", "enum": ["minted", "burned"] } + }, + "required": ["token", "ownership", "mintStatus"] + }, + "minItems": 1 + }, + "expiresAt": { "type": "integer" }, + "accurateAsOf": { "type": "integer" } + }, + "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] + } + }, + "required": ["responseCode", "registeredNameTokens"], + "additionalProperties": false + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { "type": "string", "enum": ["name-tokens-not-indexed"] }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-ensindexer-config"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-indexing-status"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + } + ] + } + ] + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + } + } + }, + "503": { + "description": "Service unavailable - Name Tokens API prerequisites not met (indexing status not ready or required plugins not activated)", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["ok"] }, + "registeredNameTokens": { + "type": "object", + "properties": { + "domainId": { "type": "string" }, + "name": { "type": "string" }, + "tokens": { + "type": "array", + "items": { + "type": "object", + "properties": { + "token": { + "type": "object", + "properties": { + "assetNamespace": { + "type": "string", + "enum": ["erc721", "erc1155"] + }, + "contract": { + "type": "object", + "properties": { + "chainId": { "type": "integer", "exclusiveMinimum": 0 }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + }, + "tokenId": { "type": "string" } + }, + "required": ["assetNamespace", "contract", "tokenId"] + }, + "ownership": { + "oneOf": [ + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["namewrapper"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["fully-onchain"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { "type": "string", "enum": ["burned"] }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + }, + { + "type": "object", + "properties": { + "ownershipType": { + "type": "string", + "enum": ["unknown"] + }, + "owner": { + "type": "object", + "properties": { + "chainId": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "address": { "type": "string" } + }, + "required": ["chainId", "address"], + "additionalProperties": false + } + }, + "required": ["ownershipType", "owner"] + } + ] + }, + "mintStatus": { "type": "string", "enum": ["minted", "burned"] } + }, + "required": ["token", "ownership", "mintStatus"] + }, + "minItems": 1 + }, + "expiresAt": { "type": "integer" }, + "accurateAsOf": { "type": "integer" } + }, + "required": ["domainId", "name", "tokens", "expiresAt", "accurateAsOf"] + } + }, + "required": ["responseCode", "registeredNameTokens"], + "additionalProperties": false + }, + { + "oneOf": [ + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { "type": "string", "enum": ["name-tokens-not-indexed"] }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-ensindexer-config"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "responseCode": { "type": "string", "enum": ["error"] }, + "errorCode": { + "type": "string", + "enum": ["unsupported-indexing-status"] + }, + "error": { + "type": "object", + "properties": { "message": { "type": "string" }, "details": {} }, + "required": ["message"] + } + }, + "required": ["responseCode", "errorCode", "error"], + "additionalProperties": false + } + ] + } + ] + } + } + } + } + } + } + }, + "/api/registrar-actions": { + "get": { + "operationId": "getRegistrarActions", + "tags": ["Explore"], + "summary": "Get Registrar Actions", + "description": "Returns all registrar actions with optional filtering and pagination", + "parameters": [ + { + "schema": { + "type": "string", + "enum": ["orderBy[timestamp]=desc"], + "default": "orderBy[timestamp]=desc", + "description": "Order of results" + }, + "required": false, + "description": "Order of results", + "name": "orderBy", + "in": "query" + }, + { + "schema": { "description": "Page number for pagination" }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { "description": "Number of records per page" }, + "required": false, + "description": "Number of records per page", + "name": "recordsPerPage", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false, + "description": "Filter to only include actions with referrals" + }, + "required": false, + "description": "Filter to only include actions with referrals", + "name": "withReferral", + "in": "query" + }, + { + "schema": { "type": "string", "description": "Filter by decoded referrer address" }, + "required": false, + "description": "Filter by decoded referrer address", + "name": "decodedReferrer", + "in": "query" + }, + { + "schema": { "description": "Filter actions at or after this Unix timestamp" }, + "required": false, + "description": "Filter actions at or after this Unix timestamp", + "name": "beginTimestamp", + "in": "query" + }, + { + "schema": { "description": "Filter actions at or before this Unix timestamp" }, + "required": false, + "description": "Filter actions at or before this Unix timestamp", + "name": "endTimestamp", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved registrar actions" }, + "400": { "description": "Invalid query" }, + "500": { "description": "Internal server error" } + } + } + }, + "/api/registrar-actions/{parentNode}": { + "get": { + "operationId": "getRegistrarActionsByParentNode", + "tags": ["Explore"], + "summary": "Get Registrar Actions by Parent Node", + "description": "Returns registrar actions filtered by parent node hash with optional additional filtering and pagination", + "parameters": [ + { + "schema": { + "type": "string", + "description": "Parent node to filter registrar actions" + }, + "required": true, + "description": "Parent node to filter registrar actions", + "name": "parentNode", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": ["orderBy[timestamp]=desc"], + "default": "orderBy[timestamp]=desc", + "description": "Order of results" + }, + "required": false, + "description": "Order of results", + "name": "orderBy", + "in": "query" + }, + { + "schema": { "description": "Page number for pagination" }, + "required": false, + "description": "Page number for pagination", + "name": "page", + "in": "query" + }, + { + "schema": { "description": "Number of records per page" }, + "required": false, + "description": "Number of records per page", + "name": "recordsPerPage", + "in": "query" + }, + { + "schema": { + "type": "string", + "default": false, + "description": "Filter to only include actions with referrals" + }, + "required": false, + "description": "Filter to only include actions with referrals", + "name": "withReferral", + "in": "query" + }, + { + "schema": { "type": "string", "description": "Filter by decoded referrer address" }, + "required": false, + "description": "Filter by decoded referrer address", + "name": "decodedReferrer", + "in": "query" + }, + { + "schema": { "description": "Filter actions at or after this Unix timestamp" }, + "required": false, + "description": "Filter actions at or after this Unix timestamp", + "name": "beginTimestamp", + "in": "query" + }, + { + "schema": { "description": "Filter actions at or before this Unix timestamp" }, + "required": false, + "description": "Filter actions at or before this Unix timestamp", + "name": "endTimestamp", + "in": "query" + } + ], + "responses": { + "200": { "description": "Successfully retrieved registrar actions" }, + "400": { "description": "Invalid input" }, + "500": { "description": "Internal server error" } + } + } + }, + "/api/resolve/records/{name}": { + "get": { + "operationId": "resolveRecords", + "tags": ["Resolution"], + "summary": "Resolve ENS Records", + "description": "Resolves ENS records for a given name", + "parameters": [ + { "schema": { "type": "string" }, "required": true, "name": "name", "in": "path" }, + { "schema": { "type": "string" }, "required": false, "name": "name", "in": "query" }, + { "schema": { "type": "string" }, "required": false, "name": "addresses", "in": "query" }, + { "schema": { "type": "string" }, "required": false, "name": "texts", "in": "query" }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "trace", + "in": "query" + }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "accelerate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully resolved records", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "records": { + "type": "object", + "properties": { + "name": { "type": ["string", "null"] }, + "addresses": { + "type": "object", + "additionalProperties": { "type": ["string", "null"] } + }, + "texts": { + "type": "object", + "additionalProperties": { "type": ["string", "null"] } + } + } + }, + "accelerationRequested": { "type": "boolean" }, + "accelerationAttempted": { "type": "boolean" }, + "trace": { "type": "array", "items": {} } + }, + "required": ["records", "accelerationRequested", "accelerationAttempted"] + } + } + } + } + } + } + }, + "/api/resolve/primary-name/{address}/{chainId}": { + "get": { + "operationId": "resolvePrimaryName", + "tags": ["Resolution"], + "summary": "Resolve Primary Name", + "description": "Resolves a primary name for a given `address` and `chainId`", + "parameters": [ + { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, + { "schema": { "type": "string" }, "required": true, "name": "chainId", "in": "path" }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "trace", + "in": "query" + }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "accelerate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully resolved name", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": ["string", "null"] }, + "accelerationRequested": { "type": "boolean" }, + "accelerationAttempted": { "type": "boolean" }, + "trace": { "type": "array", "items": {} } + }, + "required": ["name", "accelerationRequested", "accelerationAttempted"] + } + } + } + } + } + } + }, + "/api/resolve/primary-names/{address}": { + "get": { + "operationId": "resolvePrimaryNames", + "tags": ["Resolution"], + "summary": "Resolve Primary Names", + "description": "Resolves all primary names for a given address across multiple chains", + "parameters": [ + { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, + { "schema": { "type": "string" }, "required": false, "name": "chainIds", "in": "query" }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "trace", + "in": "query" + }, + { + "schema": { "type": "string", "default": false }, + "required": false, + "name": "accelerate", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Successfully resolved records", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "names": { + "type": "object", + "additionalProperties": { "type": ["string", "null"] } + }, + "accelerationRequested": { "type": "boolean" }, + "accelerationAttempted": { "type": "boolean" }, + "trace": { "type": "array", "items": {} } + }, + "required": ["names", "accelerationRequested", "accelerationAttempted"] + } + } + } + } + } + } + } + }, + "webhooks": {} +} From fa8eb978feadbf7593b9c8074c9eeb5ee172c200 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Mon, 2 Mar 2026 11:55:22 +0000 Subject: [PATCH 13/21] refactor recursive script --- docs/docs.ensnode.io/package.json | 3 ++- package.json | 2 +- scripts/generate-ensapi-openapi.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/docs.ensnode.io/package.json b/docs/docs.ensnode.io/package.json index d77269424..3fd14f2af 100644 --- a/docs/docs.ensnode.io/package.json +++ b/docs/docs.ensnode.io/package.json @@ -12,7 +12,8 @@ }, "homepage": "https://github.com/namehash/ensnode/tree/main/docs/docs.ensnode.io", "scripts": { - "mint": "pnpm dlx mint@^4.1.0" + "mint": "pnpm dlx mint@^4.1.0", + "generate:openapi": "pnpm --filter ensapi exec tsx --tsconfig tsconfig.json ../../scripts/generate-ensapi-openapi.ts" }, "packageManager": "pnpm@10.28.0" } diff --git a/package.json b/package.json index 7d85222a7..56aa6df63 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "docker:build:ensrainbow": "docker build -f apps/ensrainbow/Dockerfile -t ghcr.io/namehash/ensnode/ensrainbow:latest .", "docker:build:ensapi": "docker build -f apps/ensapi/Dockerfile -t ghcr.io/namehash/ensnode/ensapi:latest .", "otel-desktop-viewer": "docker run -p 8000:8000 -p 4317:4317 -p 4318:4318 davetron5000/otel-desktop-viewer:alpine-3", - "generate:openapi": "tsx --tsconfig apps/ensapi/tsconfig.json scripts/generate-ensapi-openapi.ts" + "generate:openapi": "pnpm -r generate:openapi" }, "devDependencies": { "@biomejs/biome": "^2.3.1", diff --git a/scripts/generate-ensapi-openapi.ts b/scripts/generate-ensapi-openapi.ts index 74be343b8..5750b9279 100644 --- a/scripts/generate-ensapi-openapi.ts +++ b/scripts/generate-ensapi-openapi.ts @@ -1,7 +1,7 @@ /** * Generates a static OpenAPI 3.1 JSON document for ENSApi. * - * Usage: tsx --tsconfig apps/ensapi/tsconfig.json scripts/generate-ensapi-openapi.ts + * Usage: pnpm generate:openapi * * Output: docs/docs.ensnode.io/ensapi-openapi.json * From 9019bef735c0bf767b9d0ff6baefd41a6779c596 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Mon, 2 Mar 2026 12:01:57 +0000 Subject: [PATCH 14/21] Update scripts/generate-ensapi-openapi.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/generate-ensapi-openapi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/generate-ensapi-openapi.ts b/scripts/generate-ensapi-openapi.ts index 5750b9279..4fdc50875 100644 --- a/scripts/generate-ensapi-openapi.ts +++ b/scripts/generate-ensapi-openapi.ts @@ -39,7 +39,7 @@ try { if (error instanceof Error) { const err = error as NodeJS.ErrnoException & { status?: number }; if (err.code === "ENOENT") { - console.error("'pnpm' or 'biome' is not available on your PATH."); + console.error("'pnpm' is not available on your PATH."); } else if (err.status !== undefined) { console.error(`Biome exited with code ${err.status}.`); console.error("Try running 'pnpm biome format --write' manually to debug."); From 12b376d3ef800f9041a5bc556aa115b588c33e47 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Mon, 2 Mar 2026 15:40:46 +0000 Subject: [PATCH 15/21] implement copilot suggestion for biome --- scripts/generate-ensapi-openapi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/generate-ensapi-openapi.ts b/scripts/generate-ensapi-openapi.ts index 4fdc50875..f71fe5c1b 100644 --- a/scripts/generate-ensapi-openapi.ts +++ b/scripts/generate-ensapi-openapi.ts @@ -31,7 +31,7 @@ console.log(`OpenAPI spec written to ${outputPath}`); // Format with Biome for consistency console.log("Formatting with Biome..."); try { - execFileSync("pnpm", ["exec", "biome", "format", "--write", outputPath], { + execFileSync("pnpm", ["-w", "exec", "biome", "format", "--write", outputPath], { stdio: "inherit", }); } catch (error) { From 608b4625f6e9835c50a0845bea1f34f5a49f231a Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 3 Mar 2026 08:17:39 +0000 Subject: [PATCH 16/21] fix spec --- apps/ensapi/src/handlers/amirealtime-api.routes.ts | 1 + apps/ensapi/src/lib/handlers/params.schema.ts | 4 ++-- docs/docs.ensnode.io/ensapi-openapi.json | 14 ++++++++------ docs/docs.ensnode.io/ensapi/preview.mdx | 4 ++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/ensapi/src/handlers/amirealtime-api.routes.ts b/apps/ensapi/src/handlers/amirealtime-api.routes.ts index 3d379aa83..3f85621ce 100644 --- a/apps/ensapi/src/handlers/amirealtime-api.routes.ts +++ b/apps/ensapi/src/handlers/amirealtime-api.routes.ts @@ -32,6 +32,7 @@ export const amIRealtimeGetMeta = createRoute({ }) .pipe(makeDurationSchema("maxWorstCaseDistance query param")), ) + .openapi({ type: "integer", minimum: 0 }) .describe("Maximum acceptable worst-case indexing distance in seconds"), }), }, diff --git a/apps/ensapi/src/lib/handlers/params.schema.ts b/apps/ensapi/src/lib/handlers/params.schema.ts index 948d7476a..4b0505960 100644 --- a/apps/ensapi/src/lib/handlers/params.schema.ts +++ b/apps/ensapi/src/lib/handlers/params.schema.ts @@ -38,8 +38,8 @@ const name = z .refine(isNormalizedName, "Must be normalized, see https://docs.ens.domains/resolution/names/") .transform((val) => val as Name); -const trace = z.optional(boolstring).default(false); -const accelerate = z.optional(boolstring).default(false); +const trace = z.optional(boolstring).prefault("false"); +const accelerate = z.optional(boolstring).prefault("false"); const address = makeLowercaseAddressSchema(); const defaultableChainId = makeDefaultableChainIdStringSchema(); const coinType = makeCoinTypeStringSchema(); diff --git a/docs/docs.ensnode.io/ensapi-openapi.json b/docs/docs.ensnode.io/ensapi-openapi.json index b6f97802d..ea681ea53 100644 --- a/docs/docs.ensnode.io/ensapi-openapi.json +++ b/docs/docs.ensnode.io/ensapi-openapi.json @@ -38,6 +38,8 @@ "parameters": [ { "schema": { + "type": "integer", + "minimum": 0, "description": "Maximum acceptable worst-case indexing distance in seconds" }, "required": false, @@ -1912,13 +1914,13 @@ { "schema": { "type": "string" }, "required": false, "name": "addresses", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "texts", "in": "query" }, { - "schema": { "type": "string", "default": false }, + "schema": { "type": "string", "default": "false" }, "required": false, "name": "trace", "in": "query" }, { - "schema": { "type": "string", "default": false }, + "schema": { "type": "string", "default": "false" }, "required": false, "name": "accelerate", "in": "query" @@ -1968,13 +1970,13 @@ { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "chainId", "in": "path" }, { - "schema": { "type": "string", "default": false }, + "schema": { "type": "string", "default": "false" }, "required": false, "name": "trace", "in": "query" }, { - "schema": { "type": "string", "default": false }, + "schema": { "type": "string", "default": "false" }, "required": false, "name": "accelerate", "in": "query" @@ -2011,13 +2013,13 @@ { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "chainIds", "in": "query" }, { - "schema": { "type": "string", "default": false }, + "schema": { "type": "string", "default": "false" }, "required": false, "name": "trace", "in": "query" }, { - "schema": { "type": "string", "default": false }, + "schema": { "type": "string", "default": "false" }, "required": false, "name": "accelerate", "in": "query" diff --git a/docs/docs.ensnode.io/ensapi/preview.mdx b/docs/docs.ensnode.io/ensapi/preview.mdx index 8907e98cd..ea65c2e29 100644 --- a/docs/docs.ensnode.io/ensapi/preview.mdx +++ b/docs/docs.ensnode.io/ensapi/preview.mdx @@ -1,9 +1,9 @@ --- title: API Preview sidebarTitle: Preview -description: Preview upcoming API changes from this branch. +description: Preview upcoming API changes from the source branch. --- This page provides a preview of the committed OpenAPI specification from the branch this docs site was built from (for pull requests, the PR's head branch), which may include unreleased API changes. -For the production API documentation, see the [API Reference](/ensapi). +For the production API documentation, see the [Production API Reference](/ensapi). From b19b199a06efb5434d89d1cde9404353f314920a Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 3 Mar 2026 08:24:45 +0000 Subject: [PATCH 17/21] update errror msg --- scripts/generate-ensapi-openapi.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/generate-ensapi-openapi.ts b/scripts/generate-ensapi-openapi.ts index f71fe5c1b..597653e17 100644 --- a/scripts/generate-ensapi-openapi.ts +++ b/scripts/generate-ensapi-openapi.ts @@ -42,7 +42,9 @@ try { console.error("'pnpm' is not available on your PATH."); } else if (err.status !== undefined) { console.error(`Biome exited with code ${err.status}.`); - console.error("Try running 'pnpm biome format --write' manually to debug."); + console.error( + `Try running 'pnpm -w exec biome format --write ${outputPath}' manually to debug.`, + ); } else if (err.message) { console.error(err.message); } From 07414e8fc35a7492aea38da24d0150fd3a2b7ae0 Mon Sep 17 00:00:00 2001 From: Tomasz Kopacki Date: Tue, 3 Mar 2026 09:56:58 +0100 Subject: [PATCH 18/21] Fix schema generation for optional bool params --- .../handlers/registrar-actions-api.routes.ts | 3 ++- apps/ensapi/src/lib/handlers/params.schema.ts | 9 +++---- docs/docs.ensnode.io/ensapi-openapi.json | 24 +++++++++---------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/apps/ensapi/src/handlers/registrar-actions-api.routes.ts b/apps/ensapi/src/handlers/registrar-actions-api.routes.ts index 3b28b2aec..317fa923c 100644 --- a/apps/ensapi/src/handlers/registrar-actions-api.routes.ts +++ b/apps/ensapi/src/handlers/registrar-actions-api.routes.ts @@ -42,7 +42,8 @@ export const registrarActionsQuerySchema = z withReferral: params.boolstring .optional() .default(false) - .describe("Filter to only include actions with referrals"), + .describe("Filter to only include actions with referrals") + .openapi({ default: false }), decodedReferrer: makeLowercaseAddressSchema("decodedReferrer") .optional() diff --git a/apps/ensapi/src/lib/handlers/params.schema.ts b/apps/ensapi/src/lib/handlers/params.schema.ts index 4b0505960..00d83c22d 100644 --- a/apps/ensapi/src/lib/handlers/params.schema.ts +++ b/apps/ensapi/src/lib/handlers/params.schema.ts @@ -1,4 +1,4 @@ -import { z } from "zod/v4"; +import { z } from "@hono/zod-openapi"; import { DEFAULT_EVM_CHAIN_ID, @@ -23,7 +23,8 @@ const excludingDefaultChainId = z const boolstring = z .string() .pipe(z.enum(["true", "false"])) - .transform((val) => val === "true"); + .transform((val) => val === "true") + .openapi({ type: "boolean" }); const stringarray = z .string() @@ -38,8 +39,8 @@ const name = z .refine(isNormalizedName, "Must be normalized, see https://docs.ens.domains/resolution/names/") .transform((val) => val as Name); -const trace = z.optional(boolstring).prefault("false"); -const accelerate = z.optional(boolstring).prefault("false"); +const trace = z.optional(boolstring).default(false).openapi({ default: false }); +const accelerate = z.optional(boolstring).default(false).openapi({ default: false }); const address = makeLowercaseAddressSchema(); const defaultableChainId = makeDefaultableChainIdStringSchema(); const coinType = makeCoinTypeStringSchema(); diff --git a/docs/docs.ensnode.io/ensapi-openapi.json b/docs/docs.ensnode.io/ensapi-openapi.json index ea681ea53..3f8ce878b 100644 --- a/docs/docs.ensnode.io/ensapi-openapi.json +++ b/docs/docs.ensnode.io/ensapi-openapi.json @@ -1781,9 +1781,9 @@ }, { "schema": { - "type": "string", - "default": false, - "description": "Filter to only include actions with referrals" + "type": "boolean", + "description": "Filter to only include actions with referrals", + "default": false }, "required": false, "description": "Filter to only include actions with referrals", @@ -1864,9 +1864,9 @@ }, { "schema": { - "type": "string", - "default": false, - "description": "Filter to only include actions with referrals" + "type": "boolean", + "description": "Filter to only include actions with referrals", + "default": false }, "required": false, "description": "Filter to only include actions with referrals", @@ -1914,13 +1914,13 @@ { "schema": { "type": "string" }, "required": false, "name": "addresses", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "texts", "in": "query" }, { - "schema": { "type": "string", "default": "false" }, + "schema": { "type": "boolean", "default": false }, "required": false, "name": "trace", "in": "query" }, { - "schema": { "type": "string", "default": "false" }, + "schema": { "type": "boolean", "default": false }, "required": false, "name": "accelerate", "in": "query" @@ -1970,13 +1970,13 @@ { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, { "schema": { "type": "string" }, "required": true, "name": "chainId", "in": "path" }, { - "schema": { "type": "string", "default": "false" }, + "schema": { "type": "boolean", "default": false }, "required": false, "name": "trace", "in": "query" }, { - "schema": { "type": "string", "default": "false" }, + "schema": { "type": "boolean", "default": false }, "required": false, "name": "accelerate", "in": "query" @@ -2013,13 +2013,13 @@ { "schema": { "type": "string" }, "required": true, "name": "address", "in": "path" }, { "schema": { "type": "string" }, "required": false, "name": "chainIds", "in": "query" }, { - "schema": { "type": "string", "default": "false" }, + "schema": { "type": "boolean", "default": false }, "required": false, "name": "trace", "in": "query" }, { - "schema": { "type": "string", "default": "false" }, + "schema": { "type": "boolean", "default": false }, "required": false, "name": "accelerate", "in": "query" From 91fc80b1a48dc3ef18d301956f5c18667ff40776 Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 3 Mar 2026 19:50:50 +0000 Subject: [PATCH 19/21] openapi spec updates --- .../src/handlers/amirealtime-api.routes.ts | 3 +- .../handlers/ensanalytics-api-v1.routes.ts | 5 ++-- .../src/handlers/ensanalytics-api.routes.ts | 5 ++-- .../src/handlers/name-tokens-api.routes.ts | 3 +- .../handlers/registrar-actions-api.routes.ts | 10 +++++-- .../src/handlers/resolution-api.routes.ts | 3 +- docs/docs.ensnode.io/ensapi-openapi.json | 30 ++++++++++++++++--- 7 files changed, 43 insertions(+), 16 deletions(-) diff --git a/apps/ensapi/src/handlers/amirealtime-api.routes.ts b/apps/ensapi/src/handlers/amirealtime-api.routes.ts index 3f85621ce..328b94167 100644 --- a/apps/ensapi/src/handlers/amirealtime-api.routes.ts +++ b/apps/ensapi/src/handlers/amirealtime-api.routes.ts @@ -1,6 +1,5 @@ -import { createRoute } from "@hono/zod-openapi"; +import { createRoute, z } from "@hono/zod-openapi"; import { minutesToSeconds } from "date-fns"; -import { z } from "zod/v4"; import type { Duration } from "@ensnode/ensnode-sdk"; import { makeDurationSchema } from "@ensnode/ensnode-sdk/internal"; diff --git a/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts b/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts index 492495075..ceef7fc5e 100644 --- a/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts +++ b/apps/ensapi/src/handlers/ensanalytics-api-v1.routes.ts @@ -1,4 +1,4 @@ -import { createRoute } from "@hono/zod-openapi"; +import { createRoute, z } from "@hono/zod-openapi"; import { MAX_EDITIONS_PER_REQUEST, REFERRERS_PER_LEADERBOARD_PAGE_MAX, @@ -7,7 +7,6 @@ import { makeReferralProgramEditionSlugSchema, makeReferrerMetricsEditionsArraySchema, } from "@namehash/ens-referrals/v1/internal"; -import { z } from "zod/v4"; import { makeLowercaseAddressSchema } from "@ensnode/ensnode-sdk/internal"; @@ -21,6 +20,7 @@ const referrerLeaderboardPageQuerySchema = z.object({ edition: makeReferralProgramEditionSlugSchema("edition"), page: z .optional(z.coerce.number().int().min(1, "Page must be a positive integer")) + .openapi({ type: "integer", minimum: 1 }) .describe("Page number for pagination"), recordsPerPage: z .optional( @@ -33,6 +33,7 @@ const referrerLeaderboardPageQuerySchema = z.object({ `Records per page must not exceed ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}`, ), ) + .openapi({ type: "integer", minimum: 1, maximum: REFERRERS_PER_LEADERBOARD_PAGE_MAX }) .describe("Number of referrers per page"), }); diff --git a/apps/ensapi/src/handlers/ensanalytics-api.routes.ts b/apps/ensapi/src/handlers/ensanalytics-api.routes.ts index e331f635b..cb14bac2b 100644 --- a/apps/ensapi/src/handlers/ensanalytics-api.routes.ts +++ b/apps/ensapi/src/handlers/ensanalytics-api.routes.ts @@ -1,6 +1,5 @@ -import { createRoute } from "@hono/zod-openapi"; +import { createRoute, z } from "@hono/zod-openapi"; import { REFERRERS_PER_LEADERBOARD_PAGE_MAX } from "@namehash/ens-referrals"; -import { z } from "zod/v4"; import { makeLowercaseAddressSchema } from "@ensnode/ensnode-sdk/internal"; @@ -10,6 +9,7 @@ export const basePath = "/ensanalytics"; const paginationQuerySchema = z.object({ page: z .optional(z.coerce.number().int().min(1, "Page must be a positive integer")) + .openapi({ type: "integer", minimum: 1 }) .describe("Page number for pagination"), recordsPerPage: z .optional( @@ -22,6 +22,7 @@ const paginationQuerySchema = z.object({ `Records per page must not exceed ${REFERRERS_PER_LEADERBOARD_PAGE_MAX}`, ), ) + .openapi({ type: "integer", minimum: 1, maximum: REFERRERS_PER_LEADERBOARD_PAGE_MAX }) .describe("Number of referrers per page"), }); diff --git a/apps/ensapi/src/handlers/name-tokens-api.routes.ts b/apps/ensapi/src/handlers/name-tokens-api.routes.ts index e15d9a4fa..01a1c773f 100644 --- a/apps/ensapi/src/handlers/name-tokens-api.routes.ts +++ b/apps/ensapi/src/handlers/name-tokens-api.routes.ts @@ -1,5 +1,4 @@ -import { createRoute } from "@hono/zod-openapi"; -import { z } from "zod/v4"; +import { createRoute, z } from "@hono/zod-openapi"; import { ErrorResponseSchema, diff --git a/apps/ensapi/src/handlers/registrar-actions-api.routes.ts b/apps/ensapi/src/handlers/registrar-actions-api.routes.ts index 317fa923c..b9f70c983 100644 --- a/apps/ensapi/src/handlers/registrar-actions-api.routes.ts +++ b/apps/ensapi/src/handlers/registrar-actions-api.routes.ts @@ -1,5 +1,4 @@ -import { createRoute } from "@hono/zod-openapi"; -import { z } from "zod/v4"; +import { createRoute, z } from "@hono/zod-openapi"; import { RECORDS_PER_PAGE_DEFAULT, @@ -30,6 +29,7 @@ export const registrarActionsQuerySchema = z .default(1) .pipe(z.coerce.number()) .pipe(makePositiveIntegerSchema("page")) + .openapi({ type: "integer", minimum: 1, default: 1 }) .describe("Page number for pagination"), recordsPerPage: params.queryParam @@ -37,6 +37,12 @@ export const registrarActionsQuerySchema = z .default(RECORDS_PER_PAGE_DEFAULT) .pipe(z.coerce.number()) .pipe(makePositiveIntegerSchema("recordsPerPage").max(RECORDS_PER_PAGE_MAX)) + .openapi({ + type: "integer", + minimum: 1, + maximum: RECORDS_PER_PAGE_MAX, + default: RECORDS_PER_PAGE_DEFAULT, + }) .describe("Number of records per page"), withReferral: params.boolstring diff --git a/apps/ensapi/src/handlers/resolution-api.routes.ts b/apps/ensapi/src/handlers/resolution-api.routes.ts index 1af335aeb..c6eadb165 100644 --- a/apps/ensapi/src/handlers/resolution-api.routes.ts +++ b/apps/ensapi/src/handlers/resolution-api.routes.ts @@ -1,5 +1,4 @@ -import { createRoute } from "@hono/zod-openapi"; -import { z } from "zod/v4"; +import { createRoute, z } from "@hono/zod-openapi"; import { makeResolvePrimaryNameResponseSchema, diff --git a/docs/docs.ensnode.io/ensapi-openapi.json b/docs/docs.ensnode.io/ensapi-openapi.json index 3f8ce878b..7630b76de 100644 --- a/docs/docs.ensnode.io/ensapi-openapi.json +++ b/docs/docs.ensnode.io/ensapi-openapi.json @@ -1766,14 +1766,25 @@ "in": "query" }, { - "schema": { "description": "Page number for pagination" }, + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "description": "Page number for pagination" + }, "required": false, "description": "Page number for pagination", "name": "page", "in": "query" }, { - "schema": { "description": "Number of records per page" }, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 10, + "description": "Number of records per page" + }, "required": false, "description": "Number of records per page", "name": "recordsPerPage", @@ -1849,14 +1860,25 @@ "in": "query" }, { - "schema": { "description": "Page number for pagination" }, + "schema": { + "type": "integer", + "minimum": 1, + "default": 1, + "description": "Page number for pagination" + }, "required": false, "description": "Page number for pagination", "name": "page", "in": "query" }, { - "schema": { "description": "Number of records per page" }, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 10, + "description": "Number of records per page" + }, "required": false, "description": "Number of records per page", "name": "recordsPerPage", From 42f0ae2bde657592dc7c7bbeb4b2584f98e1802d Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 3 Mar 2026 20:08:46 +0000 Subject: [PATCH 20/21] Update package.json Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 56aa6df63..1379f117e 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "docker:build:ensrainbow": "docker build -f apps/ensrainbow/Dockerfile -t ghcr.io/namehash/ensnode/ensrainbow:latest .", "docker:build:ensapi": "docker build -f apps/ensapi/Dockerfile -t ghcr.io/namehash/ensnode/ensapi:latest .", "otel-desktop-viewer": "docker run -p 8000:8000 -p 4317:4317 -p 4318:4318 davetron5000/otel-desktop-viewer:alpine-3", - "generate:openapi": "pnpm -r generate:openapi" + "generate:openapi": "pnpm -r --if-present generate:openapi" }, "devDependencies": { "@biomejs/biome": "^2.3.1", From aeeec50a15d3e12f028904ffbe78d8d0c244331b Mon Sep 17 00:00:00 2001 From: Jamie Barton Date: Tue, 3 Mar 2026 20:09:14 +0000 Subject: [PATCH 21/21] update docs to generate opanpi spec --- docs/docs.ensnode.io/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/docs.ensnode.io/README.md b/docs/docs.ensnode.io/README.md index e206e856d..850b18bda 100644 --- a/docs/docs.ensnode.io/README.md +++ b/docs/docs.ensnode.io/README.md @@ -12,6 +12,16 @@ Learn more about [ENSNode](https://ensnode.io) from [the "Starlight" ENSNode doc 4. `pnpm mint dev` 5. Open [http://localhost:3000](http://localhost:3000) in your browser +### Regenerating the OpenAPI Spec + +The ENSApi OpenAPI spec (`ensapi-openapi.json`) is generated from the route definitions in `apps/ensapi`. To regenerate it after making changes to route schemas: + +```sh +pnpm generate:openapi +``` + +This runs from the repo root and outputs the formatted spec to `docs/docs.ensnode.io/ensapi-openapi.json`. + ### Troubleshooting - If a page loads as a 404, make sure you are running in a folder with a valid `docs.json`.